import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten"; import { newDeferred } from "../util"; import { call, instanceOf } from "../vmutil"; export default function unmarshalPromise( ctx: QuickJSContext, handle: QuickJSHandle, /** marshal returns handle and boolean indicates that the handle should be disposed after use */ marshal: (value: unknown) => [QuickJSHandle, boolean], preUnmarshal: (target: T, handle: QuickJSHandle) => T | undefined, ): Promise | undefined { if (!isPromiseHandle(ctx, handle)) return; const deferred = newDeferred(); const [resHandle, resShouldBeDisposed] = marshal(deferred.resolve); const [rejHandle, rejShouldBeDisposed] = marshal(deferred.reject); call(ctx, "(p, res, rej) => { p.then(res, rej); }", undefined, handle, resHandle, rejHandle); if (resShouldBeDisposed) resHandle.dispose(); if (rejShouldBeDisposed) rejHandle.dispose(); return preUnmarshal(deferred.promise, handle) ?? deferred.promise; } function isPromiseHandle(ctx: QuickJSContext, handle: QuickJSHandle): boolean { if (!handle.owner) return false; return ctx.unwrapResult(ctx.evalCode("Promise")).consume(promise => { if (!handle.owner) return false; return instanceOf(ctx, handle, promise); }); }