-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlib.ts
52 lines (43 loc) · 1.49 KB
/
lib.ts
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
// We need any, this is too generic.
// deno-lint-ignore-file no-explicit-any
// Make a symbol to mark non-computed values, so it can't clash
// with whatever the user returns
const NOTHING = Symbol("Nothing");
// State is module-level, limitations not clear.
const values: any[] = [NOTHING];
let currentValue = 0;
class Effect<T> {
constructor(public readonly thunk: () => T | Promise<T>) {}
}
// TODO: implement an API similar to Promise.all to support parallel effects
export function perform<T>(thunk: () => T | Promise<T>): T {
const val = values[currentValue];
if (val !== NOTHING) {
currentValue++;
return val;
} else {
throw new Effect(thunk);
}
}
type AnyFunction = (...args: any[]) => any;
type Promisify<Fun extends AnyFunction> = (...args: Parameters<Fun>) => Promise<ReturnType<Fun>>;
export function wrap<T extends AnyFunction>(f: T): Promisify<T> {
const wrappedFunction: Promisify<T> = async (...args) => {
// Keep trying to call the wrapped function
// Once every effect is performed, it'll return.
for (;;) {
try {
return f(...args);
} catch (err) {
if (err instanceof Effect) {
values[currentValue] = await err.thunk();
values[currentValue + 1] = NOTHING;
currentValue = 0;
} else {
throw err;
}
}
}
};
return wrappedFunction;
}