diff options
author | Leo Kettmeir <crowlkats@toaxl.com> | 2023-07-02 19:30:05 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-02 19:30:05 +0200 |
commit | 805497a9a50c3219f64f481feb72271b2fcd6790 (patch) | |
tree | 5ed05d8a8f15fa8e3305cf9514c30226ec3e5e94 /ext/web/06_streams.js | |
parent | 17ddf2f97c58db0b6825809a8bc325f0bda65b1b (diff) |
feat: ReadableStream.from (#19446)
Closes #19417
Diffstat (limited to 'ext/web/06_streams.js')
-rw-r--r-- | ext/web/06_streams.js | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/ext/web/06_streams.js b/ext/web/06_streams.js index 21207c372..beab2ec12 100644 --- a/ext/web/06_streams.js +++ b/ext/web/06_streams.js @@ -62,6 +62,7 @@ const { // SharedArrayBufferPrototype, Symbol, SymbolAsyncIterator, + SymbolIterator, SymbolFor, TypeError, TypedArrayPrototypeGetBuffer, @@ -4780,6 +4781,30 @@ function initializeCountSizeFunction(globalObject) { WeakMapPrototypeSet(countSizeFunctionWeakMap, globalObject, size); } +async function* createAsyncFromSyncIterator(syncIterator) { + // deno-lint-ignore prefer-primordials + yield* syncIterator; +} + +// Ref: https://tc39.es/ecma262/#sec-getiterator +function getIterator(obj, async = false) { + if (async) { + if (obj[SymbolAsyncIterator] === undefined) { + if (obj[SymbolIterator] === undefined) { + throw new TypeError("No iterator found"); + } + return createAsyncFromSyncIterator(obj[SymbolIterator]()); + } else { + return obj[SymbolAsyncIterator](); + } + } else { + if (obj[SymbolIterator] === undefined) { + throw new TypeError("No iterator found"); + } + return obj[SymbolIterator](); + } +} + const _resourceBacking = Symbol("[[resourceBacking]]"); // This distinction exists to prevent unrefable streams being used in // regular fast streams that are unaware of refability @@ -4863,6 +4888,43 @@ class ReadableStream { } } + static from(asyncIterable) { + webidl.requiredArguments( + arguments.length, + 1, + "Failed to call 'ReadableStream.from'", + ); + asyncIterable = webidl.converters.any(asyncIterable); + + const iterator = getIterator(asyncIterable, true); + + const stream = createReadableStream(() => undefined, async () => { + // deno-lint-ignore prefer-primordials + const res = await iterator.next(); + if (typeof res !== "object") { + throw new TypeError("iterator.next value is not an object"); + } + if (res.done) { + readableStreamDefaultControllerClose(stream[_controller]); + } else { + readableStreamDefaultControllerEnqueue(stream[_controller], res.value); + } + }, async (reason) => { + if (typeof iterator.return === "undefined") { + return undefined; + } else { + // deno-lint-ignore prefer-primordials + const res = await iterator.return(reason); + if (typeof res !== "object") { + throw new TypeError("iterator.return value is not an object"); + } else { + return undefined; + } + } + }, 0); + return stream; + } + /** @returns {boolean} */ get locked() { webidl.assertBranded(this, ReadableStreamPrototype); |