@thi.ng/fibers 0.6.4 → 0.6.5

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 +14 -11
package/fiber.js CHANGED
@@ -1,406 +1,409 @@
1
- var Fiber_1;
2
- import { __decorate } from "tslib";
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result)
9
+ __defProp(target, key, result);
10
+ return result;
11
+ };
3
12
  import { INotifyMixin } from "@thi.ng/api/mixins/inotify";
4
13
  import { isFunction } from "@thi.ng/checks/is-function";
5
14
  import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
6
15
  import { illegalState } from "@thi.ng/errors/illegal-state";
7
16
  import { monotonic, prefixed } from "@thi.ng/idgen";
8
- import { EVENT_FIBER_CANCELED, EVENT_FIBER_DONE, EVENT_FIBER_ERROR, STATE_ACTIVE, STATE_CANCELED, STATE_DONE, STATE_ERROR, STATE_NEW, } from "./api.js";
17
+ import {
18
+ EVENT_FIBER_CANCELED,
19
+ EVENT_FIBER_DONE,
20
+ EVENT_FIBER_ERROR,
21
+ STATE_ACTIVE,
22
+ STATE_CANCELED,
23
+ STATE_DONE,
24
+ STATE_ERROR,
25
+ STATE_NEW
26
+ } from "./api.js";
9
27
  let DEFAULT_ID_GEN = prefixed("fib-", monotonic());
