@thi.ng/csp
Version:
Primitives & operators for Communicating Sequential Processes based on async/await and async iterables
107 lines (106 loc) • 2.31 kB
JavaScript
import { Channel } from "./channel.js";
import { __nextID } from "./idgen.js";
const mult = (arg) => new Mult(arg);
class Mult {
src;
taps = [];
/**
* See {@link mult} for reference.
*
* @param arg
*/
constructor(arg) {
let id, src;
if (typeof arg === "string") {
id = arg;
} else {
src = arg;
}
this.src = src instanceof Channel ? src : new Channel({ id: id ?? `mult${__nextID()}` });
this.process();
}
writable() {
return this.src.writable();
}
write(val) {
return this.src.write(val);
}
close() {
return this.src.close();
}
closed() {
return this.src.closed();
}
/**
* Attaches (and possibly creates) a new subscription channel to receive any
* values received by the `Mult` itself. Returns it.
*
* @remarks
* The channel can later be detached again via {@link Mult.unsubscribe}.
*
* @param ch
*/
subscribe(ch) {
if (!ch) {
ch = new Channel({
id: `${this.src.id}-tap${__nextID()}`
});
} else if (this.taps.includes(ch)) {
return ch;
}
this.taps.push(ch);
return ch;
}
/**
* Attempts to remove given subscription channel. Returns true if
* successful. If `close` is true (default), the given channel will also be
* closed (only if unsubscription was successful).
*
* @remarks
* See {@link Mult.subscribe} for reverse op.
*
* @param ch
* @param close
*/
unsubscribe(ch, close = true) {
const idx = this.taps.indexOf(ch);
if (idx >= 0) {
this.taps.splice(idx, 1);
close && ch.close();
return true;
}
return false;
}
/**
* Removes all child subscription channels and if `close` is true (default)
* also closes them.
*
* @remarks
* The `Mult` itself will remain active and will continue to accept new
* subscriptions.
*
* @param close
*/
unsubscribeAll(close = true) {
if (close) {
for (let t of this.taps) t.close();
}
this.taps.length = 0;
}
async process() {
let x;
while ((x = await this.src.read()) !== void 0) {
for (let t of this.taps) {
if (!await t.write(x)) {
this.unsubscribe(t);
}
}
x = null;
}
this.unsubscribeAll();
}
}
export {
Mult,
mult
};