|
export async function* eventToGenerator<YieldType, ReturnType>( |
|
cb: ( |
|
yieldCallback: (y: YieldType) => void, |
|
returnCallback: (r: ReturnType) => void, |
|
rejectCallack: (reason: unknown) => void |
|
) => unknown |
|
): AsyncGenerator<YieldType, ReturnType> { |
|
const promises: Array<{ |
|
p: Promise<{ done: true; value: ReturnType } | { done: false; value: YieldType }>; |
|
resolve: (value: { done: true; value: ReturnType } | { done: false; value: YieldType }) => void; |
|
reject: (reason?: unknown) => void; |
|
}> = []; |
|
|
|
function addPromise() { |
|
let resolve: (value: { done: true; value: ReturnType } | { done: false; value: YieldType }) => void; |
|
let reject: (reason?: unknown) => void; |
|
const p = new Promise<{ done: true; value: ReturnType } | { done: false; value: YieldType }>((res, rej) => { |
|
resolve = res; |
|
reject = rej; |
|
}); |
|
|
|
promises.push({ p, resolve, reject }); |
|
} |
|
|
|
addPromise(); |
|
|
|
const callbackRes = Promise.resolve() |
|
.then(() => |
|
cb( |
|
(y) => { |
|
addPromise(); |
|
promises.at(-2)?.resolve({ done: false, value: y }); |
|
}, |
|
(r) => { |
|
addPromise(); |
|
promises.at(-2)?.resolve({ done: true, value: r }); |
|
}, |
|
(err) => promises.shift()?.reject(err) |
|
) |
|
) |
|
.catch((err) => promises.shift()?.reject(err)); |
|
|
|
while (1) { |
|
const p = promises[0]; |
|
if (!p) { |
|
throw new Error("Logic error in eventGenerator, promises should never be empty"); |
|
} |
|
const result = await p.p; |
|
promises.shift(); |
|
if (result.done) { |
|
await callbackRes; |
|
|
|
|
|
|
|
|
|
|
|
return result.value; |
|
} |
|
yield result.value; |
|
} |
|
|
|
|
|
throw new Error("Unreachable"); |
|
} |
|
|