-
Notifications
You must be signed in to change notification settings - Fork 19
/
fiber.mjs
81 lines (63 loc) · 1.68 KB
/
fiber.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// Optional generator-based coroutines for Posterus.
/* eslint-disable no-invalid-this */
import * as p from './posterus.mjs'
export class Fiber extends p.Task {
constructor(iter) {
valid(iter, isIter)
super()
this.t = iter
}
done(err, val) {
try {
const next = err ? this.t.throw(err) : this.t.next(val)
err = undefined
val = maybeFromIter(next.value)
if (next.done) this.done = super.done
}
catch (err) {
this.d = false
this.done = super.done
return this.done(err)
}
if (p.isTask(val)) return super.done(err, val)
return this.done(err, val)
}
}
export function fiber(fun) {
valid(fun, isGen)
return fromGen.bind(fun)
}
export function fiberAsync(fun) {
valid(fun, isGen)
return fromGenAsync.bind(fun)
}
export function fromIter(iter) {
return new Fiber(iter).done()
}
export function fromIterAsync(iter) {
const fib = new Fiber(iter)
p.async.push(fib)
return fib
}
function fromGen() {
return fromIter(this(...arguments))
}
function fromGenAsync() {
return fromIterAsync(this(...arguments))
}
function isIter(val) {
return (
isObj(val) &&
isFun(val.next) &&
isFun(val.return) &&
isFun(val.throw)
)
}
function maybeFromIter(val) {return isIter(val) ? fromIter(val) : val}
const GeneratorFunction = (function* () {}).constructor // eslint-disable-line func-names
function isGen(val) {return isFun(val) && val.constructor === GeneratorFunction}
function isFun(val) {return typeof val === 'function'}
function isObj(val) {return val != null && typeof val === 'object'}
function valid(val, test) {
if (!test(val)) throw Error(`expected ${val} to satisfy test ${test.name}`)
}