@thi.ng/fibers 0.6.4 → 0.6.6

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.
Files changed (7) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +1 -1
  3. package/api.js +18 -19
  4. package/csp.js +200 -279
  5. package/fiber.js +396 -393
  6. package/ops.js +137 -325
  7. package/package.json +15 -12
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2023-12-09T19:12:03Z
3
+ - **Last updated**: 2023-12-18T13:41:19Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
package/README.md CHANGED
@@ -378,7 +378,7 @@ For Node.js REPL:
378
378
  const fibers = await import("@thi.ng/fibers");
379
379
  ```
380
380
 
381
- Package sizes (brotli'd, pre-treeshake): ESM: 2.60 KB
381
+ Package sizes (brotli'd, pre-treeshake): ESM: 2.64 KB
382
382
 
383
383
  ## Dependencies
384
384
 
package/api.js CHANGED
@@ -1,19 +1,18 @@
1
- export const STATE_NEW = 0;
2
- export const STATE_ACTIVE = 1;
3
- export const STATE_DONE = 2;
4
- export const STATE_CANCELED = 3;
5
- export const STATE_ERROR = 4;
6
- /**
7
- * Event ID for completed fiber. The event `value` will be the one given to
8
- * {@link Fiber.done} (if any).
9
- */
10
- export const EVENT_FIBER_DONE = "fiber-done";
11
- /**
12
- * Event ID for fiber cancellation.
13
- */
14
- export const EVENT_FIBER_CANCELED = "fiber-canceled";
15
- /**
16
- * Event ID for notifying about an error which occurred whilst executing a
17
- * fiber. The event `value` will be the error passed to {@link Fiber.catch}.
18
- */
19
- export const EVENT_FIBER_ERROR = "fiber-error";
1
+ const STATE_NEW = 0;
2
+ const STATE_ACTIVE = 1;
3
+ const STATE_DONE = 2;
4
+ const STATE_CANCELED = 3;
5
+ const STATE_ERROR = 4;
6
+ const EVENT_FIBER_DONE = "fiber-done";
7
+ const EVENT_FIBER_CANCELED = "fiber-canceled";
8
+ const EVENT_FIBER_ERROR = "fiber-error";
9
+ export {
10
+ EVENT_FIBER_CANCELED,
11
+ EVENT_FIBER_DONE,
12
+ EVENT_FIBER_ERROR,
13
+ STATE_ACTIVE,
14
+ STATE_CANCELED,
15
+ STATE_DONE,
16
+ STATE_ERROR,
17
+ STATE_NEW
18
+ };
package/csp.js CHANGED
@@ -4,287 +4,208 @@ import { Fiber, fiber } from "./fiber.js";
4
4
  const STATE_OPEN = 0;
5
5
  const STATE_CLOSING = 1;
6
6
  const STATE_CLOSED = 2;
7
- /**
8
- * Fiber-based CSP channel implementation, supporting any
9
- * {@link IReadWriteBuffer} implementation to customize read/write behaviors
10
- * (and ordering). By default uses a single value {@link fifo} buffer impl.
11
- */
12
- export class Channel {
13
- opts;
14
- buffer;
15
- state = STATE_OPEN;
16
- constructor(buffer = 1, opts) {
17
- this.opts = opts;
18
- this.buffer = isNumber(buffer) ? new FIFOBuffer(buffer) : buffer;
19
- }
20
- /**
21
- * Returns a new fiber which attempts to read a value from the channel and
22
- * "blocks" until that value is available. Unless the channel has meanwhile
23
- * been closed, the fiber returns the read value (otherwise: `undefined`).
24
- *
25
- * @remarks
26
- * Depending on chosen back buffer behavior/implementation and
27
- * {@link Channel.close}, read requests might still be successful whilst the
28
- * channel is closing and there're still buffered values.
29
- *
30
- * @example
31
- * ```ts
32
- * const val = yield* chan.read();
33
- * ```
34
- */
35
- read() {
36
- const $this = this;
37
- return fiber(function* (ctx) {
38
- while ($this.readable()) {
39
- // wait until channel is readable
40
- if ($this.buffer.readable()) {
41
- const val = $this.buffer.read();
42
- ctx.logger?.debug("read", val);
43
- return val;
44
- }
45
- else if ($this.state === STATE_CLOSING) {
46
- return;
47
- }
48
- yield;
49
- }
50
- }, this.opts);
51
- }
52
- /**
53
- * Returns a new fiber which attempts to write the given `value` to the
54
- * channel and "blocks" until channel is writable (which depends on the
55
- * channel's buffer implementation).
56
- *
57
- * @remarks
58
- * Once the channel has been closed (or still is closing, see
59
- * {@link Channel.close}), all write requests will be silently ignored.
60
- *
61
- * @example
62
- * ```ts
63
- * yield* chan.write(23);
64
- * ```
65
- */
66
- write(val) {
67
- const $this = this;
68
- return fiber(function* (ctx) {
69
- while ($this.writable()) {
70
- // wait until channel is writable
71
- if ($this.buffer.writable()) {
72
- ctx.logger?.debug("write", val);
73
- $this.buffer.write(val);
74
- return;
75
- }
76
- yield;
77
- }
78
- }, this.opts);
79
- }
80
- /**
81
- * Returns new fiber which closes the channel. By default this op will defer
82
- * the full closing until all buffered values have been read (by another
83
- * fiber), however any writes will already become unavailable/ignored even
84
- * at this stage (also see {@link Channel.write}). If `wait=false`, the
85
- * channel will be closed immediately, the backing buffered cleared and any
86
- * in-flight reads or writes will be canceled.
87
- *
88
- * @param wait
89
- */
90
- close(wait = true) {
91
- const $this = this;
92
- return fiber(function* (ctx) {
93
- if ($this.state >= STATE_CLOSING)
94
- return;
95
- if (wait) {
96
- ctx.logger?.debug("waiting to close...");
97
- $this.state = STATE_CLOSING;
98
- while ($this.buffer.readable())
99
- yield;
100
- }
101
- $this.state = STATE_CLOSED;
102
- $this.buffer.clear();
103
- ctx.logger?.debug("channel closed");
104
- }, this.opts);
105
- }
106
- /**
107
- * Returns true if the channel is principally readable (i.e. not yet
108
- * closed), however there might not be any values available yet and reads
109
- * might block.
110
- */
111
- readable() {
112
- return this.state <= STATE_CLOSING;
113
- }
114
- /**
115
- * Returns true if the channel is principally writable (i.e. not closing or
116
- * closed), however depending on buffer behavior the channel might not yet
117
- * accept new values and writes might block.
118
- */
119
- writable() {
120
- return this.state === STATE_OPEN;
121
- }
122
- /**
123
- * Returns true if the channel is fully closed and no further reads or
124
- * writes are possible.
125
- */
126
- closed() {
127
- return this.state === STATE_CLOSED;
128
- }
7
+ class Channel {
8
+ constructor(buffer = 1, opts) {
9
+ this.opts = opts;
10
+ this.buffer = isNumber(buffer) ? new FIFOBuffer(buffer) : buffer;
11
+ }
12
+ buffer;
13
+ state = STATE_OPEN;
14
+ /**
15
+ * Returns a new fiber which attempts to read a value from the channel and
16
+ * "blocks" until that value is available. Unless the channel has meanwhile
17
+ * been closed, the fiber returns the read value (otherwise: `undefined`).
18
+ *
19
+ * @remarks
20
+ * Depending on chosen back buffer behavior/implementation and
21
+ * {@link Channel.close}, read requests might still be successful whilst the
22
+ * channel is closing and there're still buffered values.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * const val = yield* chan.read();
27
+ * ```
28
+ */
29
+ read() {
30
+ const $this = this;
31
+ return fiber(function* (ctx) {
32
+ while ($this.readable()) {
33
+ if ($this.buffer.readable()) {
34
+ const val = $this.buffer.read();
35
+ ctx.logger?.debug("read", val);
36
+ return val;
37
+ } else if ($this.state === STATE_CLOSING) {
38
+ return;
39
+ }
40
+ yield;
41
+ }
42
+ }, this.opts);
43
+ }
44
+ /**
45
+ * Returns a new fiber which attempts to write the given `value` to the
46
+ * channel and "blocks" until channel is writable (which depends on the
47
+ * channel's buffer implementation).
48
+ *
49
+ * @remarks
50
+ * Once the channel has been closed (or still is closing, see
51
+ * {@link Channel.close}), all write requests will be silently ignored.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * yield* chan.write(23);
56
+ * ```
57
+ */
58
+ write(val) {
59
+ const $this = this;
60
+ return fiber(function* (ctx) {
61
+ while ($this.writable()) {
62
+ if ($this.buffer.writable()) {
63
+ ctx.logger?.debug("write", val);
64
+ $this.buffer.write(val);
65
+ return;
66
+ }
67
+ yield;
68
+ }
69
+ }, this.opts);
70
+ }
71
+ /**
72
+ * Returns new fiber which closes the channel. By default this op will defer
73
+ * the full closing until all buffered values have been read (by another
74
+ * fiber), however any writes will already become unavailable/ignored even
75
+ * at this stage (also see {@link Channel.write}). If `wait=false`, the
76
+ * channel will be closed immediately, the backing buffered cleared and any
77
+ * in-flight reads or writes will be canceled.
78
+ *
79
+ * @param wait
80
+ */
81
+ close(wait = true) {
82
+ const $this = this;
83
+ return fiber(function* (ctx) {
84
+ if ($this.state >= STATE_CLOSING)
85
+ return;
86
+ if (wait) {
87
+ ctx.logger?.debug("waiting to close...");
88
+ $this.state = STATE_CLOSING;
89
+ while ($this.buffer.readable())
90
+ yield;
91
+ }
92
+ $this.state = STATE_CLOSED;
93
+ $this.buffer.clear();
94
+ ctx.logger?.debug("channel closed");
95
+ }, this.opts);
96
+ }
97
+ /**
98
+ * Returns true if the channel is principally readable (i.e. not yet
99
+ * closed), however there might not be any values available yet and reads
100
+ * might block.
101
+ */
102
+ readable() {
103
+ return this.state <= STATE_CLOSING;
104
+ }
105
+ /**
106
+ * Returns true if the channel is principally writable (i.e. not closing or
107
+ * closed), however depending on buffer behavior the channel might not yet
108
+ * accept new values and writes might block.
109
+ */
110
+ writable() {
111
+ return this.state === STATE_OPEN;
112
+ }
113
+ /**
114
+ * Returns true if the channel is fully closed and no further reads or
115
+ * writes are possible.
116
+ */
117
+ closed() {
118
+ return this.state === STATE_CLOSED;
119
+ }
129
120
  }
