@prelude/channel
Version:
Channel module.
80 lines • 2.88 kB
JavaScript
import { Channel, ReadAttempt, WriteAttempt } from './channel.js';
export async function* select(...attempts) {
while (true) {
const result = await selectNext(...attempts);
if (result.done) {
break;
}
yield result.value;
}
}
export async function selectNext(...attempts) {
return selectSync(attempts) ?? await selectAsync(attempts);
}
export function selectAsync(attempts) {
return new Promise((resolve, reject) => {
const undos = [];
for (const attempt of attempts) {
if (attempt instanceof Channel) {
undos.push(attempt.pushRead(result => {
undos.forEach(undo => undo());
resolve(result);
}));
}
else if (attempt instanceof WriteAttempt) {
undos.push(attempt.channel.pushWrite({ value: attempt.value, enqueued: (err) => {
undos.forEach(_ => _());
if (err) {
reject(err);
return;
}
resolve(attempt.perform(attempt.value));
} }));
}
else if (attempt instanceof ReadAttempt) {
undos.push(attempt.channel.pushRead(result => {
undos.forEach(undo => undo());
resolve(attempt.perform(result));
}));
}
else {
throw new Error('Invalid attempt.');
}
}
});
}
export function selectSync(attempts) {
const n = attempts.length;
for (let i = 0; i < n; i++) {
const j = i + Math.floor(Math.random() * (n - i));
const attempt = attempts[j];
if (attempt instanceof Channel) {
if (attempt.pendingWrites > 0) {
return { value: attempt.consumeWrite() };
}
}
else if (attempt instanceof WriteAttempt) {
if (attempt.channel.cap === 0 && attempt.channel.pendingReads > 0) {
attempt.channel.consumeRead({ value: attempt.value });
return attempt.perform(attempt.value);
}
else if (attempt.channel.pendingWrites < attempt.channel.cap) {
attempt.channel.pushWrite({ value: attempt.value });
return attempt.perform(attempt.value);
}
}
else if (attempt instanceof ReadAttempt) {
if (attempt.channel.pendingWrites > 0) {
const value = attempt.channel.consumeWrite();
return attempt.perform({ value });
}
}
else {
throw new Error('Invalid attempt.');
}
attempts[j] = attempts[i];
attempts[i] = attempt;
}
return;
}
//# sourceMappingURL=select.js.map