UNPKG

reactive-channel

Version:

A simple yet powerful abstraction that enables communication between asynchronous tasks.

128 lines (127 loc) 3.31 kB
import { NotEnoughAvailableSlotsQueueError as e, NotEnoughFilledSlotsQueueError as t, makeCircularQueue as n } from "reactive-circular-queue"; import { makeDerivedStore as r, makeStore as i } from "universal-stores"; //#region src/lib/index.ts var a = () => void 0, o = class extends Error { constructor() { super("channel full, cannot enqueue data"); } }, s = class extends Error { constructor() { super("channel closed"); } }, c = class extends Error { constructor() { super("channel has already too many pending recv"); } }; function l(e) { let { capacity: t = 1024, maxConcurrentPendingRecv: l = 1024 } = e || {}, u = n(t), d = n(t), f = n(l), p = i(!1), m = r([p, u.availableSlots$], ([e, t]) => e ? 0 : t), h = r([p, u.filledSlots$], ([e, t]) => e ? 0 : t), g = r(m, (e) => e > 0), _ = r([h, f.full$], ([e, t]) => e > 0 && !t); async function v(e, t) { if (p.content()) throw new s(); if (u.full$.content()) throw new o(); let n = a, r = a, i = new Promise((e, t) => { n = e, r = t; }), c; f.empty$.content() ? (c = { promise: i, resolveSend: n, rejectSend: r }, u.enqueue(c), d.enqueue(e)) : f.dequeue().resolveRecv({ promise: i, resolveSend: n, rejectSend: r, value: e }); try { if (!t?.signal) await i; else { let e = t.signal; e.throwIfAborted(), await Promise.race([i, new Promise((t, n) => { e.addEventListener("abort", () => { Promise.resolve().then(() => n(e.reason)).catch(a); }); })]); } } catch (e) { if (c) { let e = u.indexOf(c); e !== -1 && (u.remove(e), d.remove(e)); } throw e; } } function y(e) { if (p.content()) throw new s(); if (u.full$.content()) throw new o(); v(e).catch(a); } async function b(e) { if (p.content()) throw new s(); let t; if (!u.empty$.content()) t = { ...u.dequeue(), value: d.dequeue() }; else { if (f.full$.content()) throw new c(); let n = { resolveRecv: a, rejectRecv: a }, r = new Promise((e, t) => { n.resolveRecv = e, n.rejectRecv = t, f.enqueue(n); }); try { if (!e?.signal) t = await r; else { let n = e.signal; n.throwIfAborted(), t = await Promise.race([r, new Promise((e, t) => { n.addEventListener("abort", () => { Promise.resolve().then(() => t(n.reason)).catch(a); }); })]); } } catch (e) { let t = f.indexOf(n); throw t !== -1 && f.remove(t), e; } } return t.resolveSend(), t.value; } async function* x() { for (; u.filledSlots$.content() > 0;) yield await b(); } function S() { if (p.content()) return; p.set(!0); let e = new s(); for (let t of f) t.rejectRecv(e); for (let t of u) t.rejectSend(e); d.clear(); } return { buffer: d, tx: { send: y, sendWait: v, canWrite$: g, closed$: p, close: S, availableOutboxSlots$: m, capacity: t }, rx: { pendingRecvPromises$: f.filledSlots$, recv: b, iter: x, [Symbol.asyncIterator]: x, canRead$: _, closed$: p, close: S, capacity: t, filledInboxSlots$: h } }; } //#endregion export { s as ChannelClosedError, o as ChannelFullError, c as ChannelTooManyPendingRecvError, e as NotEnoughAvailableSlotsQueueError, t as NotEnoughFilledSlotsQueueError, l as makeChannel }; //# sourceMappingURL=index.js.map