| /** |
| * @license |
| * Copyright 2023 The Emscripten Authors |
| * SPDX-License-Identifier: MIT |
| */ |
| |
| addToLibrary({ |
| $promiseMap__deps: ['$HandleAllocator'], |
| $promiseMap: "new HandleAllocator();", |
| |
| $getPromise__deps: ['$promiseMap'], |
| $getPromise: (id) => promiseMap.get(id).promise, |
| |
| $makePromise__deps: ['$promiseMap'], |
| $makePromise: () => { |
| var promiseInfo = {}; |
| promiseInfo.promise = new Promise((resolve, reject) => { |
| promiseInfo.reject = reject; |
| promiseInfo.resolve = resolve; |
| }); |
| promiseInfo.id = promiseMap.allocate(promiseInfo); |
| #if RUNTIME_DEBUG |
| dbg(`makePromise: ${promiseInfo.id}`); |
| #endif |
| return promiseInfo; |
| }, |
| |
| $idsToPromises__deps: ['$getPromise'], |
| $idsToPromises: (idBuf, size) => { |
| var promises = []; |
| for (var i = 0; i < size; i++) { |
| var id = {{{ makeGetValue('idBuf', `i*${POINTER_SIZE}`, 'i32') }}}; |
| promises[i] = getPromise(id); |
| } |
| return promises; |
| }, |
| |
| emscripten_promise_create__deps: ['$makePromise'], |
| emscripten_promise_create: () => makePromise().id, |
| |
| emscripten_promise_destroy__deps: ['$promiseMap'], |
| emscripten_promise_destroy: (id) => { |
| #if RUNTIME_DEBUG |
| dbg(`emscripten_promise_destroy: ${id}`); |
| #endif |
| promiseMap.free(id); |
| }, |
| |
| emscripten_promise_resolve__deps: ['$promiseMap', |
| '$getPromise', |
| 'emscripten_promise_destroy'], |
| emscripten_promise_resolve: (id, result, value) => { |
| #if RUNTIME_DEBUG |
| dbg(`emscripten_promise_resolve: ${id}`); |
| #endif |
| var info = promiseMap.get(id); |
| switch (result) { |
| case {{{ cDefs.EM_PROMISE_FULFILL }}}: |
| info.resolve(value); |
| return; |
| case {{{ cDefs.EM_PROMISE_MATCH }}}: |
| info.resolve(getPromise(value)); |
| return; |
| case {{{ cDefs.EM_PROMISE_MATCH_RELEASE }}}: |
| info.resolve(getPromise(value)); |
| _emscripten_promise_destroy(value); |
| return; |
| case {{{ cDefs.EM_PROMISE_REJECT }}}: |
| info.reject(value); |
| return; |
| } |
| #if ASSERTIONS |
| abort("unexpected promise callback result " + result); |
| #endif |
| }, |
| |
| $makePromiseCallback__deps: ['$getPromise', |
| '$POINTER_SIZE', |
| 'emscripten_promise_destroy', |
| '$stackAlloc', |
| '$stackRestore', |
| '$stackSave'], |
| $makePromiseCallback: (callback, userData) => { |
| return (value) => { |
| #if RUNTIME_DEBUG |
| dbg(`emscripten promise callback: ${value}`); |
| #endif |
| {{{ runtimeKeepalivePop() }}}; |
| var stack = stackSave(); |
| // Allocate space for the result value and initialize it to NULL. |
| var resultPtr = stackAlloc(POINTER_SIZE); |
| {{{ makeSetValue('resultPtr', 0, '0', '*') }}}; |
| try { |
| var result = |
| {{{ makeDynCall('ippp', 'callback') }}}(resultPtr, userData, value); |
| var resultVal = {{{ makeGetValue('resultPtr', 0, '*') }}}; |
| } catch (e) { |
| // If the thrown value is potentially a valid pointer, use it as the |
| // rejection reason. Otherwise use a null pointer as the reason. If we |
| // allow arbitrary objects to be thrown here, we will get a TypeError in |
| // MEMORY64 mode when they are later converted to void* rejection |
| // values. |
| #if MEMORY64 |
| if (typeof e != 'bigint') { |
| throw 0n; |
| } |
| #else |
| if (typeof e != 'number') { |
| throw 0; |
| } |
| #endif |
| throw e; |
| } finally { |
| // Thrown errors will reject the promise, but at least we will restore |
| // the stack first. |
| stackRestore(stack); |
| } |
| switch (result) { |
| case {{{ cDefs.EM_PROMISE_FULFILL }}}: |
| return resultVal; |
| case {{{ cDefs.EM_PROMISE_MATCH }}}: |
| return getPromise(resultVal); |
| case {{{ cDefs.EM_PROMISE_MATCH_RELEASE }}}: |
| var ret = getPromise(resultVal); |
| _emscripten_promise_destroy(resultVal); |
| return ret; |
| case {{{ cDefs.EM_PROMISE_REJECT }}}: |
| throw resultVal; |
| } |
| #if ASSERTIONS |
| abort("unexpected promise callback result " + result); |
| #endif |
| }; |
| }, |
| |
| emscripten_promise_then__deps: ['$promiseMap', |
| '$getPromise', |
| '$makePromiseCallback'], |
| emscripten_promise_then: (id, onFulfilled, onRejected, userData) => { |
| #if RUNTIME_DEBUG |
| dbg(`emscripten_promise_then: ${id}`); |
| #endif |
| {{{ runtimeKeepalivePush() }}}; |
| var promise = getPromise(id); |
| var newId = promiseMap.allocate({ |
| promise: promise.then(makePromiseCallback(onFulfilled, userData), |
| makePromiseCallback(onRejected, userData)) |
| }); |
| #if RUNTIME_DEBUG |
| dbg(`emscripten_promise_then: -> ${newId}`); |
| #endif |
| return newId; |
| }, |
| |
| emscripten_promise_all__deps: ['$promiseMap', '$idsToPromises'], |
| emscripten_promise_all: (idBuf, resultBuf, size) => { |
| var promises = idsToPromises(idBuf, size); |
| #if RUNTIME_DEBUG |
| dbg(`emscripten_promise_all: ${promises}`); |
| #endif |
| var id = promiseMap.allocate({ |
| promise: Promise.all(promises).then((results) => { |
| if (resultBuf) { |
| for (var i = 0; i < size; i++) { |
| var result = results[i]; |
| {{{ makeSetValue('resultBuf', `i*${POINTER_SIZE}`, 'result', '*') }}}; |
| } |
| } |
| return resultBuf; |
| }) |
| }); |
| #if RUNTIME_DEBUG |
| dbg(`create: ${id}`); |
| #endif |
| return id; |
| }, |
| |
| $setPromiseResult__internal: true, |
| $setPromiseResult: (ptr, fulfill, value) => { |
| #if ASSERTIONS |
| assert(typeof value == 'undefined' || typeof value === 'number', `native promises can only handle numeric results (${value} ${typeof value})`); |
| #endif |
| var result = fulfill ? {{{ cDefs.EM_PROMISE_FULFILL }}} : {{{ cDefs.EM_PROMISE_REJECT }}} |
| {{{ makeSetValue('ptr', C_STRUCTS.em_settled_result_t.result, 'result', 'i32') }}}; |
| {{{ makeSetValue('ptr', C_STRUCTS.em_settled_result_t.value, 'value', '*') }}}; |
| }, |
| |
| emscripten_promise_all_settled__deps: ['$promiseMap', '$idsToPromises', '$setPromiseResult'], |
| emscripten_promise_all_settled: (idBuf, resultBuf, size) => { |
| var promises = idsToPromises(idBuf, size); |
| #if RUNTIME_DEBUG |
| dbg(`emscripten_promise_all_settled: ${promises}`); |
| #endif |
| var id = promiseMap.allocate({ |
| promise: Promise.allSettled(promises).then((results) => { |
| if (resultBuf) { |
| var offset = resultBuf; |
| for (var i = 0; i < size; i++, offset += {{{ C_STRUCTS.em_settled_result_t.__size__ }}}) { |
| if (results[i].status === 'fulfilled') { |
| setPromiseResult(offset, true, results[i].value); |
| } else { |
| setPromiseResult(offset, false, results[i].reason); |
| } |
| } |
| } |
| return resultBuf; |
| }) |
| }); |
| #if RUNTIME_DEBUG |
| dbg(`create: ${id}`); |
| #endif |
| return id; |
| }, |
| |
| emscripten_promise_any__deps: [ |
| '$promiseMap', '$idsToPromises', |
| #if !SUPPORTS_PROMISE_ANY && !INCLUDE_FULL_LIBRARY |
| () => error("emscripten_promise_any used, but Promise.any is not supported by the current runtime configuration (run with EMCC_DEBUG=1 in the env for more details)"), |
| #endif |
| ], |
| emscripten_promise_any: (idBuf, errorBuf, size) => { |
| var promises = idsToPromises(idBuf, size); |
| #if RUNTIME_DEBUG |
| dbg(`emscripten_promise_any: ${promises}`); |
| #endif |
| #if ASSERTIONS |
| assert(typeof Promise.any != 'undefined', "Promise.any does not exist"); |
| #endif |
| var id = promiseMap.allocate({ |
| promise: Promise.any(promises).catch((err) => { |
| if (errorBuf) { |
| for (var i = 0; i < size; i++) { |
| {{{ makeSetValue('errorBuf', `i*${POINTER_SIZE}`, 'err.errors[i]', '*') }}}; |
| } |
| } |
| throw errorBuf; |
| }) |
| }); |
| #if RUNTIME_DEBUG |
| dbg(`create: ${id}`); |
| #endif |
| return id; |
| }, |
| |
| emscripten_promise_race__deps: ['$promiseMap', '$idsToPromises'], |
| emscripten_promise_race: (idBuf, size) => { |
| var promises = idsToPromises(idBuf, size); |
| #if RUNTIME_DEBUG |
| dbg(`emscripten_promise_race: ${promises}`); |
| #endif |
| var id = promiseMap.allocate({ |
| promise: Promise.race(promises) |
| }); |
| #if RUNTIME_DEBUG |
| dbg(`create: ${id}`); |
| #endif |
| return id; |
| }, |
| |
| emscripten_promise_await__async: true, |
| #if ASYNCIFY |
| emscripten_promise_await__deps: ['$getPromise', '$setPromiseResult'], |
| #endif |
| emscripten_promise_await: (returnValuePtr, id) => { |
| #if ASYNCIFY |
| #if RUNTIME_DEBUG |
| dbg(`emscripten_promise_await: ${id}`); |
| #endif |
| return Asyncify.handleAsync(() => getPromise(id).then( |
| value => setPromiseResult(returnValuePtr, true, value), |
| error => setPromiseResult(returnValuePtr, false, error) |
| )); |
| #else |
| abort('emscripten_promise_await is only available with ASYNCIFY'); |
| #endif |
| }, |
| }); |