130
- /**
131
- * Functional syntax sugar for {@link Channel} ctor, using provided backing
132
- * buffer and shared options for all fibers returned by the channel for its
133
- * various operations.
134
- *
135
- * @remarks
136
- * If `buffer` is given as number, a {@link fifo} buffer of given capacity will
137
- * be used.
138
- *
139
- * @example
140
- * ```ts
141
- * // create unbuffered channel with single value capacity
142
- * const chan = channel();
143
- *
144
- * // create channel with a fixed buffer capacity of 3 values
145
- * const chan2 = channel(3);
146
- *
147
- * // create channel with a sliding window buffer and custom ID & logger
148
- * const chan3 = channel(
149
- * sliding(3),
150
- * { id: "main", logger: new ConsoleLogger("chan") }
151
- * );
152
- * ```
153
- *
154
- * @param buffer
155
- * @param opts
156
- */
157
- export const channel = (buffer, opts) => new Channel(buffer, opts);
158
- /**
159
- * First-in, first-out ring buffer implementation for use with {@link Channel}.
160
- */
161
- export class FIFOBuffer {
162
- buf;
163
- rpos = 0;
164
- wpos = 0;
165
- constructor(cap = 1) {
166
- assert(cap >= 1, `capacity must be >= 1`);
167
- this.buf = new Array(cap + 1);
168
- }
169
- clear() {
170
- this.buf.fill(undefined);
171
- }
172
- readable() {
173
- return this.rpos !== this.wpos;
174
- }
175
- read() {
176
- const { buf, rpos } = this;
177
- const val = buf[rpos];
178
- buf[rpos] = undefined;
179
- this.rpos = (rpos + 1) % buf.length;
180
- return val;
181
- }
182
- writable() {
183
- return (this.wpos + 1) % this.buf.length !== this.rpos;
184
- }
185
- write(x) {
186
- const { buf, wpos } = this;
187
- buf[wpos] = x;
188
- this.wpos = (wpos + 1) % buf.length;
189
- }
121
+ const channel = (buffer, opts) => new Channel(buffer, opts);
122
+ class FIFOBuffer {
123
+ buf;
124
+ rpos = 0;
125
+ wpos = 0;
126
+ constructor(cap = 1) {
127
+ assert(cap >= 1, `capacity must be >= 1`);
128
+ this.buf = new Array(cap + 1);
129
+ }
130
+ clear() {
131
+ this.buf.fill(void 0);
132
+ }
133
+ readable() {
134
+ return this.rpos !== this.wpos;
135
+ }
136
+ read() {
137
+ const { buf, rpos } = this;
138
+ const val = buf[rpos];
139
+ buf[rpos] = void 0;
140
+ this.rpos = (rpos + 1) % buf.length;
141
+ return val;
142
+ }
143
+ writable() {
144
+ return (this.wpos + 1) % this.buf.length !== this.rpos;
145
+ }
146
+ write(x) {
147
+ const { buf, wpos } = this;
148
+ buf[wpos] = x;
149
+ this.wpos = (wpos + 1) % buf.length;
150
+ }
190
151
  }
191
- /**
192
- * Returns a {@link FIFOBuffer} ring buffer with given capacity for use with
193
- * {@link channel}.
194
- *
195
- * @remarks
196
- * With this implementation, writes to the channel will only start blocking once
197
- * the buffer's capacity is reached, otherwise complete immediately. Likewise,
198
- * channel reads are non-blocking whilst there're more buffered values
199
- * available. Reads will only block if the buffer is empty.
200
- *
201
- * Also see {@link lifo}.
202
- *
203
- * @param cap
204
- */
205
- export const fifo = (cap) => new FIFOBuffer(cap);
206
- export class LIFOBuffer {
207
- cap;
208
- buf = [];
209
- constructor(cap = 1) {
210
- this.cap = cap;
211
- assert(cap >= 1, `capacity must be >= 1`);
212
- }
213
- clear() {
214
- this.buf.length = 0;
215
- }
216
- readable() {
217
- return this.buf.length > 0;
218
- }
219
- read() {
220
- return this.buf.pop();
221
- }
222
- writable() {
223
- return this.buf.length < this.cap;
224
- }
225
- write(x) {
226
- this.buf.push(x);
227
- }
152
+ const fifo = (cap) => new FIFOBuffer(cap);
153
+ class LIFOBuffer {
154
+ constructor(cap = 1) {
155
+ this.cap = cap;
156
+ assert(cap >= 1, `capacity must be >= 1`);
157
+ }
158
+ buf = [];
159
+ clear() {
160
+ this.buf.length = 0;
161
+ }
162
+ readable() {
163
+ return this.buf.length > 0;
164
+ }
165
+ read() {
166
+ return this.buf.pop();
167
+ }
168
+ writable() {
169
+ return this.buf.length < this.cap;
170
+ }
171
+ write(x) {
172
+ this.buf.push(x);
173
+ }
228
174
  }
229
- /**
230
- * Returns a {@link LIFOBuffer} with given capacity for use with
231
- * {@link channel}.
232
- *
233
- * @remarks
234
- * Read/write behavior is mostly the same as with {@link fifo}, with the
235
- * important difference, that (as the name indicates), the last value written
236
- * will be the first value read (i.e. stack behavior).
237
- *
238
- * @param cap
239
- */
240
- export const lifo = (cap) => new LIFOBuffer(cap);
241
- export class SlidingBuffer extends FIFOBuffer {
242
- writable() {
243
- return true;
244
- }
245
- write(x) {
246
- if (!super.writable()) {
247
- const { buf, rpos } = this;
248
- buf[rpos] = undefined;
249
- this.rpos = (rpos + 1) % buf.length;
250
- }
251
- super.write(x);
252
- }
175
+ const lifo = (cap) => new LIFOBuffer(cap);
176
+ class SlidingBuffer extends FIFOBuffer {
177
+ writable() {
178
+ return true;
179
+ }
180
+ write(x) {
181
+ if (!super.writable()) {
182
+ const { buf, rpos } = this;
183
+ buf[rpos] = void 0;
184
+ this.rpos = (rpos + 1) % buf.length;
185
+ }
186
+ super.write(x);
187
+ }
253
188
  }
254
- /**
255
- * Returns a {@link SlidingBuffer} with given capacity for use with
256
- * {@link channel}.
257
- *
258
- * @remarks
259
- * With this implementation, writes to the channel are **never** blocking! Once
260
- * the buffer's capacity is reached, a new write will first expunge the oldest
261
- * buffered value. Read behavior is the same as for {@link fifo}.
262
- *
263
- * Also see {@link dropping} for alternative behavior.
264
- *
265
- * @param cap
266
- */
267
- export const sliding = (cap) => new SlidingBuffer(cap);
268
- export class DroppingBuffer extends FIFOBuffer {
269
- writable() {
270
- return true;
271
- }
272
- write(x) {
273
- if (super.writable())
274
- super.write(x);
275
- }
189
+ const sliding = (cap) => new SlidingBuffer(cap);
190
+ class DroppingBuffer extends FIFOBuffer {
191
+ writable() {
192
+ return true;
193
+ }
194
+ write(x) {
195
+ if (super.writable())
196
+ super.write(x);
197
+ }
276
198
  }
277
- /**
278
- * Returns a {@link DroppingBuffer} with given capacity for use with
279
- * {@link channel}.
280
- *
281
- * @remarks
282
- * With this implementation, writes to the channel are **never** blocking!
283
- * Whilst the buffer's capacity is reached, new writes will be silently ignored.
284
- * Read behavior is the same as for {@link fifo}.
285
- *
286
- * Also see {@link sliding} for alternative behavior.
287
- *
288
- * @param cap
289
- */
290
- export const dropping = (cap) => new DroppingBuffer(cap);
199
+ const dropping = (cap) => new DroppingBuffer(cap);
200
+ export {
201
+ Channel,
202
+ DroppingBuffer,
203
+ FIFOBuffer,
204
+ LIFOBuffer,
205
+ SlidingBuffer,
206
+ channel,
207
+ dropping,
208
+ fifo,
209
+ lifo,
210
+ sliding
211
+ };