@thi.ng/csp 2.1.115 → 3.0.0
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/CHANGELOG.md +35 -1
- package/README.md +50 -183
- package/api.d.ts +12 -20
- package/channel.d.ts +37 -145
- package/channel.js +131 -480
- package/idgen.d.ts +3 -0
- package/idgen.js +5 -0
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/mult.d.ts +12 -20
- package/mult.js +42 -80
- package/ops.d.ts +23 -0
- package/ops.js +117 -0
- package/package.json +19 -17
- package/pubsub.d.ts +14 -20
- package/pubsub.js +32 -49
- package/buffer.d.ts +0 -24
- package/buffer.js +0 -67
package/channel.js
CHANGED
|
@@ -1,519 +1,170 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return State2;
|
|
15
|
-
})(State || {});
|
|
1
|
+
import { fifo } from "@thi.ng/buffers/fifo";
|
|
2
|
+
import { isNumber } from "@thi.ng/checks/is-number";
|
|
3
|
+
import { isPlainObject } from "@thi.ng/checks/is-plain-object";
|
|
4
|
+
import { illegalState } from "@thi.ng/errors/illegal-state";
|
|
5
|
+
import { __nextID } from "./idgen.js";
|
|
6
|
+
const MAX_READS = 1024;
|
|
7
|
+
const MAX_QUEUE = 1024;
|
|
8
|
+
const STATE_OPEN = 0;
|
|
9
|
+
const STATE_CLOSING = 1;
|
|
10
|
+
const STATE_CLOSED = 2;
|
|
11
|
+
function channel(...args) {
|
|
12
|
+
return new Channel(...args);
|
|
13
|
+
}
|
|
16
14
|
class Channel {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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;
|
|
15
|
+
id;
|
|
16
|
+
writes;
|
|
17
|
+
queue = [];
|
|
18
|
+
reads = [];
|
|
19
|
+
races = [];
|
|
20
|
+
state = STATE_OPEN;
|
|
21
|
+
constructor(...args) {
|
|
22
|
+
let buf = 1;
|
|
23
|
+
let opts;
|
|
74
24
|
switch (args.length) {
|
|
75
25
|
case 1:
|
|
26
|
+
if (isPlainObject(args[0]))
|
|
27
|
+
opts = args[0];
|
|
28
|
+
else
|
|
29
|
+
buf = args[0];
|
|
76
30
|
break;
|
|
77
31
|
case 2:
|
|
78
|
-
|
|
79
|
-
close = args[1];
|
|
80
|
-
} else {
|
|
81
|
-
tx = args[1];
|
|
82
|
-
}
|
|
32
|
+
[buf, opts] = args;
|
|
83
33
|
break;
|
|
84
|
-
case 3:
|
|
85
|
-
tx = args[1];
|
|
86
|
-
close = args[2];
|
|
87
|
-
break;
|
|
88
|
-
default:
|
|
89
|
-
illegalArity(args.length);
|
|
90
34
|
}
|
|
91
|
-
|
|
92
|
-
chan
|
|
93
|
-
|
|
35
|
+
this.writes = isNumber(buf) ? fifo(buf) : buf;
|
|
36
|
+
this.id = opts?.id ?? `chan-${__nextID()}`;
|
|
37
|
+
}
|
|
38
|
+
async *[Symbol.asyncIterator]() {
|
|
39
|
+
while (this.state < STATE_CLOSED) {
|
|
40
|
+
const x = await this.read();
|
|
41
|
+
if (x !== void 0)
|
|
42
|
+
yield x;
|
|
43
|
+
}
|
|
94
44
|
}
|
|
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) {
|
|
45
|
+
read() {
|
|
104
46
|
return new Promise((resolve) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
c.read().then((x) => resolve([x, c]));
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
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
|
-
}
|
|
47
|
+
if (!this.readable()) {
|
|
48
|
+
resolve(void 0);
|
|
49
|
+
return;
|
|
147
50
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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 tangle:../export/merge-tuples.ts
|
|
167
|
-
* import { Channel } from "@thi.ng/csp";
|
|
168
|
-
*
|
|
169
|
-
* Channel.mergeTuples([
|
|
170
|
-
* Channel.from([1, 2, 3]),
|
|
171
|
-
* Channel.from([10, 20, 30]),
|
|
172
|
-
* Channel.from([100, 200, 300])
|
|
173
|
-
* ]).consume();
|
|
174
|
-
*
|
|
175
|
-
* // chan-0 : [ 1, 10, 100 ]
|
|
176
|
-
* // chan-0 : [ 2, 20, 200 ]
|
|
177
|
-
* // chan-0 : [ 3, 30, 300 ]
|
|
178
|
-
* // chan-0 done
|
|
179
|
-
*
|
|
180
|
-
* Channel.mergeTuples([
|
|
181
|
-
* Channel.from([1, 2, 3]),
|
|
182
|
-
* Channel.from([10, 20, 30]),
|
|
183
|
-
* Channel.from([100, 200, 300])
|
|
184
|
-
* ], null, false).consume();
|
|
185
|
-
* ```
|
|
186
|
-
*
|
|
187
|
-
* @param chans - source channels
|
|
188
|
-
* @param out - result channel
|
|
189
|
-
* @param closeOnFirst - true, if result closes when first input is done
|
|
190
|
-
* @param closeOutput - true, if result closes when all inputs are done
|
|
191
|
-
*/
|
|
192
|
-
static mergeTuples(chans, out, closeOnFirst = true, closeOutput = true) {
|
|
193
|
-
out = out || new Channel();
|
|
194
|
-
(async () => {
|
|
195
|
-
let buf = [];
|
|
196
|
-
let orig = [...chans];
|
|
197
|
-
let sel = new Set(chans);
|
|
198
|
-
let n = chans.length;
|
|
199
|
-
while (true) {
|
|
200
|
-
let [x, ch] = await Channel.select([...sel]);
|
|
201
|
-
let idx = orig.indexOf(ch);
|
|
202
|
-
if (x === void 0) {
|
|
203
|
-
if (closeOnFirst || chans.length === 1) {
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
chans.splice(idx, 1);
|
|
207
|
-
}
|
|
208
|
-
buf[idx] = x;
|
|
209
|
-
sel.delete(ch);
|
|
210
|
-
if (--n === 0) {
|
|
211
|
-
await out.write(buf);
|
|
212
|
-
buf = [];
|
|
213
|
-
n = chans.length;
|
|
214
|
-
sel = new Set(chans);
|
|
51
|
+
if (this.state < STATE_CLOSING || this.writes.readable()) {
|
|
52
|
+
if (this.reads.length < MAX_READS) {
|
|
53
|
+
this.reads.push(resolve);
|
|
54
|
+
} else {
|
|
55
|
+
resolve(void 0);
|
|
215
56
|
}
|
|
216
57
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
58
|
+
if (this.writes.readable())
|
|
59
|
+
this.deliver();
|
|
60
|
+
});
|
|
220
61
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
];
|
|
229
|
-
id;
|
|
230
|
-
onerror;
|
|
231
|
-
state;
|
|
232
|
-
buf;
|
|
233
|
-
tx;
|
|
234
|
-
writes;
|
|
235
|
-
reads;
|
|
236
|
-
txbuf;
|
|
237
|
-
isBusy;
|
|
238
|
-
constructor(...args) {
|
|
239
|
-
let id, buf, tx, err;
|
|
240
|
-
let [a, b] = args;
|
|
241
|
-
switch (args.length) {
|
|
242
|
-
case 0:
|
|
243
|
-
break;
|
|
244
|
-
case 1:
|
|
245
|
-
if (typeof a === "string") {
|
|
246
|
-
id = a;
|
|
247
|
-
} else if (maybeBuffer(a)) {
|
|
248
|
-
buf = a;
|
|
249
|
-
} else {
|
|
250
|
-
tx = a;
|
|
251
|
-
}
|
|
252
|
-
break;
|
|
253
|
-
case 2:
|
|
254
|
-
if (typeof a === "string") {
|
|
255
|
-
id = a;
|
|
256
|
-
if (maybeBuffer(b)) {
|
|
257
|
-
buf = b;
|
|
258
|
-
} else {
|
|
259
|
-
tx = b;
|
|
260
|
-
}
|
|
261
|
-
} else {
|
|
262
|
-
[tx, err] = args;
|
|
263
|
-
}
|
|
264
|
-
break;
|
|
265
|
-
case 3:
|
|
266
|
-
if (isFunction(args[1]) && isFunction(args[2])) {
|
|
267
|
-
[id, tx, err] = args;
|
|
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);
|
|
62
|
+
poll() {
|
|
63
|
+
const { reads, writes } = this;
|
|
64
|
+
if (this.readable() && !reads.length && writes.readable()) {
|
|
65
|
+
const [msg, write] = writes.read();
|
|
66
|
+
write(true);
|
|
67
|
+
this.updateQueue();
|
|
68
|
+
return msg;
|
|
277
69
|
}
|
|
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 = 0 /* OPEN */;
|
|
287
|
-
this.isBusy = false;
|
|
288
70
|
}
|
|
289
|
-
|
|
290
|
-
return this;
|
|
291
|
-
}
|
|
292
|
-
write(value) {
|
|
71
|
+
write(msg) {
|
|
293
72
|
return new Promise((resolve) => {
|
|
294
|
-
if (this.
|
|
73
|
+
if (!this.writable()) {
|
|
295
74
|
resolve(false);
|
|
75
|
+
return;
|
|
296
76
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
this.state = 1 /* CLOSED */;
|
|
303
|
-
}
|
|
304
|
-
} catch (e) {
|
|
305
|
-
this.onerror(e, this, value);
|
|
306
|
-
}
|
|
307
|
-
} : () => value,
|
|
308
|
-
resolve
|
|
309
|
-
});
|
|
310
|
-
this.process();
|
|
311
|
-
} else {
|
|
312
|
-
throw new Error(
|
|
313
|
-
`channel stalled (${Channel.MAX_WRITES} unprocessed writes)`
|
|
77
|
+
const { reads, writes, races, queue } = this;
|
|
78
|
+
const val = [msg, resolve];
|
|
79
|
+
if (!(writes.writable() && writes.write(val))) {
|
|
80
|
+
queue.length < MAX_QUEUE ? queue.push(val) : illegalState(
|
|
81
|
+
"max. queue capacity reached, reduce back pressure!"
|
|
314
82
|
);
|
|
315
83
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
if (this.state === 2 /* DONE */) {
|
|
321
|
-
resolve(void 0);
|
|
84
|
+
if (reads.length) {
|
|
85
|
+
this.deliver();
|
|
86
|
+
} else if (races.length) {
|
|
87
|
+
races.shift()(this);
|
|
322
88
|
}
|
|
323
|
-
this.reads.push(resolve);
|
|
324
|
-
this.process();
|
|
325
89
|
});
|
|
326
90
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
(
|
|
330
|
-
|
|
331
|
-
))();
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
close(flush = false) {
|
|
335
|
-
if (this.state === 0 /* OPEN */) {
|
|
336
|
-
this.state = 1 /* CLOSED */;
|
|
337
|
-
flush && this.flush();
|
|
338
|
-
return this.process();
|
|
91
|
+
offer(msg) {
|
|
92
|
+
if (this.writable() && this.writes.writable()) {
|
|
93
|
+
this.write(msg);
|
|
94
|
+
return true;
|
|
339
95
|
}
|
|
96
|
+
return false;
|
|
340
97
|
}
|
|
341
|
-
|
|
342
|
-
return
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
consume(fn = (x) => console.log(this.id, ":", x)) {
|
|
348
|
-
return (async () => {
|
|
349
|
-
let x;
|
|
350
|
-
while ((x = null, x = await this.read()) !== void 0) {
|
|
351
|
-
await fn(x);
|
|
352
|
-
}
|
|
353
|
-
})();
|
|
354
|
-
}
|
|
355
|
-
produce(fn, close = true) {
|
|
356
|
-
return (async () => {
|
|
357
|
-
while (!this.isClosed()) {
|
|
358
|
-
const val = await fn();
|
|
359
|
-
if (val === void 0) {
|
|
360
|
-
close && await this.close();
|
|
361
|
-
break;
|
|
362
|
-
}
|
|
363
|
-
await this.write(val);
|
|
364
|
-
}
|
|
365
|
-
})();
|
|
366
|
-
}
|
|
367
|
-
consumeWhileReadable(fn = (x) => console.log(this.id, ":", x)) {
|
|
368
|
-
return (async () => {
|
|
369
|
-
let x;
|
|
370
|
-
while (this.isReadable()) {
|
|
371
|
-
x = await this.read();
|
|
372
|
-
if (x === void 0) {
|
|
373
|
-
break;
|
|
374
|
-
}
|
|
375
|
-
await fn(x);
|
|
376
|
-
x = null;
|
|
377
|
-
}
|
|
378
|
-
})();
|
|
379
|
-
}
|
|
380
|
-
reduce(rfn, acc) {
|
|
381
|
-
return (async () => {
|
|
382
|
-
const [init, complete, reduce] = rfn;
|
|
383
|
-
acc = acc != null ? acc : init();
|
|
384
|
-
let x;
|
|
385
|
-
while ((x = null, x = await this.read()) !== void 0) {
|
|
386
|
-
acc = reduce(acc, x);
|
|
387
|
-
if (isReduced(acc)) {
|
|
388
|
-
acc = acc.deref();
|
|
389
|
-
break;
|
|
390
|
-
}
|
|
98
|
+
race() {
|
|
99
|
+
return new Promise((resolve) => {
|
|
100
|
+
if (!this.readable()) {
|
|
101
|
+
resolve(this);
|
|
102
|
+
return;
|
|
391
103
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
transduce(tx, rfn, acc) {
|
|
396
|
-
return (async () => {
|
|
397
|
-
const _rfn = tx(rfn);
|
|
398
|
-
return unreduced(_rfn[1](await this.reduce(_rfn, acc)));
|
|
399
|
-
})();
|
|
400
|
-
}
|
|
401
|
-
into(src, close = true) {
|
|
402
|
-
return (async () => {
|
|
403
|
-
for (let x of src) {
|
|
404
|
-
if (this.isClosed()) {
|
|
405
|
-
break;
|
|
406
|
-
}
|
|
407
|
-
await this.write(x);
|
|
104
|
+
this.races.push(resolve);
|
|
105
|
+
if (this.writes.readable()) {
|
|
106
|
+
this.races.shift()(this);
|
|
408
107
|
}
|
|
409
|
-
close && await this.close();
|
|
410
|
-
})();
|
|
411
|
-
}
|
|
412
|
-
pipe(dest, close = true) {
|
|
413
|
-
if (!(dest instanceof Channel)) {
|
|
414
|
-
dest = new Channel(dest);
|
|
415
|
-
}
|
|
416
|
-
this.consume((x) => dest.write(x)).then(() => {
|
|
417
|
-
close && dest.close();
|
|
418
108
|
});
|
|
419
|
-
return dest;
|
|
420
109
|
}
|
|
421
|
-
|
|
422
|
-
if (
|
|
423
|
-
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
|
|
110
|
+
close() {
|
|
111
|
+
if (this.state >= STATE_CLOSING)
|
|
112
|
+
return;
|
|
113
|
+
const { reads, writes, races } = this;
|
|
114
|
+
this.state = reads.length || writes.readable() ? STATE_CLOSING : STATE_CLOSED;
|
|
115
|
+
while (reads.length && writes.readable())
|
|
116
|
+
this.deliver();
|
|
117
|
+
if (!writes.readable()) {
|
|
118
|
+
while (reads.length)
|
|
119
|
+
reads.shift()(void 0);
|
|
427
120
|
}
|
|
428
|
-
this.
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
);
|
|
433
|
-
return [truthy, falsey];
|
|
434
|
-
}
|
|
435
|
-
concat(chans, close = true) {
|
|
436
|
-
return (async () => {
|
|
437
|
-
for (let c of chans) {
|
|
438
|
-
await c.consume((x) => this.write(x));
|
|
439
|
-
}
|
|
440
|
-
close && await this.close();
|
|
441
|
-
})();
|
|
121
|
+
this.state = writes.readable() ? STATE_CLOSING : STATE_CLOSED;
|
|
122
|
+
while (races.length)
|
|
123
|
+
races.shift()(this);
|
|
442
124
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
delete this.buf;
|
|
451
|
-
delete this.txbuf;
|
|
452
|
-
delete this.tx;
|
|
453
|
-
delete this.isBusy;
|
|
454
|
-
delete this.onerror;
|
|
455
|
-
}
|
|
125
|
+
/**
|
|
126
|
+
* Returns true if the channel is principally readable (i.e. not yet
|
|
127
|
+
* closed), however there might not be any values available yet and reads
|
|
128
|
+
* might block.
|
|
129
|
+
*/
|
|
130
|
+
readable() {
|
|
131
|
+
return this.state < STATE_CLOSED;
|
|
456
132
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
if (txbuf.length) {
|
|
465
|
-
const val = txbuf.drop();
|
|
466
|
-
if (val !== void 0) {
|
|
467
|
-
reads.drop()(val);
|
|
468
|
-
}
|
|
469
|
-
} else {
|
|
470
|
-
const val = await buf.drop().value();
|
|
471
|
-
if (val !== void 0) {
|
|
472
|
-
reads.drop()(val);
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
while (writes.length && !buf.isFull()) {
|
|
477
|
-
const put = writes.drop();
|
|
478
|
-
buf.push(put);
|
|
479
|
-
put.resolve(true);
|
|
480
|
-
}
|
|
481
|
-
if (this.state === 1 /* CLOSED */) {
|
|
482
|
-
if (this.tx && !writes.length) {
|
|
483
|
-
try {
|
|
484
|
-
this.tx[1](this.txbuf);
|
|
485
|
-
} catch (e) {
|
|
486
|
-
this.onerror(e, this);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
if (!this.isReadable()) {
|
|
490
|
-
this.release();
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
doProcess = reads.length && (txbuf.length || buf.length) || writes.length && !buf.isFull();
|
|
495
|
-
}
|
|
496
|
-
this.isBusy = false;
|
|
497
|
-
}
|
|
133
|
+
/**
|
|
134
|
+
* Returns true if the channel is principally writable (i.e. not closing or
|
|
135
|
+
* closed), however depending on buffer behavior the channel might not yet
|
|
136
|
+
* accept new values and writes might block.
|
|
137
|
+
*/
|
|
138
|
+
writable() {
|
|
139
|
+
return this.state === STATE_OPEN;
|
|
498
140
|
}
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Returns true if the channel is fully closed and no further reads or
|
|
143
|
+
* writes are possible.
|
|
144
|
+
*/
|
|
145
|
+
closed() {
|
|
146
|
+
return this.state === STATE_CLOSED;
|
|
147
|
+
}
|
|
148
|
+
deliver() {
|
|
149
|
+
const { reads, writes } = this;
|
|
150
|
+
const [msg, write] = writes.read();
|
|
151
|
+
write(true);
|
|
152
|
+
reads.shift()(msg);
|
|
153
|
+
this.updateQueue();
|
|
154
|
+
}
|
|
155
|
+
updateQueue() {
|
|
156
|
+
const { queue, writes } = this;
|
|
157
|
+
if (queue.length && writes.writable()) {
|
|
158
|
+
writes.write(queue.shift());
|
|
503
159
|
}
|
|
504
|
-
|
|
505
|
-
|
|
160
|
+
if (this.state === STATE_CLOSING && !writes.readable()) {
|
|
161
|
+
this.state = STATE_CLOSED;
|
|
506
162
|
}
|
|
507
|
-
this.buf.release();
|
|
508
163
|
}
|
|
509
164
|
}
|
|
510
|
-
const defaultErrorHandler = (e, chan, val) => console.log(
|
|
511
|
-
chan.id,
|
|
512
|
-
"error occurred",
|
|
513
|
-
e.message,
|
|
514
|
-
val !== void 0 ? val : ""
|
|
515
|
-
);
|
|
516
|
-
const maybeBuffer = (x) => x instanceof FixedBuffer || typeof x === "number";
|
|
517
165
|
export {
|
|
518
|
-
Channel
|
|
166
|
+
Channel,
|
|
167
|
+
MAX_QUEUE,
|
|
168
|
+
MAX_READS,
|
|
169
|
+
channel
|
|
519
170
|
};
|
package/idgen.d.ts
ADDED
package/idgen.js
ADDED
package/index.d.ts
CHANGED