@thi.ng/csp 2.1.81 → 2.1.83

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/channel.js CHANGED
@@ -7,511 +7,511 @@ import { delayed } from "@thi.ng/transducers/delayed";
7
7
  import { range } from "@thi.ng/transducers/range";
8
8
  import { isReduced, unreduced } from "@thi.ng/transducers/reduced";
9
9
  import { FixedBuffer } from "./buffer.js";
10
- var State;
11
- (function (State) {
12
- State[State["OPEN"] = 0] = "OPEN";
13
- State[State["CLOSED"] = 1] = "CLOSED";
14
- State[State["DONE"] = 2] = "DONE";
15
- })(State || (State = {}));
16
- export class Channel {
17
- static constantly(x, delay) {
18
- const chan = new Channel(delay ? delayed(delay) : null);
19
- chan.produce(() => x);
20
- return chan;
21
- }
22
- static repeatedly(fn, delay) {
23
- const chan = new Channel(delay ? delayed(delay) : null);
24
- chan.produce(fn);
25
- return chan;
26
- }
27
- static cycle(src, delay) {
28
- return Channel.from(cycle(src), delay ? delayed(delay) : null);
29
- }
30
- static range(...args) {
31
- const [from, to, step, delay] = args;
32
- return Channel.from(range(from, to, step), delay !== undefined ? delayed(delay) : null);
33
- }
34
- /**
35
- * Constructs new channel which closes automatically after given period.
36
- *
37
- * @param delay - time in ms
38
- */
39
- static timeout(delay) {
40
- const chan = new Channel(`timeout-${Channel.NEXT_ID++}`);
41
- setTimeout(() => chan.close(), delay);
42
- return chan;
43
- }
44
- /**
45
- * Shorthand for: `Channel.timeout(delay).take()`
46
- *
47
- * @param delay - time in ms
48
- */
49
- static sleep(delay) {
50
- return Channel.timeout(delay).read();
51
- }
52
- /**
53
- * Creates new channel with single value from given promise, then closes
54
- * automatically iff promise has been resolved.
55
- *
56
- * @param p - promise
57
- */
58
- static fromPromise(p) {
59
- const chan = new Channel();
60
- p.then((x) => (async () => {
61
- await chan.write(x);
62
- await chan.close();
63
- return x;
64
- })());
65
- return chan;
66
- }
67
- static from(...args) {
68
- let close, tx;
69
- switch (args.length) {
70
- case 1:
71
- break;
72
- case 2:
73
- if (typeof args[1] === "boolean") {
74
- close = args[1];
75
- }
76
- else {
77
- tx = args[1];
78
- }
79
- break;
80
- case 3:
81
- tx = args[1];
82
- close = args[2];
83
- break;
84
- default:
85
- illegalArity(args.length);
10
+ var State = /* @__PURE__ */ ((State2) => {
11
+ State2[State2["OPEN"] = 0] = "OPEN";
12
+ State2[State2["CLOSED"] = 1] = "CLOSED";
13
+ State2[State2["DONE"] = 2] = "DONE";
14
+ return State2;
15
+ })(State || {});
16
+ class Channel {
17
+ static constantly(x, delay) {
18
+ const chan = new Channel(delay ? delayed(delay) : null);
19
+ chan.produce(() => x);
20
+ return chan;
21
+ }
22
+ static repeatedly(fn, delay) {
23
+ const chan = new Channel(delay ? delayed(delay) : null);
24
+ chan.produce(fn);
25
+ return chan;
26
+ }
27
+ static cycle(src, delay) {
28
+ return Channel.from(cycle(src), delay ? delayed(delay) : null);
29
+ }
30
+ static range(...args) {
31
+ const [from, to, step, delay] = args;
32
+ return Channel.from(
33
+ range(from, to, step),
34
+ delay !== void 0 ? delayed(delay) : null
35
+ );
36
+ }
37
+ /**
38
+ * Constructs new channel which closes automatically after given period.
39
+ *
40
+ * @param delay - time in ms
41
+ */
42
+ static timeout(delay) {
43
+ const chan = new Channel(`timeout-${Channel.NEXT_ID++}`);
44
+ setTimeout(() => chan.close(), delay);
45
+ return chan;
46
+ }
47
+ /**
48
+ * Shorthand for: `Channel.timeout(delay).take()`
49
+ *
50
+ * @param delay - time in ms
51
+ */
52
+ static sleep(delay) {
53
+ return Channel.timeout(delay).read();
54
+ }
55
+ /**
56
+ * Creates new channel with single value from given promise, then closes
57
+ * automatically iff promise has been resolved.
58
+ *
59
+ * @param p - promise
60
+ */
61
+ static fromPromise(p) {
62
+ const chan = new Channel();
63
+ p.then(
64
+ (x) => (async () => {
65
+ await chan.write(x);
66
+ await chan.close();
67
+ return x;
68
+ })()
69
+ );
70
+ return chan;
71
+ }
72
+ static from(...args) {
73
+ let close, tx;
74
+ switch (args.length) {
75
+ case 1:
76
+ break;
77
+ case 2:
78
+ if (typeof args[1] === "boolean") {
79
+ close = args[1];
80
+ } else {
81
+ tx = args[1];
86
82
  }
87
- const chan = new Channel(tx);
88
- chan.into(args[0], close);
89
- return chan;
90
- }
91
- /**
92
- * Takes an array of channels and blocks until any of them becomes
93
- * readable (or has been closed). The returned promised resolves into
94
- * an array of `[value, channel]`. Channel order is repeatedly
95
- * shuffled for each read attempt.
96
- *
97
- * @param chans - source channels
98
- */
99
- static select(chans) {
100
- return new Promise((resolve) => {
101
- const _select = () => {
102
- for (let c of shuffle(chans)) {
103
- if (c.isReadable() || c.isClosed()) {
104
- c.read().then((x) => resolve([x, c]));
105
- return;
106
- }
107
- }
108
- Channel.SCHEDULE.call(null, _select, 0);
109
- };
110
- Channel.SCHEDULE.call(null, _select, 0);
111
- });
112
- }
113
- /**
114
- * Takes an array of channels to merge into new channel. Any closed
115
- * channels will be automatically removed from the input selection.
116
- * Once all inputs are closed, the target channel will close too (by
117
- * default).
118
- *
119
- * @remarks
120
- * If `named` is true, the merged channel will have tuples of:
121
- * `[src-id, val]` If false (default), only received values will be
122
- * forwarded.
123
- *
124
- * @param chans - source channels
125
- * @param out - result channel
126
- * @param close - true, if result closes
127
- * @param named - true, to emit labeled tuples
128
- */
129
- static merge(chans, out, close = true, named = false) {
130
- out = out || new Channel();
131
- (async () => {
132
- while (true) {
133
- let [x, ch] = await Channel.select(chans);
134
- if (x === undefined) {
135
- chans.splice(chans.indexOf(ch), 1);
136
- if (!chans.length) {
137
- close && (await out.close());
138
- break;
139
- }
140
- }
141
- else {
142
- await out.write(named ? [ch.id, x] : x);
143
- }
144
- }
145
- })();
146
- return out;
147
- }
148
- /**
149
- * Takes an array of channels to merge into new channel of tuples.
150
- * Whereas `Channel.merge()` realizes a sequential merging with no
151
- * guarantees about ordering of the output.
152
- *
153
- * @remarks
154
- * The output channel of this function will collect values from all
155
- * channels and a new tuple is emitted only once a new value has
156
- * been read from ALL channels. Therefore the overall throughput is
157
- * dictated by the slowest of the inputs.
158
- *
159
- * Once any of the inputs closes, the process is terminated and the
160
- * output channel is closed too (by default).
161
- *
162
- * @example
163
- * ```ts
164
- * Channel.mergeTuples([
165
- * Channel.from([1, 2, 3]),
166
- * Channel.from([10, 20, 30]),
167
- * Channel.from([100, 200, 300])
168
- * ]).consume();
169
- *
170
- * // chan-0 : [ 1, 10, 100 ]
171
- * // chan-0 : [ 2, 20, 200 ]
172
- * // chan-0 : [ 3, 30, 300 ]
173
- * // chan-0 done
174
- *
175
- * Channel.mergeTuples([
176
- * Channel.from([1, 2, 3]),
177
- * Channel.from([10, 20, 30]),
178
- * Channel.from([100, 200, 300])
179
- * ], null, false).consume();
180
- * ```
181
- *
182
- * @param chans - source channels
183
- * @param out - result channel
184
- * @param closeOnFirst - true, if result closes when first input is done
185
- * @param closeOutput - true, if result closes when all inputs are done
186
- */
187
- static mergeTuples(chans, out, closeOnFirst = true, closeOutput = true) {
188
- out = out || new Channel();
189
- (async () => {
190
- let buf = [];
191
- let orig = [...chans];
192
- let sel = new Set(chans);
193
- let n = chans.length;
194
- while (true) {
195
- let [x, ch] = await Channel.select([...sel]);
196
- let idx = orig.indexOf(ch);
197
- if (x === undefined) {
198
- if (closeOnFirst || chans.length === 1) {
199
- break;
200
- }
201
- chans.splice(idx, 1);
202
- }
203
- buf[idx] = x;
204
- sel.delete(ch);
205
- if (--n === 0) {
206
- await out.write(buf);
207
- buf = [];
208
- n = chans.length;
209
- sel = new Set(chans);
210
- }
211
- }
212
- closeOutput && (await out.close());
213
- })();
214
- return out;
83
+ break;
84
+ case 3:
85
+ tx = args[1];
86
+ close = args[2];
87
+ break;
88
+ default:
89
+ illegalArity(args.length);
215
90
  }
216
- static MAX_WRITES = 1024;
217
- static NEXT_ID = 0;
218
- static SCHEDULE = typeof setImmediate === "function" ? setImmediate : setTimeout;
219
- static RFN = [
220
- (() => null),
221
- (acc) => acc,
222
- (acc, x) => acc.push(x),
223
- ];
224
- id;
225
- onerror;
226
- state;
227
- buf;
228
- tx;
229
- writes;
230
- reads;
231
- txbuf;
232
- isBusy;
233
- constructor(...args) {
234
- let id, buf, tx, err;
235
- let [a, b] = args;
236
- switch (args.length) {
237
- case 0:
238
- break;
239
- case 1:
240
- if (typeof a === "string") {
241
- id = a;
242
- }
243
- else if (maybeBuffer(a)) {
244
- buf = a;
245
- }
246
- else {
247
- tx = a;
248
- }
249
- break;
250
- case 2:
251
- if (typeof a === "string") {
252
- id = a;
253
- if (maybeBuffer(b)) {
254
- buf = b;
255
- }
256
- else {
257
- tx = b;
258
- }
259
- }
260
- else {
261
- [tx, err] = args;
262
- }
263
- break;
264
- case 3:
265
- if (isFunction(args[1]) && isFunction(args[2])) {
266
- [id, tx, err] = args;
267
- }
268
- else {
269
- [id, buf, tx] = args;
270
- }
271
- break;
272
- case 4:
273
- [id, buf, tx, err] = args;
274
- break;
275
- default:
276
- illegalArity(args.length);
91
+ const chan = new Channel(tx);
92
+ chan.into(args[0], close);
93
+ return chan;
94
+ }
95
+ /**
96
+ * Takes an array of channels and blocks until any of them becomes
97
+ * readable (or has been closed). The returned promised resolves into
98
+ * an array of `[value, channel]`. Channel order is repeatedly
99
+ * shuffled for each read attempt.
100
+ *
101
+ * @param chans - source channels
102
+ */
103
+ static select(chans) {
104
+ return new Promise((resolve) => {
105
+ const _select = () => {
106
+ for (let c of shuffle(chans)) {
107
+ if (c.isReadable() || c.isClosed()) {
108
+ c.read().then((x) => resolve([x, c]));
109
+ return;
110
+ }
277
111
  }
278
- this.id = id || `chan-${Channel.NEXT_ID++}`;
279
- buf = buf || 1;
280
- this.buf = typeof buf === "number" ? new FixedBuffer(buf) : buf;
281
- this.writes = new DCons();
282
- this.reads = new DCons();
283
- this.txbuf = new DCons();
284
- this.tx = tx ? tx(Channel.RFN) : null;
285
- this.onerror = tx && (err || defaultErrorHandler);
286
- this.state = State.OPEN;
287
- this.isBusy = false;
288
- }
289
- channel() {
290
- return this;
291
- }
292
- write(value) {
293
- return new Promise((resolve) => {
294
- if (this.state !== State.OPEN) {
295
- resolve(false);
296
- }
297
- if (this.writes.length < Channel.MAX_WRITES) {
298
- this.writes.push({
299
- value: this.tx
300
- ? async () => {
301
- try {
302
- if (isReduced(this.tx[2](this.txbuf, value))) {
303
- this.state = State.CLOSED;
304
- }
305
- }
306
- catch (e) {
307
- this.onerror(e, this, value);
308
- }
309
- }
310
- : () => value,
311
- resolve,
312
- });
313
- this.process();
314
- }
315
- else {
316
- throw new Error(`channel stalled (${Channel.MAX_WRITES} unprocessed writes)`);
317
- }
318
- });
112
+ Channel.SCHEDULE.call(null, _select, 0);
113
+ };
114
+ Channel.SCHEDULE.call(null, _select, 0);
115
+ });
116
+ }
117
+ /**
118
+ * Takes an array of channels to merge into new channel. Any closed
119
+ * channels will be automatically removed from the input selection.
120
+ * Once all inputs are closed, the target channel will close too (by
121
+ * default).
122
+ *
123
+ * @remarks
124
+ * If `named` is true, the merged channel will have tuples of:
125
+ * `[src-id, val]` If false (default), only received values will be
126
+ * forwarded.
127
+ *
128
+ * @param chans - source channels
129
+ * @param out - result channel
130
+ * @param close - true, if result closes
131
+ * @param named - true, to emit labeled tuples
132
+ */
133
+ static merge(chans, out, close = true, named = false) {
134
+ out = out || new Channel();
135
+ (async () => {
136
+ while (true) {
137
+ let [x, ch] = await Channel.select(chans);
138
+ if (x === void 0) {
139
+ chans.splice(chans.indexOf(ch), 1);
140
+ if (!chans.length) {
141
+ close && await out.close();
142
+ break;
143
+ }
144
+ } else {
145
+ await out.write(named ? [ch.id, x] : x);
146
+ }
147
+ }
148
+ })();
149
+ return out;
150
+ }
151
+ /**
152
+ * Takes an array of channels to merge into new channel of tuples.
153
+ * Whereas `Channel.merge()` realizes a sequential merging with no
154
+ * guarantees about ordering of the output.
155
+ *
156
+ * @remarks
157
+ * The output channel of this function will collect values from all
158
+ * channels and a new tuple is emitted only once a new value has
159
+ * been read from ALL channels. Therefore the overall throughput is
160
+ * dictated by the slowest of the inputs.
161
+ *
162
+ * Once any of the inputs closes, the process is terminated and the
163
+ * output channel is closed too (by default).
164
+ *
165
+ * @example
166
+ * ```ts
167
+ * Channel.mergeTuples([
168
+ * Channel.from([1, 2, 3]),
169
+ * Channel.from([10, 20, 30]),
170
+ * Channel.from([100, 200, 300])
171
+ * ]).consume();
172
+ *
173
+ * // chan-0 : [ 1, 10, 100 ]
174
+ * // chan-0 : [ 2, 20, 200 ]
175
+ * // chan-0 : [ 3, 30, 300 ]
176
+ * // chan-0 done
177
+ *
178
+ * Channel.mergeTuples([
179
+ * Channel.from([1, 2, 3]),
180
+ * Channel.from([10, 20, 30]),
181
+ * Channel.from([100, 200, 300])
182
+ * ], null, false).consume();
183
+ * ```
184
+ *
185
+ * @param chans - source channels
186
+ * @param out - result channel
187
+ * @param closeOnFirst - true, if result closes when first input is done
188
+ * @param closeOutput - true, if result closes when all inputs are done
189
+ */
190
+ static mergeTuples(chans, out, closeOnFirst = true, closeOutput = true) {
191
+ out = out || new Channel();
192
+ (async () => {
193
+ let buf = [];
194
+ let orig = [...chans];
195
+ let sel = new Set(chans);
196
+ let n = chans.length;
197
+ while (true) {
198
+ let [x, ch] = await Channel.select([...sel]);
199
+ let idx = orig.indexOf(ch);
200
+ if (x === void 0) {
201
+ if (closeOnFirst || chans.length === 1) {
202
+ break;
203
+ }
204
+ chans.splice(idx, 1);
205
+ }
206
+ buf[idx] = x;
207
+ sel.delete(ch);
208
+ if (--n === 0) {
209
+ await out.write(buf);
210
+ buf = [];
211
+ n = chans.length;
212
+ sel = new Set(chans);
213
+ }
214
+ }
215
+ closeOutput && await out.close();
216
+ })();
217
+ return out;
218
+ }
219
+ static MAX_WRITES = 1024;
220
+ static NEXT_ID = 0;
221
+ static SCHEDULE = typeof setImmediate === "function" ? setImmediate : setTimeout;
222
+ static RFN = [
223
+ () => null,
224
+ (acc) => acc,
225
+ (acc, x) => acc.push(x)
226
+ ];
227
+ id;
228
+ onerror;
229
+ state;
230
+ buf;
231
+ tx;
232
+ writes;
233
+ reads;
234
+ txbuf;
235
+ isBusy;
236
+ constructor(...args) {
237
+ let id, buf, tx, err;
238
+ let [a, b] = args;
239
+ switch (args.length) {
240
+ case 0:
241
+ break;
242
+ case 1:
243
+ if (typeof a === "string") {
244
+ id = a;
245
+ } else if (maybeBuffer(a)) {
246
+ buf = a;
247
+ } else {
248
+ tx = a;
249
+ }
250
+ break;
251
+ case 2:
252
+ if (typeof a === "string") {
253
+ id = a;
254
+ if (maybeBuffer(b)) {
255
+ buf = b;
256
+ } else {
257
+ tx = b;
258
+ }
259
+ } else {
260
+ [tx, err] = args;
261
+ }
262
+ break;
263
+ case 3:
264
+ if (isFunction(args[1]) && isFunction(args[2])) {
265
+ [id, tx, err] = args;
266
+ } else {
267
+ [id, buf, tx] = args;
268
+ }
269
+ break;
270
+ case 4:
271
+ [id, buf, tx, err] = args;
272
+ break;
273
+ default:
274
+ illegalArity(args.length);
319
275
  }
320
- read() {
321
- return new Promise((resolve) => {
322
- if (this.state === State.DONE) {
323
- resolve(undefined);
276
+ this.id = id || `chan-${Channel.NEXT_ID++}`;
277
+ buf = buf || 1;
278
+ this.buf = typeof buf === "number" ? new FixedBuffer(buf) : buf;
279
+ this.writes = new DCons();
280
+ this.reads = new DCons();
281
+ this.txbuf = new DCons();
282
+ this.tx = tx ? tx(Channel.RFN) : null;
283
+ this.onerror = tx && (err || defaultErrorHandler);
284
+ this.state = 0 /* OPEN */;
285
+ this.isBusy = false;
286
+ }
287
+ channel() {
288
+ return this;
289
+ }
290
+ write(value) {
291
+ return new Promise((resolve) => {
292
+ if (this.state !== 0 /* OPEN */) {
293
+ resolve(false);
294
+ }
295
+ if (this.writes.length < Channel.MAX_WRITES) {
296
+ this.writes.push({
297
+ value: this.tx ? async () => {
298
+ try {
299
+ if (isReduced(this.tx[2](this.txbuf, value))) {
300
+ this.state = 1 /* CLOSED */;
301
+ }
302
+ } catch (e) {
303
+ this.onerror(e, this, value);
324
304
  }
325
- this.reads.push(resolve);
326
- this.process();
327
- });
328
- }
329
- tryRead(timeout = 1000) {
330
- return new Promise((resolve) => {
331
- (async () => resolve((await Channel.select([this, Channel.timeout(timeout)]))[0]))();
305
+ } : () => value,
306
+ resolve
332
307
  });
308
+ this.process();
309
+ } else {
310
+ throw new Error(
311
+ `channel stalled (${Channel.MAX_WRITES} unprocessed writes)`
312
+ );
313
+ }
314
+ });
315
+ }
316
+ read() {
317
+ return new Promise((resolve) => {
318
+ if (this.state === 2 /* DONE */) {
319
+ resolve(void 0);
320
+ }
321
+ this.reads.push(resolve);
322
+ this.process();
323
+ });
324
+ }
325
+ tryRead(timeout = 1e3) {
326
+ return new Promise((resolve) => {
327
+ (async () => resolve(
328
+ (await Channel.select([this, Channel.timeout(timeout)]))[0]
329
+ ))();
330
+ });
331
+ }
332
+ close(flush = false) {
333
+ if (this.state === 0 /* OPEN */) {
334
+ this.state = 1 /* CLOSED */;
335
+ flush && this.flush();
336
+ return this.process();
333
337
  }
334
- close(flush = false) {
335
- if (this.state === State.OPEN) {
336
- this.state = State.CLOSED;
337
- flush && this.flush();
338
- return this.process();
338
+ }
339
+ isClosed() {
340
+ return this.state !== 0 /* OPEN */;
341
+ }
342
+ isReadable() {
343
+ return this.state !== 2 /* DONE */ && this.buf && this.buf.length > 0 || this.writes && this.writes.length > 0 || this.txbuf && this.txbuf.length > 0;
344
+ }
345
+ consume(fn = (x) => console.log(this.id, ":", x)) {
346
+ return (async () => {
347
+ let x;
348
+ while ((x = null, x = await this.read()) !== void 0) {
349
+ await fn(x);
350
+ }
351
+ })();
352
+ }
353
+ produce(fn, close = true) {
354
+ return (async () => {
355
+ while (!this.isClosed()) {
356
+ const val = await fn();
357
+ if (val === void 0) {
358
+ close && await this.close();
359
+ break;
339
360
  }
361
+ await this.write(val);
362
+ }
363
+ })();
364
+ }
365
+ consumeWhileReadable(fn = (x) => console.log(this.id, ":", x)) {
366
+ return (async () => {
367
+ let x;
368
+ while (this.isReadable()) {
369
+ x = await this.read();
370
+ if (x === void 0) {
371
+ break;
372
+ }
373
+ await fn(x);
374
+ x = null;
375
+ }
376
+ })();
377
+ }
378
+ reduce(rfn, acc) {
379
+ return (async () => {
380
+ const [init, complete, reduce] = rfn;
381
+ acc = acc != null ? acc : init();
382
+ let x;
383
+ while ((x = null, x = await this.read()) !== void 0) {
384
+ acc = reduce(acc, x);
385
+ if (isReduced(acc)) {
386
+ acc = acc.deref();
387
+ break;
388
+ }
389
+ }
390
+ return unreduced(complete(acc));
391
+ })();
392
+ }
393
+ transduce(tx, rfn, acc) {
394
+ return (async () => {
395
+ const _rfn = tx(rfn);
396
+ return unreduced(_rfn[1](await this.reduce(_rfn, acc)));
397
+ })();
398
+ }
399
+ into(src, close = true) {
400
+ return (async () => {
401
+ for (let x of src) {
402
+ if (this.isClosed()) {
403
+ break;
404
+ }
405
+ await this.write(x);
406
+ }
407
+ close && await this.close();
408
+ })();
409
+ }
410
+ pipe(dest, close = true) {
411
+ if (!(dest instanceof Channel)) {
412
+ dest = new Channel(dest);
340
413
  }
341
- isClosed() {
342
- return this.state !== State.OPEN;
343
- }
344
- isReadable() {
345
- return ((this.state !== State.DONE && this.buf && this.buf.length > 0) ||
346
- (this.writes && this.writes.length > 0) ||
347
- (this.txbuf && this.txbuf.length > 0));
348
- }
349
- consume(fn = (x) => console.log(this.id, ":", x)) {
350
- return (async () => {
351
- let x;
352
- while (((x = null), (x = await this.read())) !== undefined) {
353
- await fn(x);
354
- }
355
- })();
414
+ this.consume((x) => dest.write(x)).then(() => {
415
+ close && dest.close();
416
+ });
417
+ return dest;
418
+ }
419
+ split(pred, truthy, falsey, close = true) {
420
+ if (!(truthy instanceof Channel)) {
421
+ truthy = new Channel();
356
422
  }
357
- produce(fn, close = true) {
358
- return (async () => {
359
- while (!this.isClosed()) {
360
- const val = await fn();
361
- if (val === undefined) {
362
- close && (await this.close());
363
- break;
364
- }
365
- await this.write(val);
366
- }
367
- })();
423
+ if (!(falsey instanceof Channel)) {
424
+ falsey = new Channel();
368
425
  }
369
- consumeWhileReadable(fn = (x) => console.log(this.id, ":", x)) {
370
- return (async () => {
371
- let x;
372
- while (this.isReadable()) {
373
- x = await this.read();
374
- if (x === undefined) {
375
- break;
376
- }
377
- await fn(x);
378
- x = null;
379
- }
380
- })();
426
+ this.consume((x) => (pred(x) ? truthy : falsey).write(x)).then(
427
+ () => {
428
+ close && (truthy.close(), falsey.close());
429
+ }
430
+ );
431
+ return [truthy, falsey];
432
+ }
433
+ concat(chans, close = true) {
434
+ return (async () => {
435
+ for (let c of chans) {
436
+ await c.consume((x) => this.write(x));
437
+ }
438
+ close && await this.close();
439
+ })();
440
+ }
441
+ release() {
442
+ if (this.state === 1 /* CLOSED */) {
443
+ this.state = 2 /* DONE */;
444
+ this.flush();
445
+ this.buf.release();
446
+ delete this.reads;
447
+ delete this.writes;
448
+ delete this.buf;
449
+ delete this.txbuf;
450
+ delete this.tx;
451
+ delete this.isBusy;
452
+ delete this.onerror;
381
453
  }
382
- reduce(rfn, acc) {
383
- return (async () => {
384
- const [init, complete, reduce] = rfn;
385
- acc = acc != null ? acc : init();
386
- let x;
387
- while (((x = null), (x = await this.read())) !== undefined) {
388
- acc = reduce(acc, x);
389
- if (isReduced(acc)) {
390
- acc = acc.deref();
391
- break;
392
- }
454
+ }
455
+ async process() {
456
+ if (!this.isBusy) {
457
+ this.isBusy = true;
458
+ const { buf, txbuf, reads, writes } = this;
459
+ let doProcess = true;
460
+ while (doProcess) {
461
+ while (reads.length && (txbuf.length || buf.length)) {
462
+ if (txbuf.length) {
463
+ const val = txbuf.drop();
464
+ if (val !== void 0) {
465
+ reads.drop()(val);
393
466
  }
394
- return unreduced(complete(acc));
395
- })();
396
- }
397
- transduce(tx, rfn, acc) {
398
- return (async () => {
399
- const _rfn = tx(rfn);
400
- return unreduced(_rfn[1](await this.reduce(_rfn, acc)));
401
- })();
402
- }
403
- into(src, close = true) {
404
- return (async () => {
405
- for (let x of src) {
406
- if (this.isClosed()) {
407
- break;
408
- }
409
- await this.write(x);
467
+ } else {
468
+ const val = await buf.drop().value();
469
+ if (val !== void 0) {
470
+ reads.drop()(val);
410
471
  }
411
- close && (await this.close());
412
- })();
413
- }
414
- pipe(dest, close = true) {
415
- if (!(dest instanceof Channel)) {
416
- dest = new Channel(dest);
417
- }
418
- this.consume((x) => dest.write(x)) // return undefined here?
419
- .then(() => {
420
- close && dest.close();
421
- });
422
- return dest;
423
- }
424
- split(pred, truthy, falsey, close = true) {
425
- if (!(truthy instanceof Channel)) {
426
- truthy = new Channel();
472
+ }
427
473
  }
428
- if (!(falsey instanceof Channel)) {
429
- falsey = new Channel();
474
+ while (writes.length && !buf.isFull()) {
475
+ const put = writes.drop();
476
+ buf.push(put);
477
+ put.resolve(true);
430
478
  }
431
- this.consume((x) => (pred(x) ? truthy : falsey).write(x)).then(() => {
432
- close && (truthy.close(), falsey.close());
433
- });
434
- return [truthy, falsey];
435
- }
436
- concat(chans, close = true) {
437
- return (async () => {
438
- for (let c of chans) {
439
- await c.consume((x) => this.write(x));
479
+ if (this.state === 1 /* CLOSED */) {
480
+ if (this.tx && !writes.length) {
481
+ try {
482
+ this.tx[1](this.txbuf);
483
+ } catch (e) {
484
+ this.onerror(e, this);
440
485
  }
441
- close && (await this.close());
442
- })();
443
- }
444
- release() {
445
- if (this.state === State.CLOSED) {
446
- this.state = State.DONE;
447
- this.flush();
448
- this.buf.release();
449
- delete this.reads;
450
- delete this.writes;
451
- delete this.buf;
452
- delete this.txbuf;
453
- delete this.tx;
454
- delete this.isBusy;
455
- delete this.onerror;
486
+ }
487
+ if (!this.isReadable()) {
488
+ this.release();
489
+ return;
490
+ }
456
491
  }
492
+ doProcess = reads.length && (txbuf.length || buf.length) || writes.length && !buf.isFull();
493
+ }
494
+ this.isBusy = false;
457
495
  }
458
- async process() {
459
- if (!this.isBusy) {
460
- this.isBusy = true;
461
- const { buf, txbuf, reads, writes } = this;
462
- let doProcess = true;
463
- while (doProcess) {
464
- while (reads.length && (txbuf.length || buf.length)) {
465
- if (txbuf.length) {
466
- const val = txbuf.drop();
467
- if (val !== undefined) {
468
- reads.drop()(val);
469
- }
470
- }
471
- else {
472
- const val = await buf.drop().value();
473
- if (val !== undefined) {
474
- reads.drop()(val);
475
- }
476
- }
477
- }
478
- while (writes.length && !buf.isFull()) {
479
- const put = writes.drop();
480
- buf.push(put);
481
- put.resolve(true);
482
- }
483
- if (this.state === State.CLOSED) {
484
- if (this.tx && !writes.length) {
485
- try {
486
- // finalize/complete transducer
487
- this.tx[1](this.txbuf);
488
- }
489
- catch (e) {
490
- this.onerror(e, this);
491
- }
492
- }
493
- if (!this.isReadable()) {
494
- this.release();
495
- return;
496
- }
497
- }
498
- doProcess =
499
- (reads.length && (txbuf.length || buf.length)) ||
500
- (writes.length && !buf.isFull());
501
- }
502
- this.isBusy = false;
503
- }
496
+ }
497
+ flush() {
498
+ let op;
499
+ while (op = this.reads.drop()) {
500
+ op();
504
501
  }
505
- flush() {
506
- let op;
507
- while ((op = this.reads.drop())) {
508
- op();
509
- }
510
- while ((op = this.writes.drop())) {
511
- op.resolve(false);
512
- }
513
- this.buf.release();
502
+ while (op = this.writes.drop()) {
503
+ op.resolve(false);
514
504
  }
505
+ this.buf.release();
506
+ }
515
507
  }
516
- const defaultErrorHandler = (e, chan, val) => console.log(chan.id, "error occurred", e.message, val !== undefined ? val : "");
508
+ const defaultErrorHandler = (e, chan, val) => console.log(
509
+ chan.id,
510
+ "error occurred",
511
+ e.message,
512
+ val !== void 0 ? val : ""
513
+ );
517
514
  const maybeBuffer = (x) => x instanceof FixedBuffer || typeof x === "number";
515
+ export {
516
+ Channel
517
+ };