10
- export const setDefaultIDGen = (gen) => (DEFAULT_ID_GEN = gen);
11
- const NO_RESULT = { done: false, value: undefined };
12
- let Fiber = Fiber_1 = class Fiber {
13
- /**
14
- * This fiber's user provided or generated ID.
15
- */
16
- id;
17
- /**
18
- * This fiber's parent.
19
- */
20
- parent;
21
- gen;
22
- idgen;
23
- state = STATE_NEW;
24
- autoTerminate = false;
25
- children = [];
26
- value = undefined;
27
- error;
28
- logger;
29
- user;
30
- _promise;
31
- constructor(gen, opts) {
32
- if (opts) {
33
- this.autoTerminate = !!opts.terminate;
34
- this.logger = opts.logger;
35
- this.parent = opts.parent;
36
- this.user = {
37
- init: opts.init,
38
- deinit: opts.deinit,
39
- catch: opts.catch,
40
- };
41
- if (opts.id) {
42
- this.id = opts.id;
43
- }
44
- else {
45
- this.idgen = opts.idgen || DEFAULT_ID_GEN;
46
- }
47
- }
48
- else {
49
- this.idgen = DEFAULT_ID_GEN;
50
- }
51
- if (this.idgen)
52
- this.id = this.idgen.next();
53
- this.gen = isFunction(gen) ? gen(this) : gen;
54
- }
55
- /**
56
- * Co-routine which blocks whilst this fiber (incl. its children) is active.
57
- * Then return this fiber's value.
58
- */
59
- *[Symbol.iterator]() {
60
- while (this.state <= STATE_ACTIVE && this.next() <= STATE_ACTIVE)
61
- yield;
62
- return this.value;
28
+ const setDefaultIDGen = (gen) => DEFAULT_ID_GEN = gen;
29
+ const NO_RESULT = { done: false, value: void 0 };
30
+ let Fiber = class {
31
+ /**
32
+ * This fiber's user provided or generated ID.
33
+ */
34
+ id;
35
+ /**
36
+ * This fiber's parent.
37
+ */
38
+ parent;
39
+ gen;
40
+ idgen;
41
+ state = STATE_NEW;
42
+ autoTerminate = false;
43
+ children = [];
44
+ value = void 0;
45
+ error;
46
+ logger;
47
+ user;
48
+ _promise;
49
+ constructor(gen, opts) {
50
+ if (opts) {
51
+ this.autoTerminate = !!opts.terminate;
52
+ this.logger = opts.logger;
53
+ this.parent = opts.parent;
54
+ this.user = {
55
+ init: opts.init,
56
+ deinit: opts.deinit,
57
+ catch: opts.catch
58
+ };
59
+ if (opts.id) {
60
+ this.id = opts.id;
61
+ } else {
62
+ this.idgen = opts.idgen || DEFAULT_ID_GEN;
63
+ }
64
+ } else {
65
+ this.idgen = DEFAULT_ID_GEN;
63
66
  }
64
- /**
65
- * Returns a promise which only resolves when the fiber is not active
66
- * anymore. If there was an unhandled error during the fiber execution the
67
- * promise will reject, else if the fiber (incl. children) completed on its
68
- * own or was cancelled, the promise resolves with the fiber's final
69
- * (possibly `undefined`) value.
70
- *
71
- * @remarks
72
- * The promise assumes the fiber either already has been (or will be)
73
- * scheduled & executed via other means. This promise only repeatedly checks
74
- * for any state changes of this fiber (at a configurable
75
- * frequency/interval), but does *NOT* trigger fiber execution!
76
- *
77
- * @param delay
78
- */
79
- promise(delay = 1) {
80
- return (this._promise ||
81
- (this._promise = new Promise((resolve, reject) => {
82
- const timerID = setInterval(() => {
83
- if (this.state > STATE_ACTIVE) {
84
- clearInterval(timerID);
85
- this.state < STATE_ERROR
86
- ? resolve(this.value)
87
- : reject(this.error);
88
- }
89
- }, delay);
90
- })));
91
- }
92
- /**
93
- * Returns this fiber's result value (if any). Only available if the fiber
94
- * completed successfully and produced a value (either by returning a value
95
- * from the fiber's generator or externally via {@link Fiber.done}).
96
- */
97
- deref() {
98
- return this.value;
99
- }
100
- /**
101
- * Returns true if this fiber is still in new or active state (i.e. still
102
- * can be processed).
103
- */
104
- isActive() {
105
- return this.state <= STATE_ACTIVE;
106
- }
107
- /**
108
- * Returns child fiber for given `id`.
109
- *
110
- * @param id
111
- */
112
- childForID(id) {
113
- return this.children.find((f) => f.id === id);
114
- }
115
- /**
116
- * Adds given `body` as child process to this fiber. If not already a
117
- * {@link Fiber} instance, it will be wrapped as such incl. with given
118
- * options. `opts` are only used for this latter case and will inherit this
119
- * (parent) fiber's {@link FiberOpts.logger} and {@link FiberOpts.idgen} as
120
- * defaults. Returns child fiber.
121
- *
122
- * @remarks
123
- * Child fibers are only processed when the parent is processed (e.g. via
124
- * {@link Fiber.run} or via `yield* fiber`). Also see {@link Fiber.join} to
125
- * wait for all child processes to finish.
126
- *
127
- * Non-active child process (i.e. finished, cancelled or errored) are
128
- * automatically removed from the parent. If the child fiber is needed for
129
- * future inspection, the return value of `fork()` should be stored by the
130
- * user. Whilst still active, child fibers can also be looked up via
131
- * {@link Fiber.childForID}.
132
- *
133
- * @example
134
- * ```ts
135
- * fiber(function* (ctx) {
136
- * console.log("main start")
137
- * // create 2 child processes
138
- * ctx.fork(function* () {
139
- * console.log("child1 start");
140
- * yield* wait(500);
141
- * console.log("child1 end");
142
- * });
143
- * // second process will take longer than first
144
- * ctx.fork(function* () {
145
- * console.log("child2 start");
146
- * yield* wait(1000);
147
- * console.log("child2 end");
148
- * });
149
- * // wait for children to complete
150
- * yield* ctx.join();
151
- * console.log("main end")
152
- * }).run();
153
- *
154
- * // main start
155
- * // child1 start
156
- * // child2 start
157
- * // child1 end
158
- * // child2 end
159
- * // main end
160
- * ```
161
- *
162
- * @param f
163
- * @param opts
164
- */
165
- fork(body, opts) {
166
- if (!this.isActive())
167
- illegalState(`fiber (id: ${this.id}) not active`);
168
- let $fiber;
169
- if (body instanceof Fiber_1) {
170
- if (body.parent)
171
- illegalArgs(`fiber id: ${body.id} already has a parent`);
172
- $fiber = body;
173
- }
174
- else {
175
- $fiber = fiber(body, {
176
- parent: this,
177
- logger: this.logger,
178
- idgen: this.idgen,
179
- ...opts,
180
- });
67
+ if (this.idgen)
68
+ this.id = this.idgen.next();
69
+ this.gen = isFunction(gen) ? gen(this) : gen;
70
+ }
71
+ /**
72
+ * Co-routine which blocks whilst this fiber (incl. its children) is active.
73
+ * Then return this fiber's value.
74
+ */
75
+ *[Symbol.iterator]() {
76
+ while (this.state <= STATE_ACTIVE && this.next() <= STATE_ACTIVE)
77
+ yield;
78
+ return this.value;
79
+ }
80
+ /**
81
+ * Returns a promise which only resolves when the fiber is not active
82
+ * anymore. If there was an unhandled error during the fiber execution the
83
+ * promise will reject, else if the fiber (incl. children) completed on its
84
+ * own or was cancelled, the promise resolves with the fiber's final
85
+ * (possibly `undefined`) value.
86
+ *
87
+ * @remarks
88
+ * The promise assumes the fiber either already has been (or will be)
89
+ * scheduled & executed via other means. This promise only repeatedly checks
90
+ * for any state changes of this fiber (at a configurable
91
+ * frequency/interval), but does *NOT* trigger fiber execution!
92
+ *
93
+ * @param delay
94
+ */
95
+ promise(delay = 1) {
96
+ return this._promise || (this._promise = new Promise((resolve, reject) => {
97
+ const timerID = setInterval(() => {
98
+ if (this.state > STATE_ACTIVE) {
99
+ clearInterval(timerID);
100
+ this.state < STATE_ERROR ? resolve(this.value) : reject(this.error);
181
101
  }
182
- this.children.push($fiber);
183
- this.logger?.debug("forking", $fiber.id);
184
- return $fiber;
102
+ }, delay);
103
+ }));
104
+ }
105
+ /**
106
+ * Returns this fiber's result value (if any). Only available if the fiber
107
+ * completed successfully and produced a value (either by returning a value
108
+ * from the fiber's generator or externally via {@link Fiber.done}).
109
+ */
110
+ deref() {
111
+ return this.value;
112
+ }
113
+ /**
114
+ * Returns true if this fiber is still in new or active state (i.e. still
115
+ * can be processed).
116
+ */
117
+ isActive() {
118
+ return this.state <= STATE_ACTIVE;
119
+ }
120
+ /**
121
+ * Returns child fiber for given `id`.
122
+ *
123
+ * @param id
124
+ */
125
+ childForID(id) {
126
+ return this.children.find((f) => f.id === id);
127
+ }
128
+ /**
129
+ * Adds given `body` as child process to this fiber. If not already a
130
+ * {@link Fiber} instance, it will be wrapped as such incl. with given
131
+ * options. `opts` are only used for this latter case and will inherit this
132
+ * (parent) fiber's {@link FiberOpts.logger} and {@link FiberOpts.idgen} as
133
+ * defaults. Returns child fiber.
134
+ *
135
+ * @remarks
136
+ * Child fibers are only processed when the parent is processed (e.g. via
137
+ * {@link Fiber.run} or via `yield* fiber`). Also see {@link Fiber.join} to
138
+ * wait for all child processes to finish.
139
+ *
140
+ * Non-active child process (i.e. finished, cancelled or errored) are
141
+ * automatically removed from the parent. If the child fiber is needed for
142
+ * future inspection, the return value of `fork()` should be stored by the
143
+ * user. Whilst still active, child fibers can also be looked up via
144
+ * {@link Fiber.childForID}.
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * fiber(function* (ctx) {
149
+ * console.log("main start")
150
+ * // create 2 child processes
151
+ * ctx.fork(function* () {
152
+ * console.log("child1 start");
153
+ * yield* wait(500);
154
+ * console.log("child1 end");
155
+ * });
156
+ * // second process will take longer than first
157
+ * ctx.fork(function* () {
158
+ * console.log("child2 start");
159
+ * yield* wait(1000);
160
+ * console.log("child2 end");
161
+ * });
162
+ * // wait for children to complete
163
+ * yield* ctx.join();
164
+ * console.log("main end")
165
+ * }).run();
166
+ *
167
+ * // main start
168
+ * // child1 start
169
+ * // child2 start
170
+ * // child1 end
171
+ * // child2 end
172
+ * // main end
173
+ * ```
174
+ *
175
+ * @param f
176
+ * @param opts
177
+ */
178
+ fork(body, opts) {
179
+ if (!this.isActive())
180
+ illegalState(`fiber (id: ${this.id}) not active`);
181
+ let $fiber;
182
+ if (body instanceof Fiber) {
183
+ if (body.parent)
184
+ illegalArgs(`fiber id: ${body.id} already has a parent`);
185
+ $fiber = body;
186
+ } else {
187
+ $fiber = fiber(body, {
188
+ parent: this,
189
+ logger: this.logger,
190
+ idgen: this.idgen,
191
+ ...opts
192
+ });
185
193
  }
186
- /**
187
- * Calls {@link Fiber.fork} for all given fibers and returns them as array.
188
- *
189
- * @remarks
190
- * Also see {@link Fiber.join} to wait for all child processes to complete.
191
- *
192
- * @param fibers
193
- */
194
- forkAll(...fibers) {
195
- return fibers.map((f) => this.fork(f));
196
- }
197
- /**
198
- * Waits for all child processes to complete/terminate. Use as `yield*
199
- * fiber.join()`.
200
- *
201
- * @remarks
202
- * See {@link Fiber.fork}, {@link Fiber.forkAll}.
203
- *
204
- */
205
- *join() {
206
- this.logger?.debug("waiting for children...");
207
- while (this.children.length)
208
- yield;
209
- }
210
- /**
211
- * Processes a single iteration of this fiber and any of its children. Does
212
- * nothing if the fiber is not active anymore. Returns fiber's state.
213
- *
214
- * @remarks
215
- * New, ininitialized fibers are first initialized via {@link Fiber.init}.
216
- * Likewise, when fibers are terminated (for whatever reason), they will be
217
- * de-initialized via {@link Fiber.deinit}. For all of these cases
218
- * (init/deinit), hooks for user customization are provided via
219
- * {@link FiberOpts.init}, {@link FiberOpts.deinit} and
220
- * {@link FiberOpts.catch}.
221
- */
222
- next() {
223
- switch (this.state) {
224
- case STATE_NEW:
225
- this.init();
226
- // explicit fallthrough
227
- case STATE_ACTIVE:
228
- try {
229
- const { children } = this;
230
- if (children.length) {
231
- for (let i = 0, n = children.length; i < n;) {
232
- const child = children[i];
233
- if (child.state > STATE_ACTIVE ||
234
- child.next() > STATE_ACTIVE) {
235
- children.splice(i, 1);
236
- n--;
237
- }
238
- else
239
- i++;
240
- }
241
- }
242
- else if (this.autoTerminate) {
243
- this.cancel();
244
- break;
245
- }
246
- const res = this.gen ? this.gen.next(this) : NO_RESULT;
247
- if (res.done)
248
- this.done(res.value);
249
- }
250
- catch (e) {
251
- this.catch(e);
252
- }
253
- break;
254
- default:
194
+ this.children.push($fiber);
195
+ this.logger?.debug("forking", $fiber.id);
196
+ return $fiber;
197
+ }
198
+ /**
199
+ * Calls {@link Fiber.fork} for all given fibers and returns them as array.
200
+ *
201
+ * @remarks
202
+ * Also see {@link Fiber.join} to wait for all child processes to complete.
203
+ *
204
+ * @param fibers
205
+ */
206
+ forkAll(...fibers) {
207
+ return fibers.map((f) => this.fork(f));
208
+ }
209
+ /**
210
+ * Waits for all child processes to complete/terminate. Use as `yield*
211
+ * fiber.join()`.
212
+ *
213
+ * @remarks
214
+ * See {@link Fiber.fork}, {@link Fiber.forkAll}.
215
+ *
216
+ */
217
+ *join() {
218
+ this.logger?.debug("waiting for children...");
219
+ while (this.children.length)
220
+ yield;
221
+ }
222
+ /**
223
+ * Processes a single iteration of this fiber and any of its children. Does
224
+ * nothing if the fiber is not active anymore. Returns fiber's state.
225
+ *
226
+ * @remarks
227
+ * New, ininitialized fibers are first initialized via {@link Fiber.init}.
228
+ * Likewise, when fibers are terminated (for whatever reason), they will be
229
+ * de-initialized via {@link Fiber.deinit}. For all of these cases
230
+ * (init/deinit), hooks for user customization are provided via
231
+ * {@link FiberOpts.init}, {@link FiberOpts.deinit} and
232
+ * {@link FiberOpts.catch}.
233
+ */
234
+ next() {
235
+ switch (this.state) {
236
+ case STATE_NEW:
237
+ this.init();
238
+ case STATE_ACTIVE:
239
+ try {
240
+ const { children } = this;
241
+ if (children.length) {
242
+ for (let i = 0, n = children.length; i < n; ) {
243
+ const child = children[i];
244
+ if (child.state > STATE_ACTIVE || child.next() > STATE_ACTIVE) {
245
+ children.splice(i, 1);
246
+ n--;
247
+ } else
248
+ i++;
249
+ }
250
+ } else if (this.autoTerminate) {
251
+ this.cancel();
252
+ break;
253
+ }
254
+ const res = this.gen ? this.gen.next(this) : NO_RESULT;
255
+ if (res.done)
256
+ this.done(res.value);
257
+ } catch (e) {
258
+ this.catch(e);
255
259
  }
256
- return this.state;
257
- }
258
- init() {
259
- this.logger?.debug("init", this.id);
260
- this.user?.init?.(this);
261
- this.state = STATE_ACTIVE;
262
- }
263
- deinit() {
264
- this.logger?.debug("deinit", this.id);
265
- this.user?.deinit?.(this);
266
- this.children.length = 0;
267
- this.gen = null;
268
- }
269
- /**
270
- * Cancels further processing of this fiber and its children (if any). Calls
271
- * {@link Fiber.deinit} and emits {@link EVENT_FIBER_CANCELED} event.
272
- *
273
- * @remarks
274
- * Function is a no-op if the fiber is not active anymore.
275
- */
276
- cancel() {
277
- if (!this.isActive())
278
- return;
279
- this.logger?.debug("cancel", this.id);
280
- for (let child of this.children)
281
- child.cancel();
282
- this.deinit();
283
- this.state = STATE_CANCELED;
284
- this.idgen?.free(this.id);
285
- this.notify({ id: EVENT_FIBER_CANCELED, target: this });
286
- }
287
- /**
288
- * Stops further processing of this fiber and its children (if any) and sets
289
- * this fiber's value to given `value`. Calls {@link Fiber.deinit} and emits
290
- * {@link EVENT_FIBER_DONE} event.
291
- *
292
- * @remarks
293
- * Function is a no-op if the fiber is not active anymore.
294
- *
295
- * @param value
296
- */
297
- done(value) {
298
- if (!this.isActive())
299
- return;
300
- this.logger?.debug("done", this.id, value);
301
- this.value = value;
302
- for (let child of this.children)
303
- child.done();
304
- this.deinit();
305
- this.state = STATE_DONE;
306
- this.idgen?.free(this.id);
307
- this.notify({ id: EVENT_FIBER_DONE, target: this, value });
308
- }
309
- /**
310
- * Stops further processing of this fiber, cancels all child processes (if
311
- * any) and sets this fiber's {@link Fiber.error} value to given `error`.
312
- * Calls {@link Fiber.deinit} and emits {@link EVENT_FIBER_ERROR} event.
313
- *
314
- * @remarks
315
- * Function is a no-op if the fiber already is in an error state. See
316
- * {@link FiberOpts.catch} for details about user provided error handling
317
- * and interception logic.
318
- *
319
- * @param err
320
- */
321
- catch(err) {
322
- if (this.state >= STATE_ERROR || this.user?.catch?.(this, err))
323
- return;
324
- this.logger
325
- ? this.logger.severe(`error ${this.id}:`, err)
326
- : console.warn(`error ${this.id}:`, err);
327
- for (let child of this.children)
328
- child.cancel();
329
- this.state = STATE_ERROR;
330
- this.error = err;
331
- this.deinit();
332
- this.idgen?.free(this.id);
333
- this.notify({ id: EVENT_FIBER_ERROR, target: this, value: err });
334
- }
335
- // @ts-ignore mixin
336
- // prettier-ignore
337
- addListener(id, fn, scope) { }
338
- // @ts-ignore mixin
339
- // prettier-ignore
340
- removeListener(id, fn, scope) { }
341
- // @ts-ignore mixin
342
- notify(event) { }
343
- /**
344
- * Calls {@link Fiber.runWith} using default loop handlers.
345
- *
346
- * @remarks
347
- * Current default handlers:
348
- *
349
- * - `requestAnimationFrame()` in browsers
350
- * - `setImmediate()` in NodeJs
351
- * - `setTimeout(fn, 1)` otherwise
352
- */
353
- run() {
354
- return this.runWith(typeof requestAnimationFrame === "function"
355
- ? requestAnimationFrame
356
- : typeof setImmediate === "function"
357
- ? setImmediate
358
- : (fn) => setTimeout(fn, 1));
359
- }
360
- /**
361
- * Starts fiber execution using the provided higher-order loop/interval
362
- * `handler` (e.g. see {@link Fiber.run}).
363
- *
364
- * @remarks
365
- * That given `handler` is used to repeatedly schedule the next execution of
366
- * {@link Fiber.next} (indirectly, via a zero-arg helper function passed to
367
- * the `handler`).
368
- *
369
- * Note: **Do not use `setInterval` instead of `setTimeout`**. The given
370
- * `handler` must only manage a single execution step, not multiple.
371
- *
372
- * @example
373
- * ```ts
374
- * // start with custom higher frequency handler
375
- * fiber(function*() {
376
- * while(true) {
377
- * console.log("hello");
378
- * yield;
379
- * }
380
- * }).runWith(setImmediate);
381
- * ```
382
- *
383
- * @param handler
384
- */
385
- runWith(handler) {
386
- this.logger?.debug(`running ${this.id}...`);
387
- const loop = () => {
388
- if (this.state <= STATE_ACTIVE && this.next() <= STATE_ACTIVE)
389
- handler(loop);
390
- };
391
- loop();
392
- return this;
260
+ break;
261
+ default:
393
262
  }
263
+ return this.state;
264
+ }
265
+ init() {
266
+ this.logger?.debug("init", this.id);
267
+ this.user?.init?.(this);
268
+ this.state = STATE_ACTIVE;
269
+ }
270
+ deinit() {
271
+ this.logger?.debug("deinit", this.id);
272
+ this.user?.deinit?.(this);
273
+ this.children.length = 0;
274
+ this.gen = null;
275
+ }
276
+ /**
277
+ * Cancels further processing of this fiber and its children (if any). Calls
278
+ * {@link Fiber.deinit} and emits {@link EVENT_FIBER_CANCELED} event.
279
+ *
280
+ * @remarks
281
+ * Function is a no-op if the fiber is not active anymore.
282
+ */
283
+ cancel() {
284
+ if (!this.isActive())
285
+ return;
286
+ this.logger?.debug("cancel", this.id);
287
+ for (let child of this.children)
288
+ child.cancel();
289
+ this.deinit();
290
+ this.state = STATE_CANCELED;
291
+ this.idgen?.free(this.id);
292
+ this.notify({ id: EVENT_FIBER_CANCELED, target: this });
293
+ }
294
+ /**
295
+ * Stops further processing of this fiber and its children (if any) and sets
296
+ * this fiber's value to given `value`. Calls {@link Fiber.deinit} and emits
297
+ * {@link EVENT_FIBER_DONE} event.
298
+ *
299
+ * @remarks
300
+ * Function is a no-op if the fiber is not active anymore.
301
+ *
302
+ * @param value
303
+ */
304
+ done(value) {
305
+ if (!this.isActive())
306
+ return;
307
+ this.logger?.debug("done", this.id, value);
308
+ this.value = value;
309
+ for (let child of this.children)
310
+ child.done();
311
+ this.deinit();
312
+ this.state = STATE_DONE;
313
+ this.idgen?.free(this.id);
314
+ this.notify({ id: EVENT_FIBER_DONE, target: this, value });
315
+ }
316
+ /**
317
+ * Stops further processing of this fiber, cancels all child processes (if
318
+ * any) and sets this fiber's {@link Fiber.error} value to given `error`.
319
+ * Calls {@link Fiber.deinit} and emits {@link EVENT_FIBER_ERROR} event.
320
+ *
321
+ * @remarks
322
+ * Function is a no-op if the fiber already is in an error state. See
323
+ * {@link FiberOpts.catch} for details about user provided error handling
324
+ * and interception logic.
325
+ *
326
+ * @param err
327
+ */
328
+ catch(err) {
329
+ if (this.state >= STATE_ERROR || this.user?.catch?.(this, err))
330
+ return;
331
+ this.logger ? this.logger.severe(`error ${this.id}:`, err) : console.warn(`error ${this.id}:`, err);
332
+ for (let child of this.children)
333
+ child.cancel();
334
+ this.state = STATE_ERROR;
335
+ this.error = err;
336
+ this.deinit();
337
+ this.idgen?.free(this.id);
338
+ this.notify({ id: EVENT_FIBER_ERROR, target: this, value: err });
339
+ }
340
+ // @ts-ignore mixin
341
+ // prettier-ignore
342
+ addListener(id, fn, scope) {
343
+ }
344
+ // @ts-ignore mixin
345
+ // prettier-ignore
346
+ removeListener(id, fn, scope) {
347
+ }
348
+ // @ts-ignore mixin
349
+ notify(event) {
350
+ }
351
+ /**
352
+ * Calls {@link Fiber.runWith} using default loop handlers.
353
+ *
354
+ * @remarks
355
+ * Current default handlers:
356
+ *
357
+ * - `requestAnimationFrame()` in browsers
358
+ * - `setImmediate()` in NodeJs
359
+ * - `setTimeout(fn, 1)` otherwise
360
+ */
361
+ run() {
362
+ return this.runWith(
363
+ typeof requestAnimationFrame === "function" ? requestAnimationFrame : typeof setImmediate === "function" ? setImmediate : (fn) => setTimeout(fn, 1)
364
+ );
365
+ }
366
+ /**
367
+ * Starts fiber execution using the provided higher-order loop/interval
368
+ * `handler` (e.g. see {@link Fiber.run}).
369
+ *
370
+ * @remarks
371
+ * That given `handler` is used to repeatedly schedule the next execution of
372
+ * {@link Fiber.next} (indirectly, via a zero-arg helper function passed to
373
+ * the `handler`).
374
+ *
375
+ * Note: **Do not use `setInterval` instead of `setTimeout`**. The given
376
+ * `handler` must only manage a single execution step, not multiple.
377
+ *
378
+ * @example
379
+ * ```ts
380
+ * // start with custom higher frequency handler
381
+ * fiber(function*() {
382
+ * while(true) {
383
+ * console.log("hello");
384
+ * yield;
385
+ * }
386
+ * }).runWith(setImmediate);
387
+ * ```
388
+ *
389
+ * @param handler
390
+ */
391
+ runWith(handler) {
392
+ this.logger?.debug(`running ${this.id}...`);
393
+ const loop = () => {
394
+ if (this.state <= STATE_ACTIVE && this.next() <= STATE_ACTIVE)
395
+ handler(loop);
396
+ };
397
+ loop();
398
+ return this;
399
+ }
394
400
  };
395
- Fiber = Fiber_1 = __decorate([
396
- INotifyMixin
401
+ Fiber = __decorateClass([
402
+ INotifyMixin
397
403
  ], Fiber);
398
- export { Fiber };
399
- /**
400
- * Functional syntax sugar for {@link Fiber} constructor. The `opts` are only
401
- * used if given a generator or {@link FiberFactory}.
402
- *
403
- * @param fiber
404
- * @param opts
405
- */
406
- export const fiber = (fiber, opts) => (fiber != null && fiber instanceof Fiber ? fiber : new Fiber(fiber, opts));
404
+ const fiber = (fiber2, opts) => fiber2 != null && fiber2 instanceof Fiber ? fiber2 : new Fiber(fiber2, opts);
405
+ export {
406
+ Fiber,
407
+ fiber,
408
+ setDefaultIDGen
409
+ };