UNPKG

@thi.ng/csp

Version:

Primitives & operators for Communicating Sequential Processes based on async/await and async iterables

107 lines (106 loc) 2.31 kB
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 };