diff options
Diffstat (limited to 'src/bun.js/builtins/js')
23 files changed, 0 insertions, 8146 deletions
diff --git a/src/bun.js/builtins/js/BundlerPlugin.js b/src/bun.js/builtins/js/BundlerPlugin.js deleted file mode 100644 index 344f570d0..000000000 --- a/src/bun.js/builtins/js/BundlerPlugin.js +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Copyright (C) 2023 Codeblog Corp. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// This API expects 4 functions: -// - onLoadAsync -// - onResolveAsync -// - addError -// - addFilter -// -// It should be generic enough to reuse for Bun.plugin() eventually, too. - -function runOnResolvePlugins( - specifier, - inputNamespace, - importer, - internalID, - kindId -) { - "use strict"; - - // Must be kept in sync with ImportRecord.label - const kind = [ - "entry-point", - "import-statement", - "require-call", - "dynamic-import", - "require-resolve", - "import-rule", - "url-token", - "internal", - ][kindId]; - - var promiseResult = (async (inputPath, inputNamespace, importer, kind) => { - var {onResolve, onLoad} = this; - var results = onResolve.@get(inputNamespace); - if (!results) { - this.onResolveAsync(internalID, null, null, null); - return null; - } - - for (let [filter, callback] of results) { - if (filter.test(inputPath)) { - var result = callback({ - path: inputPath, - importer, - namespace: inputNamespace, - // resolveDir - kind, - // pluginData - }); - - while ( - result && - @isPromise(result) && - (@getPromiseInternalField(result, @promiseFieldFlags) & - @promiseStateMask) === - @promiseStateFulfilled - ) { - result = @getPromiseInternalField( - result, - @promiseFieldReactionsOrResult - ); - } - - if (result && @isPromise(result)) { - result = await result; - } - - if (!result || !@isObject(result)) { - continue; - } - - - var { - path, - namespace: userNamespace = inputNamespace, - external, - } = result; - if ( - !(typeof path === "string") || - !(typeof userNamespace === "string") - ) { - @throwTypeError( - "onResolve plugins must return an object with a string 'path' and string 'loader' field" - ); - } - - if (!path) { - continue; - } - - if (!userNamespace) { - userNamespace = inputNamespace; - } - if (typeof external !== "boolean" && !@isUndefinedOrNull(external)) { - @throwTypeError( - 'onResolve plugins "external" field must be boolean or unspecified' - ); - } - - - if (!external) { - if (userNamespace === "file") { - // TODO: Windows - - if (path[0] !== "/" || path.includes("..")) { - @throwTypeError( - 'onResolve plugin "path" must be absolute when the namespace is "file"' - ); - } - } - if (userNamespace === "dataurl") { - if (!path.startsWith("data:")) { - @throwTypeError( - 'onResolve plugin "path" must start with "data:" when the namespace is "dataurl"' - ); - } - } - - if (userNamespace && userNamespace !== "file" && (!onLoad || !onLoad.@has(userNamespace))) { - @throwTypeError( - `Expected onLoad plugin for namespace ${@jsonStringify(userNamespace, " ")} to exist` - ); - } - - } - this.onResolveAsync(internalID, path, userNamespace, external); - return null; - } - } - - this.onResolveAsync(internalID, null, null, null); - return null; - })(specifier, inputNamespace, importer, kind); - - while ( - promiseResult && - @isPromise(promiseResult) && - (@getPromiseInternalField(promiseResult, @promiseFieldFlags) & - @promiseStateMask) === - @promiseStateFulfilled - ) { - promiseResult = @getPromiseInternalField( - promiseResult, - @promiseFieldReactionsOrResult - ); - } - - if (promiseResult && @isPromise(promiseResult)) { - promiseResult.then( - () => {}, - (e) => { - this.addError(internalID, e, 0); - } - ); - } -} - -function runSetupFunction(setup, config) { - "use strict"; - var onLoadPlugins = new Map(), - onResolvePlugins = new Map(); - - function validate(filterObject, callback, map) { - if (!filterObject || !@isObject(filterObject)) { - @throwTypeError('Expected an object with "filter" RegExp'); - } - - if (!callback || !@isCallable(callback)) { - @throwTypeError("callback must be a function"); - } - - var { filter, namespace = "file" } = filterObject; - - if (!filter) { - @throwTypeError('Expected an object with "filter" RegExp'); - } - - if (!@isRegExpObject(filter)) { - @throwTypeError("filter must be a RegExp"); - } - - if (namespace && !(typeof namespace === "string")) { - @throwTypeError("namespace must be a string"); - } - - if ((namespace?.length ?? 0) === 0) { - namespace = "file"; - } - - if (!/^([/@a-zA-Z0-9_\\-]+)$/.test(namespace)) { - @throwTypeError("namespace can only contain @a-zA-Z0-9_\\-"); - } - - var callbacks = map.@get(namespace); - - if (!callbacks) { - map.@set(namespace, [[filter, callback]]); - } else { - @arrayPush(callbacks, [filter, callback]); - } - } - - function onLoad(filterObject, callback) { - validate(filterObject, callback, onLoadPlugins); - } - - function onResolve(filterObject, callback) { - validate(filterObject, callback, onResolvePlugins); - } - - function onStart(callback) { - // builtin generator thinks the // in the link is a comment and removes it - @throwTypeError("On-start callbacks are not implemented yet. See https:/\/github.com/oven-sh/bun/issues/2771"); - } - - function onEnd(callback) { - @throwTypeError("On-end callbacks are not implemented yet. See https:/\/github.com/oven-sh/bun/issues/2771"); - } - - function onDispose(callback) { - @throwTypeError("On-dispose callbacks are not implemented yet. See https:/\/github.com/oven-sh/bun/issues/2771"); - } - - function resolve(callback) { - @throwTypeError("build.resolve() is not implemented yet. See https:/\/github.com/oven-sh/bun/issues/2771"); - } - - const processSetupResult = () => { - var anyOnLoad = false, - anyOnResolve = false; - - for (var [namespace, callbacks] of onLoadPlugins.entries()) { - for (var [filter] of callbacks) { - this.addFilter(filter, namespace, 1); - anyOnLoad = true; - } - } - - for (var [namespace, callbacks] of onResolvePlugins.entries()) { - for (var [filter] of callbacks) { - this.addFilter(filter, namespace, 0); - anyOnResolve = true; - } - } - - if (anyOnResolve) { - var onResolveObject = this.onResolve; - if (!onResolveObject) { - this.onResolve = onResolvePlugins; - } else { - for (var [namespace, callbacks] of onResolvePlugins.entries()) { - var existing = onResolveObject.@get(namespace); - - if (!existing) { - onResolveObject.@set(namespace, callbacks); - } else { - onResolveObject.@set(namespace, existing.concat(callbacks)); - } - } - } - } - - if (anyOnLoad) { - var onLoadObject = this.onLoad; - if (!onLoadObject) { - this.onLoad = onLoadPlugins; - } else { - for (var [namespace, callbacks] of onLoadPlugins.entries()) { - var existing = onLoadObject.@get(namespace); - - if (!existing) { - onLoadObject.@set(namespace, callbacks); - } else { - onLoadObject.@set(namespace, existing.concat(callbacks)); - } - } - } - } - - return anyOnLoad || anyOnResolve; - }; - - var setupResult = setup({ - config, - onDispose, - onEnd, - onLoad, - onResolve, - onStart, - resolve, - // esbuild's options argument is different, we provide some interop - initialOptions: { - ...config, - bundle: true, - entryPoints: config.entrypoints ?? config.entryPoints ?? [], - minify: typeof config.minify === 'boolean' ? config.minify : false, - minifyIdentifiers: config.minify === true || config.minify?.identifiers, - minifyWhitespace: config.minify === true || config.minify?.whitespace, - minifySyntax: config.minify === true || config.minify?.syntax, - outbase: config.root, - platform: config.target === 'bun' ? 'node' : config.target, - root: undefined, - }, - esbuild: {}, - }); - - if (setupResult && @isPromise(setupResult)) { - if ( - @getPromiseInternalField(setupResult, @promiseFieldFlags) & - @promiseStateFulfilled - ) { - setupResult = @getPromiseInternalField( - setupResult, - @promiseFieldReactionsOrResult - ); - } else { - return setupResult.@then(processSetupResult); - } - } - - return processSetupResult(); -} - -function runOnLoadPlugins(internalID, path, namespace, defaultLoaderId) { - "use strict"; - - const LOADERS_MAP = { - jsx: 0, - js: 1, - ts: 2, - tsx: 3, - css: 4, - file: 5, - json: 6, - toml: 7, - wasm: 8, - napi: 9, - base64: 10, - dataurl: 11, - text: 12, - }; - const loaderName = [ - "jsx", - "js", - "ts", - "tsx", - "css", - "file", - "json", - "toml", - "wasm", - "napi", - "base64", - "dataurl", - "text", - ][defaultLoaderId]; - - var promiseResult = (async (internalID, path, namespace, defaultLoader) => { - var results = this.onLoad.@get(namespace); - if (!results) { - this.onLoadAsync(internalID, null, null, null); - return null; - } - - for (let [filter, callback] of results) { - if (filter.test(path)) { - var result = callback({ - path, - namespace, - // suffix - // pluginData - loader: defaultLoader, - }); - - while ( - result && - @isPromise(result) && - (@getPromiseInternalField(result, @promiseFieldFlags) & - @promiseStateMask) === - @promiseStateFulfilled - ) { - result = @getPromiseInternalField( - result, - @promiseFieldReactionsOrResult - ); - } - - if (result && @isPromise(result)) { - result = await result; - } - - if (!result || !@isObject(result)) { - continue; - } - - var { contents, loader = defaultLoader } = result; - if (!(typeof contents === "string") && !@isTypedArrayView(contents)) { - @throwTypeError( - 'onLoad plugins must return an object with "contents" as a string or Uint8Array' - ); - } - - if (!(typeof loader === "string")) { - @throwTypeError( - 'onLoad plugins must return an object with "loader" as a string' - ); - } - - const chosenLoader = LOADERS_MAP[loader]; - if (chosenLoader === @undefined) { - @throwTypeError(`Loader ${@jsonStringify(loader, " ")} is not supported.`); - } - - this.onLoadAsync(internalID, contents, chosenLoader); - return null; - } - } - - this.onLoadAsync(internalID, null, null); - return null; - })(internalID, path, namespace, loaderName); - - while ( - promiseResult && - @isPromise(promiseResult) && - (@getPromiseInternalField(promiseResult, @promiseFieldFlags) & - @promiseStateMask) === - @promiseStateFulfilled - ) { - promiseResult = @getPromiseInternalField( - promiseResult, - @promiseFieldReactionsOrResult - ); - } - - if (promiseResult && @isPromise(promiseResult)) { - promiseResult.then( - () => {}, - (e) => { - this.addError(internalID, e, 1); - } - ); - } -} diff --git a/src/bun.js/builtins/js/ByteLengthQueuingStrategy.js b/src/bun.js/builtins/js/ByteLengthQueuingStrategy.js deleted file mode 100644 index e8f5b1cfc..000000000 --- a/src/bun.js/builtins/js/ByteLengthQueuingStrategy.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2015 Canon Inc. - * Copyright (C) 2015 Igalia S.L. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -@getter -function highWaterMark() -{ - "use strict"; - - const highWaterMark = @getByIdDirectPrivate(this, "highWaterMark"); - if (highWaterMark === @undefined) - @throwTypeError("ByteLengthQueuingStrategy.highWaterMark getter called on incompatible |this| value."); - - return highWaterMark; -} - -function size(chunk) -{ - "use strict"; - - return chunk.byteLength; -} - -function initializeByteLengthQueuingStrategy(parameters) -{ - "use strict"; - - @putByIdDirectPrivate(this, "highWaterMark", @extractHighWaterMarkFromQueuingStrategyInit(parameters)); -} diff --git a/src/bun.js/builtins/js/ConsoleObject.js b/src/bun.js/builtins/js/ConsoleObject.js deleted file mode 100644 index d51ed08ef..000000000 --- a/src/bun.js/builtins/js/ConsoleObject.js +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2023 Codeblog Corp. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -@overriddenName="[Symbol.asyncIterator]" -function asyncIterator() { - "use strict"; - - const Iterator = async function* ConsoleAsyncIterator() { - "use strict"; - - const stream = @Bun.stdin.stream(); - var reader = stream.getReader(); - - // TODO: use builtin - var decoder = new globalThis.TextDecoder("utf-8", { fatal: false }); - var deferredError; - var indexOf = @Bun.indexOfLine; - - try { - while (true) { - var done, value; - var pendingChunk; - const firstResult = reader.readMany(); - if (@isPromise(firstResult)) { - ({done, value} = await firstResult); - } else { - ({done, value} = firstResult); - } - - if (done) { - if (pendingChunk) { - yield decoder.decode(pendingChunk); - } - return; - } - - var actualChunk; - // we assume it was given line-by-line - for (const chunk of value) { - actualChunk = chunk; - if (pendingChunk) { - actualChunk = Buffer.concat([pendingChunk, chunk]); - pendingChunk = null; - } - - var last = 0; - // TODO: "\r", 0x4048, 0x4049, 0x404A, 0x404B, 0x404C, 0x404D, 0x404E, 0x404F - var i = indexOf(actualChunk, last); - while (i !== -1) { - yield decoder.decode(actualChunk.subarray(last, i)); - last = i + 1; - i = indexOf(actualChunk, last); - } - - pendingChunk = actualChunk.subarray(last); - } - } - } catch(e) { - deferredError = e; - } finally { - reader.releaseLock(); - - if (deferredError) { - throw deferredError; - } - } - }; - - const symbol = globalThis.Symbol.asyncIterator; - this[symbol] = Iterator; - return Iterator(); -} - -function write(input) { - "use strict"; - - var writer = @getByIdDirectPrivate(this, "writer"); - if (!writer) { - var length = @toLength(input?.length ?? 0); - writer = @Bun.stdout.writer({highWaterMark: length > 65536 ? length : 65536}); - @putByIdDirectPrivate(this, "writer", writer); - } - - var wrote = writer.write(input); - - const count = @argumentCount(); - for (var i = 1; i < count; i++) { - wrote += writer.write(@argument(i)); - } - - writer.flush(true); - return wrote; -}
\ No newline at end of file diff --git a/src/bun.js/builtins/js/CountQueuingStrategy.js b/src/bun.js/builtins/js/CountQueuingStrategy.js deleted file mode 100644 index 3cd9cffc2..000000000 --- a/src/bun.js/builtins/js/CountQueuingStrategy.js +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2015 Canon Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -@getter -function highWaterMark() -{ - "use strict"; - - const highWaterMark = @getByIdDirectPrivate(this, "highWaterMark"); - if (highWaterMark === @undefined) - @throwTypeError("CountQueuingStrategy.highWaterMark getter called on incompatible |this| value."); - - return highWaterMark; -} - -function size() -{ - "use strict"; - - return 1; -} - -function initializeCountQueuingStrategy(parameters) -{ - "use strict"; - - @putByIdDirectPrivate(this, "highWaterMark", @extractHighWaterMarkFromQueuingStrategyInit(parameters)); -} diff --git a/src/bun.js/builtins/js/ImportMetaObject.js b/src/bun.js/builtins/js/ImportMetaObject.js deleted file mode 100644 index e2a9a42d8..000000000 --- a/src/bun.js/builtins/js/ImportMetaObject.js +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2023 Codeblog Corp. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -function loadCJS2ESM(resolvedSpecifier) { - "use strict"; - - var loader = @Loader; - var queue = @createFIFO(); - var key = resolvedSpecifier; - while (key) { - // we need to explicitly check because state could be @ModuleFetch - // it will throw this error if we do not: - // @throwTypeError("Requested module is already fetched."); - var entry = loader.registry.@get(key); - - if (!entry || !entry.state || entry.state <= @ModuleFetch) { - @fulfillModuleSync(key); - entry = loader.registry.@get(key); - } - - - // entry.fetch is a Promise<SourceCode> - // SourceCode is not a string, it's a JSC::SourceCode object - // this pulls it out of the promise without delaying by a tick - // the promise is already fullfilled by @fullfillModuleSync - var sourceCodeObject = @getPromiseInternalField( - entry.fetch, - @promiseFieldReactionsOrResult - ); - // parseModule() returns a Promise, but the value is already fulfilled - // so we just pull it out of the promise here once again - // But, this time we do it a little more carefully because this is a JSC function call and not bun source code - var moduleRecordPromise = loader.parseModule(key, sourceCodeObject); - var module = entry.module; - if (!module && moduleRecordPromise && @isPromise(moduleRecordPromise)) { - var reactionsOrResult = @getPromiseInternalField( - moduleRecordPromise, - @promiseFieldReactionsOrResult - ); - var flags = @getPromiseInternalField( - moduleRecordPromise, - @promiseFieldFlags - ); - var state = flags & @promiseStateMask; - // this branch should never happen, but just to be safe - if ( - state === @promiseStatePending || - (reactionsOrResult && @isPromise(reactionsOrResult)) - ) { - @throwTypeError(`require() async module \"${key}\" is unsupported`); - } else if (state === @promiseStateRejected) { - // this branch happens if there is a syntax error and somehow bun didn't catch it - // "throw" is unsupported here, so we use "throwTypeError" (TODO: use SyntaxError but preserve the specifier) - @throwTypeError( - `${ - reactionsOrResult?.message ?? "An error occurred" - } while parsing module \"${key}\"` - ); - } - entry.module = module = reactionsOrResult; - } else if (moduleRecordPromise && !module) { - entry.module = module = moduleRecordPromise; - } - - // This is very similar to "requestInstantiate" in ModuleLoader.js in JavaScriptCore. - @setStateToMax(entry, @ModuleLink); - var dependenciesMap = module.dependenciesMap; - var requestedModules = loader.requestedModules(module); - var dependencies = @newArrayWithSize(requestedModules.length); - for (var i = 0, length = requestedModules.length; i < length; ++i) { - var depName = requestedModules[i]; - // optimization: if it starts with a slash then it's an absolute path - // we don't need to run the resolver a 2nd time - var depKey = - depName[0] === "/" - ? depName - : loader.resolve(depName, key, @undefined); - var depEntry = loader.ensureRegistered(depKey); - if (depEntry.state < @ModuleLink) { - queue.push(depKey); - } - - @putByValDirect(dependencies, i, depEntry); - dependenciesMap.@set(depName, depEntry); - } - - entry.dependencies = dependencies; - // All dependencies resolved, set instantiate and satisfy field directly. - entry.instantiate = @Promise.resolve(entry) - entry.satisfy = @Promise.resolve(entry); - key = queue.shift(); - while (key && (loader.registry.@get(key)?.state ?? @ModuleFetch) >= @ModuleLink) { - key = queue.shift(); - } - - } - - var linkAndEvaluateResult = loader.linkAndEvaluateModule( - resolvedSpecifier, - @undefined - ); - if (linkAndEvaluateResult && @isPromise(linkAndEvaluateResult)) { - // if you use top-level await, or any dependencies use top-level await, then we throw here - // this means the module will still actually load eventually, but that's okay. - @throwTypeError( - `require() async module \"${resolvedSpecifier}\" is unsupported` - ); - } - - return loader.registry.@get(resolvedSpecifier); - -} - - -function requireESM(resolved) { - "use strict"; - var entry = @Loader.registry.@get(resolved); - - if (!entry || !entry.evaluated) { - entry = @loadCJS2ESM(resolved); - } - - if (!entry || !entry.evaluated || !entry.module) { - @throwTypeError(`require() failed to evaluate module \"${resolved}\". This is an internal consistentency error.`); - } - var exports = @Loader.getModuleNamespaceObject(entry.module); - var commonJS = exports.default; - var cjs = commonJS?.[@commonJSSymbol]; - if (cjs === 0) { - return commonJS; - } else if (cjs && @isCallable(commonJS)) { - return commonJS(); - } - - return exports; -} - -function internalRequire(resolved) { - "use strict"; - - var cached = @requireMap.@get(resolved); - const last5 = resolved.substring(resolved.length - 5); - if (cached) { - if (last5 === ".node") { - return cached.exports; - } - - return cached; - } - - // TODO: remove this hardcoding - if (last5 === ".json") { - var fs = (globalThis[Symbol.for("_fs")] ||= @Bun.fs()); - var exports = JSON.parse(fs.readFileSync(resolved, "utf8")); - @requireMap.@set(resolved, exports); - return exports; - } else if (last5 === ".node") { - var module = { exports: {} }; - process.dlopen(module, resolved); - @requireMap.@set(resolved, module); - return module.exports; - } else if (last5 === ".toml") { - var fs = (globalThis[Symbol.for("_fs")] ||= @Bun.fs()); - var exports = @Bun.TOML.parse(fs.readFileSync(resolved, "utf8")); - @requireMap.@set(resolved, exports); - return exports; - } else { - var exports = @requireESM(resolved); - @requireMap.@set(resolved, exports); - return exports; - } -} - -function require(name) { - const from = this?.path ?? arguments.callee.path; - - if (typeof name !== "string") { - @throwTypeError("require(name) must be a string"); - } - - return @internalRequire(@resolveSync(name, from)); -} - -@getter -function main() { - return this.path === @Bun.main; -} diff --git a/src/bun.js/builtins/js/JSBufferConstructor.js b/src/bun.js/builtins/js/JSBufferConstructor.js deleted file mode 100644 index f5389385e..000000000 --- a/src/bun.js/builtins/js/JSBufferConstructor.js +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2023 Codeblog Corp. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// ^ that comment is required or the builtins generator will have a fit. - -function from(items) { - "use strict"; - - if (@isUndefinedOrNull(items)) { - @throwTypeError( - "The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object.", - ); - } - - - // TODO: figure out why private symbol not found - if ( - typeof items === "string" || - (typeof items === "object" && - (@isTypedArrayView(items) || - items instanceof ArrayBuffer || - items instanceof SharedArrayBuffer || - items instanceof @String)) - ) { - switch (@argumentCount()) { - case 1: { - return new @Buffer(items); - } - case 2: { - return new @Buffer(items, @argument(1)); - } - default: { - return new @Buffer(items, @argument(1), @argument(2)); - } - } - } - - var arrayLike = @toObject( - items, - "The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object.", - ); - - if (!@isJSArray(arrayLike)) { - const toPrimitive = @tryGetByIdWithWellKnownSymbol(items, "toPrimitive"); - - if (toPrimitive) { - const primitive = toPrimitive.@call(items, "string"); - - if (typeof primitive === "string") { - switch (@argumentCount()) { - case 1: { - return new @Buffer(primitive); - } - case 2: { - return new @Buffer(primitive, @argument(1)); - } - default: { - return new @Buffer(primitive, @argument(1), @argument(2)); - } - } - } - } - - if (!("length" in arrayLike) || @isCallable(arrayLike)) { - @throwTypeError( - "The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object.", - ); - } - } - - // Don't pass the second argument because Node's Buffer.from doesn't accept - // a function and Uint8Array.from requires it if it exists - // That means we cannot use @tailCallFowrardArguments here, sadly - return new @Buffer(@Uint8Array.from(arrayLike).buffer); -} diff --git a/src/bun.js/builtins/js/JSBufferPrototype.js b/src/bun.js/builtins/js/JSBufferPrototype.js deleted file mode 100644 index 1ae6fb0d6..000000000 --- a/src/bun.js/builtins/js/JSBufferPrototype.js +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Copyright 2023 Codeblog Corp. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -// ^ that comment is required or the builtins generator will have a fit. - -// The fastest way as of April 2022 is to use DataView. -// DataView has intrinsics that cause inlining - -function setBigUint64(offset, value, le) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setBigUint64(offset, value, le); -} -function readInt8(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getInt8(offset); -} -function readUInt8(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getUint8(offset); -} -function readInt16LE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getInt16(offset, true); -} -function readInt16BE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getInt16(offset, false); -} -function readUInt16LE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getUint16(offset, true); -} -function readUInt16BE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getUint16(offset, false); -} -function readInt32LE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getInt32(offset, true); -} -function readInt32BE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getInt32(offset, false); -} -function readUInt32LE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getUint32(offset, true); -} -function readUInt32BE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getUint32(offset, false); -} - -function readIntLE(offset, byteLength) { - "use strict"; - const view = this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength); - switch (byteLength) { - case 1: { - return view.getInt8(offset); - } - case 2: { - return view.getInt16(offset, true); - } - case 3: { - const val = view.getUint16(offset, true) + view.getUint8(offset + 2) * 2 ** 16; - return val | (val & 2 ** 23) * 0x1fe; - } - case 4: { - return view.getInt32(offset, true); - } - case 5: { - const last = view.getUint8(offset + 4); - return (last | (last & 2 ** 7) * 0x1fffffe) * 2 ** 32 + view.getUint32(offset, true); - } - case 6: { - const last = view.getUint16(offset + 4, true); - return (last | (last & 2 ** 15) * 0x1fffe) * 2 ** 32 + view.getUint32(offset, true); - } - } - @throwRangeError("byteLength must be >= 1 and <= 6"); -} -function readIntBE(offset, byteLength) { - "use strict"; - const view = this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength); - switch (byteLength) { - case 1: { - return view.getInt8(offset); - } - case 2: { - return view.getInt16(offset, false); - } - case 3: { - const val = view.getUint16(offset + 1, false) + view.getUint8(offset) * 2 ** 16; - return val | (val & 2 ** 23) * 0x1fe; - } - case 4: { - return view.getInt32(offset, false); - } - case 5: { - const last = view.getUint8(offset); - return (last | (last & 2 ** 7) * 0x1fffffe) * 2 ** 32 + view.getUint32(offset + 1, false); - } - case 6: { - const last = view.getUint16(offset, false); - return (last | (last & 2 ** 15) * 0x1fffe) * 2 ** 32 + view.getUint32(offset + 2, false); - } - } - @throwRangeError("byteLength must be >= 1 and <= 6"); -} -function readUIntLE(offset, byteLength) { - "use strict"; - const view = this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength); - switch (byteLength) { - case 1: { - return view.getUint8(offset); - } - case 2: { - return view.getUint16(offset, true); - } - case 3: { - return view.getUint16(offset, true) + view.getUint8(offset + 2) * 2 ** 16; - } - case 4: { - return view.getUint32(offset, true); - } - case 5: { - return view.getUint8(offset + 4) * 2 ** 32 + view.getUint32(offset, true); - } - case 6: { - return view.getUint16(offset + 4, true) * 2 ** 32 + view.getUint32(offset, true); - } - } - @throwRangeError("byteLength must be >= 1 and <= 6"); -} - -function inspect(recurseTimes, ctx) { - "use strict"; - - return @Bun.inspect(this); -} - -function readUIntBE(offset, byteLength) { - "use strict"; - const view = this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength); - switch (byteLength) { - case 1: { - return view.getUint8(offset); - } - case 2: { - return view.getUint16(offset, false); - } - case 3: { - return view.getUint16(offset + 1, false) + view.getUint8(offset) * 2 ** 16; - } - case 4: { - return view.getUint32(offset, false); - } - case 5: { - const last = view.getUint8(offset); - return (last | (last & 2 ** 7) * 0x1fffffe) * 2 ** 32 + view.getUint32(offset + 1, false); - } - case 6: { - const last = view.getUint16(offset, false); - return (last | (last & 2 ** 15) * 0x1fffe) * 2 ** 32 + view.getUint32(offset + 2, false); - } - } - @throwRangeError("byteLength must be >= 1 and <= 6"); -} - -function readFloatLE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getFloat32(offset, true); -} -function readFloatBE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getFloat32(offset, false); -} -function readDoubleLE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getFloat64(offset, true); -} -function readDoubleBE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getFloat64(offset, false); -} -function readBigInt64LE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getBigInt64(offset, true); -} -function readBigInt64BE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getBigInt64(offset, false); -} -function readBigUInt64LE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getBigUint64(offset, true); -} -function readBigUInt64BE(offset) { - "use strict"; - return (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).getBigUint64(offset, false); -} - -function writeInt8(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setInt8(offset, value); - return offset + 1; -} -function writeUInt8(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setUint8(offset, value); - return offset + 1; -} -function writeInt16LE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setInt16(offset, value, true); - return offset + 2; -} -function writeInt16BE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setInt16(offset, value, false); - return offset + 2; -} -function writeUInt16LE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setUint16(offset, value, true); - return offset + 2; -} -function writeUInt16BE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setUint16(offset, value, false); - return offset + 2; -} -function writeInt32LE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setInt32(offset, value, true); - return offset + 4; -} -function writeInt32BE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setInt32(offset, value, false); - return offset + 4; -} -function writeUInt32LE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setUint32(offset, value, true); - return offset + 4; -} -function writeUInt32BE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setUint32(offset, value, false); - return offset + 4; -} - -function writeIntLE(value, offset, byteLength) { - "use strict"; - const view = this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength); - switch (byteLength) { - case 1: { - view.setInt8(offset, value); - break; - } - case 2: { - view.setInt16(offset, value, true); - break; - } - case 3: { - view.setUint16(offset, value & 0xFFFF, true); - view.setInt8(offset + 2, Math.floor(value * 2 ** -16)); - break; - } - case 4: { - view.setInt32(offset, value, true); - break; - } - case 5: { - view.setUint32(offset, value | 0, true); - view.setInt8(offset + 4, Math.floor(value * 2 ** -32)); - break; - } - case 6: { - view.setUint32(offset, value | 0, true); - view.setInt16(offset + 4, Math.floor(value * 2 ** -32), true); - break; - } - default: { - @throwRangeError("byteLength must be >= 1 and <= 6"); - } - } - return offset + byteLength; -} -function writeIntBE(value, offset, byteLength) { - "use strict"; - const view = this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength); - switch (byteLength) { - case 1: { - view.setInt8(offset, value); - break; - } - case 2: { - view.setInt16(offset, value, false); - break; - } - case 3: { - view.setUint16(offset + 1, value & 0xFFFF, false); - view.setInt8(offset, Math.floor(value * 2 ** -16)); - break; - } - case 4: { - view.setInt32(offset, value, false); - break; - } - case 5: { - view.setUint32(offset + 1, value | 0, false); - view.setInt8(offset, Math.floor(value * 2 ** -32)); - break; - } - case 6: { - view.setUint32(offset + 2, value | 0, false); - view.setInt16(offset, Math.floor(value * 2 ** -32), false); - break; - } - default: { - @throwRangeError("byteLength must be >= 1 and <= 6"); - } - } - return offset + byteLength; -} -function writeUIntLE(value, offset, byteLength) { - "use strict"; - const view = this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength); - switch (byteLength) { - case 1: { - view.setUint8(offset, value); - break; - } - case 2: { - view.setUint16(offset, value, true); - break; - } - case 3: { - view.setUint16(offset, value & 0xFFFF, true); - view.setUint8(offset + 2, Math.floor(value * 2 ** -16)); - break; - } - case 4: { - view.setUint32(offset, value, true); - break; - } - case 5: { - view.setUint32(offset, value | 0, true); - view.setUint8(offset + 4, Math.floor(value * 2 ** -32)); - break; - } - case 6: { - view.setUint32(offset, value | 0, true); - view.setUint16(offset + 4, Math.floor(value * 2 ** -32), true); - break; - } - default: { - @throwRangeError("byteLength must be >= 1 and <= 6"); - } - } - return offset + byteLength; -} -function writeUIntBE(value, offset, byteLength) { - "use strict"; - const view = this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength); - switch (byteLength) { - case 1: { - view.setUint8(offset, value); - break; - } - case 2: { - view.setUint16(offset, value, false); - break; - } - case 3: { - view.setUint16(offset + 1, value & 0xFFFF, false); - view.setUint8(offset, Math.floor(value * 2 ** -16)); - break; - } - case 4: { - view.setUint32(offset, value, false); - break; - } - case 5: { - view.setUint32(offset + 1, value | 0, false); - view.setUint8(offset, Math.floor(value * 2 ** -32)); - break; - } - case 6: { - view.setUint32(offset + 2, value | 0, false); - view.setUint16(offset, Math.floor(value * 2 ** -32), false); - break; - } - default: { - @throwRangeError("byteLength must be >= 1 and <= 6"); - } - } - return offset + byteLength; -} - -function writeFloatLE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setFloat32(offset, value, true); - return offset + 4; -} - -function writeFloatBE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setFloat32(offset, value, false); - return offset + 4; -} - -function writeDoubleLE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setFloat64(offset, value, true); - return offset + 8; -} - -function writeDoubleBE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setFloat64(offset, value, false); - return offset + 8; -} - -function writeBigInt64LE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setBigInt64(offset, value, true); - return offset + 8; -} - -function writeBigInt64BE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setBigInt64(offset, value, false); - return offset + 8; -} - -function writeBigUInt64LE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setBigUint64(offset, value, true); - return offset + 8; -} - -function writeBigUInt64BE(value, offset) { - "use strict"; - (this.@dataView ||= new DataView(this.buffer, this.byteOffset, this.byteLength)).setBigUint64(offset, value, false); - return offset + 8; -} - -function utf8Write(text, offset, length) { - "use strict"; - return this.write(text, offset, length, "utf8"); -} -function ucs2Write(text, offset, length) { - "use strict"; - return this.write(text, offset, length, "ucs2"); -} -function utf16leWrite(text, offset, length) { - "use strict"; - return this.write(text, offset, length, "utf16le"); -} -function latin1Write(text, offset, length) { - "use strict"; - return this.write(text, offset, length, "latin1"); -} -function asciiWrite(text, offset, length) { - "use strict"; - return this.write(text, offset, length, "ascii"); -} -function base64Write(text, offset, length) { - "use strict"; - return this.write(text, offset, length, "base64"); -} -function base64urlWrite(text, offset, length) { - "use strict"; - return this.write(text, offset, length, "base64url"); -} -function hexWrite(text, offset, length) { - "use strict"; - return this.write(text, offset, length, "hex"); -} - -function utf8Slice(offset, length) { - "use strict"; - return this.toString(offset, length, "utf8"); -} -function ucs2Slice(offset, length) { - "use strict"; - return this.toString(offset, length, "ucs2"); -} -function utf16leSlice(offset, length) { - "use strict"; - return this.toString(offset, length, "utf16le"); -} -function latin1Slice(offset, length) { - "use strict"; - return this.toString(offset, length, "latin1"); -} -function asciiSlice(offset, length) { - "use strict"; - return this.toString(offset, length, "ascii"); -} -function base64Slice(offset, length) { - "use strict"; - return this.toString(offset, length, "base64"); -} -function base64urlSlice(offset, length) { - "use strict"; - return this.toString(offset, length, "base64url"); -} -function hexSlice(offset, length) { - "use strict"; - return this.toString(offset, length, "hex"); -} - -function toJSON() { - "use strict"; - const type = "Buffer"; - const data = @Array.from(this); - return { type, data }; -} - -function slice(start, end) { - "use strict"; - var { buffer, byteOffset, byteLength } = this; - - function adjustOffset(offset, length) { - // Use Math.trunc() to convert offset to an integer value that can be larger - // than an Int32. Hence, don't use offset | 0 or similar techniques. - offset = @trunc(offset); - if (offset === 0 || @isNaN(offset)) { - return 0; - } else if (offset < 0) { - offset += length; - return offset > 0 ? offset : 0; - } else { - return offset < length ? offset : length; - } - } - - var start_ = adjustOffset(start, byteLength); - var end_ = end !== @undefined ? adjustOffset(end, byteLength) : byteLength; - return new Buffer(buffer, byteOffset + start_, end_ > start_ ? (end_ - start_) : 0); -} - -@getter -function parent() { - "use strict"; - return @isObject(this) && this instanceof @Buffer ? this.buffer : @undefined; -} - -@getter -function offset() { - "use strict"; - return @isObject(this) && this instanceof @Buffer ? this.byteOffset : @undefined; -} diff --git a/src/bun.js/builtins/js/ProcessObjectInternals.js b/src/bun.js/builtins/js/ProcessObjectInternals.js deleted file mode 100644 index 82df97f63..000000000 --- a/src/bun.js/builtins/js/ProcessObjectInternals.js +++ /dev/null @@ -1,678 +0,0 @@ -/* - * Copyright 2023 Codeblog Corp. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -function binding(bindingName) { - "use strict"; - bindingName !== "constants" && - @throwTypeError( - 'process.binding() is not supported in Bun. If that breaks something, please file an issue and include a reproducible code sample.' - ); - - var cache = globalThis.Symbol.for("process.bindings.constants"); - var constants = globalThis[cache]; - if (!constants) { - // TODO: make this less hacky. - // This calls require("node:fs").constants - // except, outside an ESM module. - const {constants: fs} = globalThis[globalThis.Symbol.for("Bun.lazy")]( - "createImportMeta", - "node:process" - ).require( - "node:fs" - ) - constants = { - fs, - zlib: {}, - crypto: {}, - os: @Bun._Os().constants, - }; - globalThis[cache] = constants; - } - return constants; -} - -function getStdioWriteStream(fd_, rawRequire) { - var module = { path: "node:process", require: rawRequire }; - var require = path => module.require(path); - - function createStdioWriteStream(fd_) { - var { Duplex, eos, destroy } = require("node:stream"); - var StdioWriteStream = class StdioWriteStream extends Duplex { - #writeStream; - #readStream; - - #readable = true; - #writable = true; - #fdPath; - - #onClose; - #onDrain; - #onFinish; - #onReadable; - #isTTY; - - get isTTY() { - return (this.#isTTY ??= require("node:tty").isatty(fd_)); - } - - get fd() { - return fd_; - } - - constructor(fd) { - super({ readable: true, writable: true }); - this.#fdPath = `/dev/fd/${fd}`; - } - - #onFinished(err) { - const cb = this.#onClose; - this.#onClose = null; - - if (cb) { - cb(err); - } else if (err) { - this.destroy(err); - } else if (!this.#readable && !this.#writable) { - this.destroy(); - } - } - - _destroy(err, callback) { - if (!err && this.#onClose !== null) { - var AbortError = class AbortError extends Error { - constructor(message = "The operation was aborted", options = void 0) { - if (options !== void 0 && typeof options !== "object") { - throw new Error(`Invalid AbortError options:\n\n${JSON.stringify(options, null, 2)}`); - } - super(message, options); - this.code = "ABORT_ERR"; - this.name = "AbortError"; - } - }; - err = new AbortError(); - } - - this.#onDrain = null; - this.#onFinish = null; - if (this.#onClose === null) { - callback(err); - } else { - this.#onClose = callback; - if (this.#writeStream) destroy(this.#writeStream, err); - if (this.#readStream) destroy(this.#readStream, err); - } - } - - _write(chunk, encoding, callback) { - if (!this.#writeStream) { - var { createWriteStream } = require("node:fs"); - var stream = (this.#writeStream = createWriteStream(this.#fdPath)); - - stream.on("finish", () => { - if (this.#onFinish) { - const cb = this.#onFinish; - this.#onFinish = null; - cb(); - } - }); - - stream.on("drain", () => { - if (this.#onDrain) { - const cb = this.#onDrain; - this.#onDrain = null; - cb(); - } - }); - - eos(stream, err => { - this.#writable = false; - if (err) { - destroy(stream, err); - } - this.#onFinished(err); - }); - } - if (stream.write(chunk, encoding)) { - callback(); - } else { - this.#onDrain = callback; - } - } - - _final(callback) { - this.#writeStream && this.#writeStream.end(); - this.#onFinish = callback; - } - - #loadReadStream() { - var { createReadStream } = require("node:fs"); - - var readStream = (this.#readStream = createReadStream(this.#fdPath)); - - readStream.on("readable", () => { - if (this.#onReadable) { - const cb = this.#onReadable; - this.#onReadable = null; - cb(); - } else { - this.read(); - } - }); - - readStream.on("end", () => { - this.push(null); - }); - - eos(readStream, err => { - this.#readable = false; - if (err) { - destroy(readStream, err); - } - this.#onFinished(err); - }); - return readStream; - } - - _read() { - var stream = this.#readStream; - if (!stream) { - stream = this.#loadReadStream(); - } - - while (true) { - const buf = stream.read(); - if (buf === null || !this.push(buf)) { - return; - } - } - } - }; - return new StdioWriteStream(fd_); - } - - var { EventEmitter } = require("node:events"); - - function isFastEncoding(encoding) { - if (!encoding) return true; - - var normalied = encoding.toLowerCase(); - return normalied === "utf8" || normalied === "utf-8" || normalied === "buffer" || normalied === "binary"; - } - - var readline; - - var FastStdioWriteStream = class StdioWriteStream extends EventEmitter { - #fd; - #innerStream; - #writer; - #isTTY; - - bytesWritten = 0; - - setDefaultEncoding(encoding) { - if (this.#innerStream || !isFastEncoding(encoding)) { - this.#ensureInnerStream(); - return this.#innerStream.setDefaultEncoding(encoding); - } - } - - #createWriter() { - switch (this.#fd) { - case 1: { - var writer = Bun.stdout.writer({ highWaterMark: 0 }); - writer.unref(); - return writer; - } - - case 2: { - var writer = Bun.stderr.writer({ highWaterMark: 0 }); - writer.unref(); - return writer; - } - default: { - throw new Error("Unsupported writer"); - } - } - } - - #getWriter() { - return (this.#writer ??= this.#createWriter()); - } - - constructor(fd_) { - super(); - this.#fd = fd_; - } - - get fd() { - return this.#fd; - } - - get isTTY() { - return (this.#isTTY ??= require("node:tty").isatty(this.#fd)); - } - - cursorTo(x, y, callback) { - return (readline ??= require("readline")).cursorTo(this, x, y, callback); - } - - moveCursor(dx, dy, callback) { - return (readline ??= require("readline")).moveCursor(this, dx, dy, callback); - } - - clearLine(dir, callback) { - return (readline ??= require("readline")).clearLine(this, dir, callback); - } - - clearScreenDown(callback) { - return (readline ??= require("readline")).clearScreenDown(this, callback); - } - - // TODO: once implemented this.columns and this.rows should be uncommented - // getWindowSize() { - // return [this.columns, this.rows]; - // } - - ref() { - this.#getWriter().ref(); - } - - unref() { - this.#getWriter().unref(); - } - - on(event, listener) { - if (event === "close" || event === "finish") { - this.#ensureInnerStream(); - return this.#innerStream.on(event, listener); - } - - if (event === "drain") { - return super.on("drain", listener); - } - - if (event === "error") { - return super.on("error", listener); - } - - return super.on(event, listener); - } - - get _writableState() { - this.#ensureInnerStream(); - return this.#innerStream._writableState; - } - - get _readableState() { - this.#ensureInnerStream(); - return this.#innerStream._readableState; - } - - pipe(destination) { - this.#ensureInnerStream(); - return this.#innerStream.pipe(destination); - } - - unpipe(destination) { - this.#ensureInnerStream(); - return this.#innerStream.unpipe(destination); - } - - #ensureInnerStream() { - if (this.#innerStream) return; - this.#innerStream = createStdioWriteStream(this.#fd); - const events = this.eventNames(); - for (const event of events) { - this.#innerStream.on(event, (...args) => { - this.emit(event, ...args); - }); - } - } - - #write1(chunk) { - var writer = this.#getWriter(); - const writeResult = writer.write(chunk); - this.bytesWritten += writeResult; - const flushResult = writer.flush(false); - return !!(writeResult || flushResult); - } - - #writeWithEncoding(chunk, encoding) { - if (!isFastEncoding(encoding)) { - this.#ensureInnerStream(); - return this.#innerStream.write(chunk, encoding); - } - - return this.#write1(chunk); - } - - #performCallback(cb, err) { - if (err) { - this.emit("error", err); - } - - try { - cb(err ? err : null); - } catch (err2) { - this.emit("error", err2); - } - } - - #writeWithCallbackAndEncoding(chunk, encoding, callback) { - if (!isFastEncoding(encoding)) { - this.#ensureInnerStream(); - return this.#innerStream.write(chunk, encoding, callback); - } - - var writer = this.#getWriter(); - const writeResult = writer.write(chunk); - const flushResult = writer.flush(true); - if (flushResult?.then) { - flushResult.then( - () => { - this.#performCallback(callback); - this.emit("drain"); - }, - err => this.#performCallback(callback, err), - ); - return false; - } - - queueMicrotask(() => { - this.#performCallback(callback); - }); - - return !!(writeResult || flushResult); - } - - write(chunk, encoding, callback) { - const result = this._write(chunk, encoding, callback); - - if (result) { - this.emit("drain"); - } - - return result; - } - - get hasColors() { - return Bun.tty[this.#fd].hasColors; - } - - _write(chunk, encoding, callback) { - var inner = this.#innerStream; - if (inner) { - return inner.write(chunk, encoding, callback); - } - - switch (arguments.length) { - case 0: { - var error = new Error("Invalid arguments"); - error.code = "ERR_INVALID_ARG_TYPE"; - throw error; - } - case 1: { - return this.#write1(chunk); - } - case 2: { - if (typeof encoding === "function") { - return this.#writeWithCallbackAndEncoding(chunk, "", encoding); - } else if (typeof encoding === "string") { - return this.#writeWithEncoding(chunk, encoding); - } - } - default: { - if ( - (typeof encoding !== "undefined" && typeof encoding !== "string") || - (typeof callback !== "undefined" && typeof callback !== "function") - ) { - var error = new Error("Invalid arguments"); - error.code = "ERR_INVALID_ARG_TYPE"; - throw error; - } - - if (typeof callback === "undefined") { - return this.#writeWithEncoding(chunk, encoding); - } - - return this.#writeWithCallbackAndEncoding(chunk, encoding, callback); - } - } - } - - destroy() { - return this; - } - - end() { - return this; - } - }; - - return new FastStdioWriteStream(fd_); -} - -function getStdinStream(fd_, rawRequire, Bun) { - var module = { path: "node:process", require: rawRequire }; - var require = path => module.require(path); - - var { Duplex, eos, destroy } = require("node:stream"); - - var StdinStream = class StdinStream extends Duplex { - #reader; - // TODO: investigate https://github.com/oven-sh/bun/issues/1607 - - #readRef; - #writeStream; - - #readable = true; - #unrefOnRead = false; - #writable = true; - - #onFinish; - #onClose; - #onDrain; - - get isTTY() { - return require("tty").isatty(fd_); - } - - get fd() { - return fd_; - } - - constructor() { - super({ readable: true, writable: true }); - } - - #onFinished(err) { - const cb = this.#onClose; - this.#onClose = null; - - if (cb) { - cb(err); - } else if (err) { - this.destroy(err); - } else if (!this.#readable && !this.#writable) { - this.destroy(); - } - } - - _destroy(err, callback) { - if (!err && this.#onClose !== null) { - var AbortError = class AbortError extends Error { - constructor(message = "The operation was aborted", options = void 0) { - if (options !== void 0 && typeof options !== "object") { - throw new Error(`Invalid AbortError options:\n\n${JSON.stringify(options, null, 2)}`); - } - super(message, options); - this.code = "ABORT_ERR"; - this.name = "AbortError"; - } - }; - err = new AbortError(); - } - - if (this.#onClose === null) { - callback(err); - } else { - this.#onClose = callback; - if (this.#writeStream) destroy(this.#writeStream, err); - } - } - - setRawMode(mode) {} - on(name, callback) { - // Streams don't generally required to present any data when only - // `readable` events are present, i.e. `readableFlowing === false` - // - // However, Node.js has a this quirk whereby `process.stdin.read()` - // blocks under TTY mode, thus looping `.read()` in this particular - // case would not result in truncation. - // - // Therefore the following hack is only specific to `process.stdin` - // and does not apply to the underlying Stream implementation. - if (name === "readable") { - this.ref(); - this.#unrefOnRead = true; - } - return super.on(name, callback); - } - - pause() { - this.unref(); - return super.pause(); - } - - resume() { - this.ref(); - return super.resume(); - } - - ref() { - this.#reader ??= Bun.stdin.stream().getReader(); - this.#readRef ??= setInterval(() => {}, 1 << 30); - } - - unref() { - if (this.#readRef) { - clearInterval(this.#readRef); - this.#readRef = null; - } - } - - async #readInternal() { - try { - var done, value; - const read = this.#reader.readMany(); - - // read same-tick if possible - if (!read?.then) { - ({ done, value } = read); - } else { - ({ done, value } = await read); - } - - if (!done) { - this.push(value[0]); - - // shouldn't actually happen, but just in case - const length = value.length; - for (let i = 1; i < length; i++) { - this.push(value[i]); - } - } else { - this.push(null); - this.pause(); - this.#readable = false; - this.#onFinished(); - } - } catch (err) { - this.#readable = false; - this.#onFinished(err); - } - } - - _read(size) { - if (this.#unrefOnRead) { - this.unref(); - this.#unrefOnRead = false; - } - this.#readInternal(); - } - - #constructWriteStream() { - var { createWriteStream } = require("node:fs"); - var writeStream = (this.#writeStream = createWriteStream("/dev/fd/0")); - - writeStream.on("finish", () => { - if (this.#onFinish) { - const cb = this.#onFinish; - this.#onFinish = null; - cb(); - } - }); - - writeStream.on("drain", () => { - if (this.#onDrain) { - const cb = this.#onDrain; - this.#onDrain = null; - cb(); - } - }); - - eos(writeStream, err => { - this.#writable = false; - if (err) { - destroy(writeStream, err); - } - this.#onFinished(err); - }); - - return writeStream; - } - - _write(chunk, encoding, callback) { - var writeStream = this.#writeStream; - if (!writeStream) { - writeStream = this.#constructWriteStream(); - } - - if (writeStream.write(chunk, encoding)) { - callback(); - } else { - this.#onDrain = callback; - } - } - - _final(callback) { - this.#writeStream.end(); - this.#onFinish = (...args) => callback(...args); - } - }; - - return new StdinStream(); -} diff --git a/src/bun.js/builtins/js/ReadableByteStreamController.js b/src/bun.js/builtins/js/ReadableByteStreamController.js deleted file mode 100644 index 0b47d730c..000000000 --- a/src/bun.js/builtins/js/ReadableByteStreamController.js +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2016 Canon Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -function initializeReadableByteStreamController(stream, underlyingByteSource, highWaterMark) -{ - "use strict"; - - if (arguments.length !== 4 && arguments[3] !== @isReadableStream) - @throwTypeError("ReadableByteStreamController constructor should not be called directly"); - - return @privateInitializeReadableByteStreamController.@call(this, stream, underlyingByteSource, highWaterMark); -} - -function enqueue(chunk) -{ - "use strict"; - - if (!@isReadableByteStreamController(this)) - throw @makeThisTypeError("ReadableByteStreamController", "enqueue"); - - if (@getByIdDirectPrivate(this, "closeRequested")) - @throwTypeError("ReadableByteStreamController is requested to close"); - - if (@getByIdDirectPrivate(@getByIdDirectPrivate(this, "controlledReadableStream"), "state") !== @streamReadable) - @throwTypeError("ReadableStream is not readable"); - - if (!@isObject(chunk) || !@ArrayBuffer.@isView(chunk)) - @throwTypeError("Provided chunk is not a TypedArray"); - - return @readableByteStreamControllerEnqueue(this, chunk); -} - -function error(error) -{ - "use strict"; - - if (!@isReadableByteStreamController(this)) - throw @makeThisTypeError("ReadableByteStreamController", "error"); - - if (@getByIdDirectPrivate(@getByIdDirectPrivate(this, "controlledReadableStream"), "state") !== @streamReadable) - @throwTypeError("ReadableStream is not readable"); - - @readableByteStreamControllerError(this, error); -} - -function close() -{ - "use strict"; - - if (!@isReadableByteStreamController(this)) - throw @makeThisTypeError("ReadableByteStreamController", "close"); - - if (@getByIdDirectPrivate(this, "closeRequested")) - @throwTypeError("Close has already been requested"); - - if (@getByIdDirectPrivate(@getByIdDirectPrivate(this, "controlledReadableStream"), "state") !== @streamReadable) - @throwTypeError("ReadableStream is not readable"); - - @readableByteStreamControllerClose(this); -} - -@getter -function byobRequest() -{ - "use strict"; - - if (!@isReadableByteStreamController(this)) - throw @makeGetterTypeError("ReadableByteStreamController", "byobRequest"); - - - var request = @getByIdDirectPrivate(this, "byobRequest"); - if (request === @undefined) { - var pending = @getByIdDirectPrivate(this, "pendingPullIntos"); - const firstDescriptor = pending.peek(); - if (firstDescriptor) { - const view = new @Uint8Array(firstDescriptor.buffer, - firstDescriptor.byteOffset + firstDescriptor.bytesFilled, - firstDescriptor.byteLength - firstDescriptor.bytesFilled); - @putByIdDirectPrivate(this, "byobRequest", new @ReadableStreamBYOBRequest(this, view, @isReadableStream)); - } - } - - return @getByIdDirectPrivate(this, "byobRequest"); -} - -@getter -function desiredSize() -{ - "use strict"; - - if (!@isReadableByteStreamController(this)) - throw @makeGetterTypeError("ReadableByteStreamController", "desiredSize"); - - return @readableByteStreamControllerGetDesiredSize(this); -} diff --git a/src/bun.js/builtins/js/ReadableByteStreamInternals.js b/src/bun.js/builtins/js/ReadableByteStreamInternals.js deleted file mode 100644 index 01da62e1a..000000000 --- a/src/bun.js/builtins/js/ReadableByteStreamInternals.js +++ /dev/null @@ -1,712 +0,0 @@ -/* - * Copyright (C) 2016 Canon Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -// @internal - -function privateInitializeReadableByteStreamController(stream, underlyingByteSource, highWaterMark) -{ - "use strict"; - - if (!@isReadableStream(stream)) - @throwTypeError("ReadableByteStreamController needs a ReadableStream"); - - // readableStreamController is initialized with null value. - if (@getByIdDirectPrivate(stream, "readableStreamController") !== null) - @throwTypeError("ReadableStream already has a controller"); - - @putByIdDirectPrivate(this, "controlledReadableStream", stream); - @putByIdDirectPrivate(this, "underlyingByteSource", underlyingByteSource); - @putByIdDirectPrivate(this, "pullAgain", false); - @putByIdDirectPrivate(this, "pulling", false); - @readableByteStreamControllerClearPendingPullIntos(this); - @putByIdDirectPrivate(this, "queue", @newQueue()); - @putByIdDirectPrivate(this, "started", 0); - @putByIdDirectPrivate(this, "closeRequested", false); - - let hwm = @toNumber(highWaterMark); - if (@isNaN(hwm) || hwm < 0) - @throwRangeError("highWaterMark value is negative or not a number"); - @putByIdDirectPrivate(this, "strategyHWM", hwm); - - let autoAllocateChunkSize = underlyingByteSource.autoAllocateChunkSize; - if (autoAllocateChunkSize !== @undefined) { - autoAllocateChunkSize = @toNumber(autoAllocateChunkSize); - if (autoAllocateChunkSize <= 0 || autoAllocateChunkSize === @Infinity || autoAllocateChunkSize === -@Infinity) - @throwRangeError("autoAllocateChunkSize value is negative or equal to positive or negative infinity"); - } - @putByIdDirectPrivate(this, "autoAllocateChunkSize", autoAllocateChunkSize); - @putByIdDirectPrivate(this, "pendingPullIntos", @createFIFO()); - - - const controller = this; - @promiseInvokeOrNoopNoCatch(@getByIdDirectPrivate(controller, "underlyingByteSource"), "start", [controller]).@then(() => { - @putByIdDirectPrivate(controller, "started", 1); - @assert(!@getByIdDirectPrivate(controller, "pulling")); - @assert(!@getByIdDirectPrivate(controller, "pullAgain")); - @readableByteStreamControllerCallPullIfNeeded(controller); - }, (error) => { - if (@getByIdDirectPrivate(stream, "state") === @streamReadable) - @readableByteStreamControllerError(controller, error); - }); - - @putByIdDirectPrivate(this, "cancel", @readableByteStreamControllerCancel); - @putByIdDirectPrivate(this, "pull", @readableByteStreamControllerPull); - - return this; -} - -function readableStreamByteStreamControllerStart(controller) { - "use strict"; - @putByIdDirectPrivate(controller, "start", @undefined); - -} - - -function privateInitializeReadableStreamBYOBRequest(controller, view) -{ - "use strict"; - - @putByIdDirectPrivate(this, "associatedReadableByteStreamController", controller); - @putByIdDirectPrivate(this, "view", view); -} - -function isReadableByteStreamController(controller) -{ - "use strict"; - - // Same test mechanism as in isReadableStreamDefaultController (ReadableStreamInternals.js). - // See corresponding function for explanations. - return @isObject(controller) && !!@getByIdDirectPrivate(controller, "underlyingByteSource"); -} - -function isReadableStreamBYOBRequest(byobRequest) -{ - "use strict"; - - // Same test mechanism as in isReadableStreamDefaultController (ReadableStreamInternals.js). - // See corresponding function for explanations. - return @isObject(byobRequest) && !!@getByIdDirectPrivate(byobRequest, "associatedReadableByteStreamController"); -} - -function isReadableStreamBYOBReader(reader) -{ - "use strict"; - - // Spec tells to return true only if reader has a readIntoRequests internal slot. - // However, since it is a private slot, it cannot be checked using hasOwnProperty(). - // Since readIntoRequests is initialized with an empty array, the following test is ok. - return @isObject(reader) && !!@getByIdDirectPrivate(reader, "readIntoRequests"); -} - -function readableByteStreamControllerCancel(controller, reason) -{ - "use strict"; - - var pendingPullIntos = @getByIdDirectPrivate(controller, "pendingPullIntos"); - var first = pendingPullIntos.peek(); - if (first) - first.bytesFilled = 0; - - @putByIdDirectPrivate(controller, "queue", @newQueue()); - return @promiseInvokeOrNoop(@getByIdDirectPrivate(controller, "underlyingByteSource"), "cancel", [reason]); -} - -function readableByteStreamControllerError(controller, e) -{ - "use strict"; - - @assert(@getByIdDirectPrivate(@getByIdDirectPrivate(controller, "controlledReadableStream"), "state") === @streamReadable); - @readableByteStreamControllerClearPendingPullIntos(controller); - @putByIdDirectPrivate(controller, "queue", @newQueue()); - @readableStreamError(@getByIdDirectPrivate(controller, "controlledReadableStream"), e); -} - -function readableByteStreamControllerClose(controller) -{ - "use strict"; - - @assert(!@getByIdDirectPrivate(controller, "closeRequested")); - @assert(@getByIdDirectPrivate(@getByIdDirectPrivate(controller, "controlledReadableStream"), "state") === @streamReadable); - - if (@getByIdDirectPrivate(controller, "queue").size > 0) { - @putByIdDirectPrivate(controller, "closeRequested", true); - return; - } - - var first = @getByIdDirectPrivate(controller, "pendingPullIntos")?.peek(); - if (first) { - if (first.bytesFilled > 0) { - const e = @makeTypeError("Close requested while there remain pending bytes"); - @readableByteStreamControllerError(controller, e); - throw e; - } - } - - @readableStreamClose(@getByIdDirectPrivate(controller, "controlledReadableStream")); -} - -function readableByteStreamControllerClearPendingPullIntos(controller) -{ - "use strict"; - - @readableByteStreamControllerInvalidateBYOBRequest(controller); - var existing = @getByIdDirectPrivate(controller, "pendingPullIntos"); - if (existing !== @undefined) { - existing.clear(); - } else { - @putByIdDirectPrivate(controller, "pendingPullIntos", @createFIFO()); - } -} - -function readableByteStreamControllerGetDesiredSize(controller) -{ - "use strict"; - - const stream = @getByIdDirectPrivate(controller, "controlledReadableStream"); - const state = @getByIdDirectPrivate(stream, "state"); - - if (state === @streamErrored) - return null; - if (state === @streamClosed) - return 0; - - return @getByIdDirectPrivate(controller, "strategyHWM") - @getByIdDirectPrivate(controller, "queue").size; -} - -function readableStreamHasBYOBReader(stream) -{ - "use strict"; - - const reader = @getByIdDirectPrivate(stream, "reader"); - return reader !== @undefined && @isReadableStreamBYOBReader(reader); -} - -function readableStreamHasDefaultReader(stream) -{ - "use strict"; - - const reader = @getByIdDirectPrivate(stream, "reader"); - return reader !== @undefined && @isReadableStreamDefaultReader(reader); -} - -function readableByteStreamControllerHandleQueueDrain(controller) { - - "use strict"; - - @assert(@getByIdDirectPrivate(@getByIdDirectPrivate(controller, "controlledReadableStream"), "state") === @streamReadable); - if (!@getByIdDirectPrivate(controller, "queue").size && @getByIdDirectPrivate(controller, "closeRequested")) - @readableStreamClose(@getByIdDirectPrivate(controller, "controlledReadableStream")); - else - @readableByteStreamControllerCallPullIfNeeded(controller); -} - -function readableByteStreamControllerPull(controller) -{ - "use strict"; - - const stream = @getByIdDirectPrivate(controller, "controlledReadableStream"); - @assert(@readableStreamHasDefaultReader(stream)); - if (@getByIdDirectPrivate(controller, "queue").content?.isNotEmpty()) { - const entry = @getByIdDirectPrivate(controller, "queue").content.shift(); - @getByIdDirectPrivate(controller, "queue").size -= entry.byteLength; - @readableByteStreamControllerHandleQueueDrain(controller); - let view; - try { - view = new @Uint8Array(entry.buffer, entry.byteOffset, entry.byteLength); - } catch (error) { - return @Promise.@reject(error); - } - return @createFulfilledPromise({ value: view, done: false }); - } - - if (@getByIdDirectPrivate(controller, "autoAllocateChunkSize") !== @undefined) { - let buffer; - try { - buffer = @createUninitializedArrayBuffer(@getByIdDirectPrivate(controller, "autoAllocateChunkSize")); - } catch (error) { - return @Promise.@reject(error); - } - const pullIntoDescriptor = { - buffer, - byteOffset: 0, - byteLength: @getByIdDirectPrivate(controller, "autoAllocateChunkSize"), - bytesFilled: 0, - elementSize: 1, - ctor: @Uint8Array, - readerType: 'default' - }; - @getByIdDirectPrivate(controller, "pendingPullIntos").push(pullIntoDescriptor); - } - - const promise = @readableStreamAddReadRequest(stream); - @readableByteStreamControllerCallPullIfNeeded(controller); - return promise; -} - -function readableByteStreamControllerShouldCallPull(controller) -{ - "use strict"; - - const stream = @getByIdDirectPrivate(controller, "controlledReadableStream"); - - if (@getByIdDirectPrivate(stream, "state") !== @streamReadable) - return false; - if (@getByIdDirectPrivate(controller, "closeRequested")) - return false; - if (!(@getByIdDirectPrivate(controller, "started") > 0)) - return false; - const reader = @getByIdDirectPrivate(stream, "reader"); - - if (reader && (@getByIdDirectPrivate(reader, "readRequests")?.isNotEmpty() || !!@getByIdDirectPrivate(reader, "bunNativePtr"))) - return true; - if (@readableStreamHasBYOBReader(stream) && @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readIntoRequests")?.isNotEmpty()) - return true; - if (@readableByteStreamControllerGetDesiredSize(controller) > 0) - return true; - return false; -} - -function readableByteStreamControllerCallPullIfNeeded(controller) -{ - "use strict"; - - if (!@readableByteStreamControllerShouldCallPull(controller)) - return; - - if (@getByIdDirectPrivate(controller, "pulling")) { - @putByIdDirectPrivate(controller, "pullAgain", true); - return; - } - - @assert(!@getByIdDirectPrivate(controller, "pullAgain")); - @putByIdDirectPrivate(controller, "pulling", true); - @promiseInvokeOrNoop(@getByIdDirectPrivate(controller, "underlyingByteSource"), "pull", [controller]).@then(() => { - @putByIdDirectPrivate(controller, "pulling", false); - if (@getByIdDirectPrivate(controller, "pullAgain")) { - @putByIdDirectPrivate(controller, "pullAgain", false); - @readableByteStreamControllerCallPullIfNeeded(controller); - } - }, (error) => { - if (@getByIdDirectPrivate(@getByIdDirectPrivate(controller, "controlledReadableStream"), "state") === @streamReadable) - @readableByteStreamControllerError(controller, error); - }); -} - -function transferBufferToCurrentRealm(buffer) -{ - "use strict"; - - // FIXME: Determine what should be done here exactly (what is already existing in current - // codebase and what has to be added). According to spec, Transfer operation should be - // performed in order to transfer buffer to current realm. For the moment, simply return - // received buffer. - return buffer; -} - -function readableStreamReaderKind(reader) { - "use strict"; - - - if (!!@getByIdDirectPrivate(reader, "readRequests")) - return @getByIdDirectPrivate(reader, "bunNativePtr") ? 3 : 1; - - if (!!@getByIdDirectPrivate(reader, "readIntoRequests")) - return 2; - - return 0; -} -function readableByteStreamControllerEnqueue(controller, chunk) -{ - "use strict"; - - const stream = @getByIdDirectPrivate(controller, "controlledReadableStream"); - @assert(!@getByIdDirectPrivate(controller, "closeRequested")); - @assert(@getByIdDirectPrivate(stream, "state") === @streamReadable); - - - switch (@getByIdDirectPrivate(stream, "reader") ? @readableStreamReaderKind(@getByIdDirectPrivate(stream, "reader")) : 0) { - /* default reader */ - case 1: { - if (!@getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests")?.isNotEmpty()) - @readableByteStreamControllerEnqueueChunk(controller, @transferBufferToCurrentRealm(chunk.buffer), chunk.byteOffset, chunk.byteLength); - else { - @assert(!@getByIdDirectPrivate(controller, "queue").content.size()); - const transferredView = chunk.constructor === @Uint8Array ? chunk : new @Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength); - @readableStreamFulfillReadRequest(stream, transferredView, false); - } - break; - } - - /* BYOB */ - case 2: { - @readableByteStreamControllerEnqueueChunk(controller, @transferBufferToCurrentRealm(chunk.buffer), chunk.byteOffset, chunk.byteLength); - @readableByteStreamControllerProcessPullDescriptors(controller); - break; - } - - /* NativeReader */ - case 3: { - // reader.@enqueueNative(@getByIdDirectPrivate(reader, "bunNativePtr"), chunk); - - break; - } - - default: { - @assert(!@isReadableStreamLocked(stream)); - @readableByteStreamControllerEnqueueChunk(controller, @transferBufferToCurrentRealm(chunk.buffer), chunk.byteOffset, chunk.byteLength); - break; - } - } -} - -// Spec name: readableByteStreamControllerEnqueueChunkToQueue. -function readableByteStreamControllerEnqueueChunk(controller, buffer, byteOffset, byteLength) -{ - "use strict"; - - @getByIdDirectPrivate(controller, "queue").content.push({ - buffer: buffer, - byteOffset: byteOffset, - byteLength: byteLength - }); - @getByIdDirectPrivate(controller, "queue").size += byteLength; -} - -function readableByteStreamControllerRespondWithNewView(controller, view) -{ - "use strict"; - - @assert(@getByIdDirectPrivate(controller, "pendingPullIntos").isNotEmpty()); - - let firstDescriptor = @getByIdDirectPrivate(controller, "pendingPullIntos").peek(); - - if (firstDescriptor.byteOffset + firstDescriptor.bytesFilled !== view.byteOffset) - @throwRangeError("Invalid value for view.byteOffset"); - - if (firstDescriptor.byteLength !== view.byteLength) - @throwRangeError("Invalid value for view.byteLength"); - - firstDescriptor.buffer = view.buffer; - @readableByteStreamControllerRespondInternal(controller, view.byteLength); -} - -function readableByteStreamControllerRespond(controller, bytesWritten) -{ - "use strict"; - - bytesWritten = @toNumber(bytesWritten); - - if (@isNaN(bytesWritten) || bytesWritten === @Infinity || bytesWritten < 0 ) - @throwRangeError("bytesWritten has an incorrect value"); - - @assert(@getByIdDirectPrivate(controller, "pendingPullIntos").isNotEmpty()); - - @readableByteStreamControllerRespondInternal(controller, bytesWritten); -} - -function readableByteStreamControllerRespondInternal(controller, bytesWritten) -{ - "use strict"; - - let firstDescriptor = @getByIdDirectPrivate(controller, "pendingPullIntos").peek(); - let stream = @getByIdDirectPrivate(controller, "controlledReadableStream"); - - if (@getByIdDirectPrivate(stream, "state") === @streamClosed) { - if (bytesWritten !== 0) - @throwTypeError("bytesWritten is different from 0 even though stream is closed"); - @readableByteStreamControllerRespondInClosedState(controller, firstDescriptor); - } else { - @assert(@getByIdDirectPrivate(stream, "state") === @streamReadable); - @readableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor); - } -} - -function readableByteStreamControllerRespondInReadableState(controller, bytesWritten, pullIntoDescriptor) -{ - "use strict"; - - if (pullIntoDescriptor.bytesFilled + bytesWritten > pullIntoDescriptor.byteLength) - @throwRangeError("bytesWritten value is too great"); - - @assert(@getByIdDirectPrivate(controller, "pendingPullIntos").isEmpty() || @getByIdDirectPrivate(controller, "pendingPullIntos").peek() === pullIntoDescriptor); - @readableByteStreamControllerInvalidateBYOBRequest(controller); - pullIntoDescriptor.bytesFilled += bytesWritten; - - if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) - return; - - @readableByteStreamControllerShiftPendingDescriptor(controller); - const remainderSize = pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize; - - if (remainderSize > 0) { - const end = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled; - const remainder = @cloneArrayBuffer(pullIntoDescriptor.buffer, end - remainderSize, remainderSize); - @readableByteStreamControllerEnqueueChunk(controller, remainder, 0, remainder.byteLength); - } - - pullIntoDescriptor.buffer = @transferBufferToCurrentRealm(pullIntoDescriptor.buffer); - pullIntoDescriptor.bytesFilled -= remainderSize; - @readableByteStreamControllerCommitDescriptor(@getByIdDirectPrivate(controller, "controlledReadableStream"), pullIntoDescriptor); - @readableByteStreamControllerProcessPullDescriptors(controller); -} - -function readableByteStreamControllerRespondInClosedState(controller, firstDescriptor) -{ - "use strict"; - - firstDescriptor.buffer = @transferBufferToCurrentRealm(firstDescriptor.buffer); - @assert(firstDescriptor.bytesFilled === 0); - - if (@readableStreamHasBYOBReader(@getByIdDirectPrivate(controller, "controlledReadableStream"))) { - while (@getByIdDirectPrivate(@getByIdDirectPrivate(@getByIdDirectPrivate(controller, "controlledReadableStream"), "reader"), "readIntoRequests")?.isNotEmpty()) { - let pullIntoDescriptor = @readableByteStreamControllerShiftPendingDescriptor(controller); - @readableByteStreamControllerCommitDescriptor(@getByIdDirectPrivate(controller, "controlledReadableStream"), pullIntoDescriptor); - } - } -} - -// Spec name: readableByteStreamControllerProcessPullIntoDescriptorsUsingQueue (shortened for readability). -function readableByteStreamControllerProcessPullDescriptors(controller) -{ - "use strict"; - - @assert(!@getByIdDirectPrivate(controller, "closeRequested")); - while (@getByIdDirectPrivate(controller, "pendingPullIntos").isNotEmpty()) { - if (@getByIdDirectPrivate(controller, "queue").size === 0) - return; - let pullIntoDescriptor = @getByIdDirectPrivate(controller, "pendingPullIntos").peek(); - if (@readableByteStreamControllerFillDescriptorFromQueue(controller, pullIntoDescriptor)) { - @readableByteStreamControllerShiftPendingDescriptor(controller); - @readableByteStreamControllerCommitDescriptor(@getByIdDirectPrivate(controller, "controlledReadableStream"), pullIntoDescriptor); - } - } -} - -// Spec name: readableByteStreamControllerFillPullIntoDescriptorFromQueue (shortened for readability). -function readableByteStreamControllerFillDescriptorFromQueue(controller, pullIntoDescriptor) -{ - "use strict"; - - const currentAlignedBytes = pullIntoDescriptor.bytesFilled - (pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize); - const maxBytesToCopy = @getByIdDirectPrivate(controller, "queue").size < pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled ? - @getByIdDirectPrivate(controller, "queue").size : pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled; - const maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy; - const maxAlignedBytes = maxBytesFilled - (maxBytesFilled % pullIntoDescriptor.elementSize); - let totalBytesToCopyRemaining = maxBytesToCopy; - let ready = false; - - if (maxAlignedBytes > currentAlignedBytes) { - totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; - ready = true; - } - - while (totalBytesToCopyRemaining > 0) { - let headOfQueue = @getByIdDirectPrivate(controller, "queue").content.peek(); - const bytesToCopy = totalBytesToCopyRemaining < headOfQueue.byteLength ? totalBytesToCopyRemaining : headOfQueue.byteLength; - // Copy appropriate part of pullIntoDescriptor.buffer to headOfQueue.buffer. - // Remark: this implementation is not completely aligned on the definition of CopyDataBlockBytes - // operation of ECMAScript (the case of Shared Data Block is not considered here, but it doesn't seem to be an issue). - const destStart = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled; - // FIXME: As indicated in comments of bug 172717, access to set is not safe. However, using prototype.@set.@call does - // not work (@set is undefined). A safe way to do that is needed. - new @Uint8Array(pullIntoDescriptor.buffer).set(new @Uint8Array(headOfQueue.buffer, headOfQueue.byteOffset, bytesToCopy), destStart); - - if (headOfQueue.byteLength === bytesToCopy) - @getByIdDirectPrivate(controller, "queue").content.shift(); - else { - headOfQueue.byteOffset += bytesToCopy; - headOfQueue.byteLength -= bytesToCopy; - } - - @getByIdDirectPrivate(controller, "queue").size -= bytesToCopy; - @assert(@getByIdDirectPrivate(controller, "pendingPullIntos").isEmpty() || @getByIdDirectPrivate(controller, "pendingPullIntos").peek() === pullIntoDescriptor); - @readableByteStreamControllerInvalidateBYOBRequest(controller); - pullIntoDescriptor.bytesFilled += bytesToCopy; - totalBytesToCopyRemaining -= bytesToCopy; - } - - if (!ready) { - @assert(@getByIdDirectPrivate(controller, "queue").size === 0); - @assert(pullIntoDescriptor.bytesFilled > 0); - @assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize); - } - - return ready; -} - -// Spec name: readableByteStreamControllerShiftPendingPullInto (renamed for consistency). -function readableByteStreamControllerShiftPendingDescriptor(controller) -{ - "use strict"; - - let descriptor = @getByIdDirectPrivate(controller, "pendingPullIntos").shift(); - @readableByteStreamControllerInvalidateBYOBRequest(controller); - return descriptor; -} - -function readableByteStreamControllerInvalidateBYOBRequest(controller) -{ - "use strict"; - - if (@getByIdDirectPrivate(controller, "byobRequest") === @undefined) - return; - const byobRequest = @getByIdDirectPrivate(controller, "byobRequest"); - @putByIdDirectPrivate(byobRequest, "associatedReadableByteStreamController", @undefined); - @putByIdDirectPrivate(byobRequest, "view", @undefined); - @putByIdDirectPrivate(controller, "byobRequest", @undefined); -} - -// Spec name: readableByteStreamControllerCommitPullIntoDescriptor (shortened for readability). -function readableByteStreamControllerCommitDescriptor(stream, pullIntoDescriptor) -{ - "use strict"; - - @assert(@getByIdDirectPrivate(stream, "state") !== @streamErrored); - let done = false; - if (@getByIdDirectPrivate(stream, "state") === @streamClosed) { - @assert(!pullIntoDescriptor.bytesFilled); - done = true; - } - let filledView = @readableByteStreamControllerConvertDescriptor(pullIntoDescriptor); - if (pullIntoDescriptor.readerType === "default") - @readableStreamFulfillReadRequest(stream, filledView, done); - else { - @assert(pullIntoDescriptor.readerType === "byob"); - @readableStreamFulfillReadIntoRequest(stream, filledView, done); - } -} - -// Spec name: readableByteStreamControllerConvertPullIntoDescriptor (shortened for readability). -function readableByteStreamControllerConvertDescriptor(pullIntoDescriptor) -{ - "use strict"; - - @assert(pullIntoDescriptor.bytesFilled <= pullIntoDescriptor.byteLength); - @assert(pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize === 0); - - return new pullIntoDescriptor.ctor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, pullIntoDescriptor.bytesFilled / pullIntoDescriptor.elementSize); -} - -function readableStreamFulfillReadIntoRequest(stream, chunk, done) -{ - "use strict"; - const readIntoRequest = @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readIntoRequests").shift(); - @fulfillPromise(readIntoRequest, { value: chunk, done: done }); -} - -function readableStreamBYOBReaderRead(reader, view) -{ - "use strict"; - - const stream = @getByIdDirectPrivate(reader, "ownerReadableStream"); - @assert(!!stream); - - @putByIdDirectPrivate(stream, "disturbed", true); - if (@getByIdDirectPrivate(stream, "state") === @streamErrored) - return @Promise.@reject(@getByIdDirectPrivate(stream, "storedError")); - - return @readableByteStreamControllerPullInto(@getByIdDirectPrivate(stream, "readableStreamController"), view); -} - -function readableByteStreamControllerPullInto(controller, view) -{ - "use strict"; - - const stream = @getByIdDirectPrivate(controller, "controlledReadableStream"); - let elementSize = 1; - // Spec describes that in the case where view is a TypedArray, elementSize - // should be set to the size of an element (e.g. 2 for UInt16Array). For - // DataView, BYTES_PER_ELEMENT is undefined, contrary to the same property - // for TypedArrays. - // FIXME: Getting BYTES_PER_ELEMENT like this is not safe (property is read-only - // but can be modified if the prototype is redefined). A safe way of getting - // it would be to determine which type of ArrayBufferView view is an instance - // of based on typed arrays private variables. However, this is not possible due - // to bug 167697, which prevents access to typed arrays through their private - // names unless public name has already been met before. - if (view.BYTES_PER_ELEMENT !== @undefined) - elementSize = view.BYTES_PER_ELEMENT; - - // FIXME: Getting constructor like this is not safe. A safe way of getting - // it would be to determine which type of ArrayBufferView view is an instance - // of, and to assign appropriate constructor based on this (e.g. ctor = - // @Uint8Array). However, this is not possible due to bug 167697, which - // prevents access to typed arrays through their private names unless public - // name has already been met before. - const ctor = view.constructor; - - const pullIntoDescriptor = { - buffer: view.buffer, - byteOffset: view.byteOffset, - byteLength: view.byteLength, - bytesFilled: 0, - elementSize, - ctor, - readerType: 'byob' - }; - - var pending = @getByIdDirectPrivate(controller, "pendingPullIntos"); - if (pending?.isNotEmpty()) { - pullIntoDescriptor.buffer = @transferBufferToCurrentRealm(pullIntoDescriptor.buffer); - pending.push(pullIntoDescriptor); - return @readableStreamAddReadIntoRequest(stream); - } - - if (@getByIdDirectPrivate(stream, "state") === @streamClosed) { - const emptyView = new ctor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, 0); - return @createFulfilledPromise({ value: emptyView, done: true }); - } - - if (@getByIdDirectPrivate(controller, "queue").size > 0) { - if (@readableByteStreamControllerFillDescriptorFromQueue(controller, pullIntoDescriptor)) { - const filledView = @readableByteStreamControllerConvertDescriptor(pullIntoDescriptor); - @readableByteStreamControllerHandleQueueDrain(controller); - return @createFulfilledPromise({ value: filledView, done: false }); - } - if (@getByIdDirectPrivate(controller, "closeRequested")) { - const e = @makeTypeError("Closing stream has been requested"); - @readableByteStreamControllerError(controller, e); - return @Promise.@reject(e); - } - } - - pullIntoDescriptor.buffer = @transferBufferToCurrentRealm(pullIntoDescriptor.buffer); - @getByIdDirectPrivate(controller, "pendingPullIntos").push(pullIntoDescriptor); - const promise = @readableStreamAddReadIntoRequest(stream); - @readableByteStreamControllerCallPullIfNeeded(controller); - return promise; -} - -function readableStreamAddReadIntoRequest(stream) -{ - "use strict"; - - @assert(@isReadableStreamBYOBReader(@getByIdDirectPrivate(stream, "reader"))); - @assert(@getByIdDirectPrivate(stream, "state") === @streamReadable || @getByIdDirectPrivate(stream, "state") === @streamClosed); - - const readRequest = @newPromise(); - @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readIntoRequests").push(readRequest); - - return readRequest; -} diff --git a/src/bun.js/builtins/js/ReadableStream.js b/src/bun.js/builtins/js/ReadableStream.js deleted file mode 100644 index 1449c836d..000000000 --- a/src/bun.js/builtins/js/ReadableStream.js +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (C) 2015 Canon Inc. - * Copyright (C) 2015 Igalia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -function initializeReadableStream(underlyingSource, strategy) -{ - "use strict"; - - if (underlyingSource === @undefined) - underlyingSource = { @bunNativeType: 0, @bunNativePtr: 0, @lazy: false }; - if (strategy === @undefined) - strategy = { }; - - if (!@isObject(underlyingSource)) - @throwTypeError("ReadableStream constructor takes an object as first argument"); - - if (strategy !== @undefined && !@isObject(strategy)) - @throwTypeError("ReadableStream constructor takes an object as second argument, if any"); - - @putByIdDirectPrivate(this, "state", @streamReadable); - - @putByIdDirectPrivate(this, "reader", @undefined); - - @putByIdDirectPrivate(this, "storedError", @undefined); - - @putByIdDirectPrivate(this, "disturbed", false); - - - // Initialized with null value to enable distinction with undefined case. - @putByIdDirectPrivate(this, "readableStreamController", null); - @putByIdDirectPrivate(this, "bunNativeType", @getByIdDirectPrivate(underlyingSource, "bunNativeType") ?? 0); - @putByIdDirectPrivate(this, "bunNativePtr", @getByIdDirectPrivate(underlyingSource, "bunNativePtr") ?? 0); - - const isDirect = underlyingSource.type === "direct"; - // direct streams are always lazy - const isUnderlyingSourceLazy = !!underlyingSource.@lazy; - const isLazy = isDirect || isUnderlyingSourceLazy; - - // // FIXME: We should introduce https://streams.spec.whatwg.org/#create-readable-stream. - // // For now, we emulate this with underlyingSource with private properties. - if (@getByIdDirectPrivate(underlyingSource, "pull") !== @undefined && !isLazy) { - const size = @getByIdDirectPrivate(strategy, "size"); - const highWaterMark = @getByIdDirectPrivate(strategy, "highWaterMark"); - @putByIdDirectPrivate(this, "highWaterMark", highWaterMark); - @putByIdDirectPrivate(this, "underlyingSource", @undefined); - @setupReadableStreamDefaultController(this, underlyingSource, size, highWaterMark !== @undefined ? highWaterMark : 1, @getByIdDirectPrivate(underlyingSource, "start"), @getByIdDirectPrivate(underlyingSource, "pull"), @getByIdDirectPrivate(underlyingSource, "cancel")); - - return this; - } - if (isDirect) { - @putByIdDirectPrivate(this, "underlyingSource", underlyingSource); - @putByIdDirectPrivate(this, "highWaterMark", @getByIdDirectPrivate(strategy, "highWaterMark")); - @putByIdDirectPrivate(this, "start", () => @createReadableStreamController(this, underlyingSource, strategy)); - } else if (isLazy) { - const autoAllocateChunkSize = underlyingSource.autoAllocateChunkSize; - @putByIdDirectPrivate(this, "highWaterMark", @undefined); - @putByIdDirectPrivate(this, "underlyingSource", @undefined); - @putByIdDirectPrivate(this, "highWaterMark", autoAllocateChunkSize || @getByIdDirectPrivate(strategy, "highWaterMark")); - - - @putByIdDirectPrivate(this, "start", () => { - const instance = @lazyLoadStream(this, autoAllocateChunkSize); - if (instance) { - @createReadableStreamController(this, instance, strategy); - } - }); - } else { - @putByIdDirectPrivate(this, "underlyingSource", @undefined); - @putByIdDirectPrivate(this, "highWaterMark", @getByIdDirectPrivate(strategy, "highWaterMark")); - @putByIdDirectPrivate(this, "start", @undefined); - @createReadableStreamController(this, underlyingSource, strategy); - } - - - return this; -} - - -@linkTimeConstant -function readableStreamToArray(stream) { - "use strict"; - - // this is a direct stream - var underlyingSource = @getByIdDirectPrivate(stream, "underlyingSource"); - if (underlyingSource !== @undefined) { - return @readableStreamToArrayDirect(stream, underlyingSource); - } - - return @readableStreamIntoArray(stream); -} - -@linkTimeConstant -function readableStreamToText(stream) { - "use strict"; - - // this is a direct stream - var underlyingSource = @getByIdDirectPrivate(stream, "underlyingSource"); - if (underlyingSource !== @undefined) { - return @readableStreamToTextDirect(stream, underlyingSource); - } - - return @readableStreamIntoText(stream); -} - -@linkTimeConstant -function readableStreamToArrayBuffer(stream) { - "use strict"; - - // this is a direct stream - var underlyingSource = @getByIdDirectPrivate(stream, "underlyingSource"); - - if (underlyingSource !== @undefined) { - return @readableStreamToArrayBufferDirect(stream, underlyingSource); - } - - return @Bun.readableStreamToArray(stream).@then(@Bun.concatArrayBuffers); -} - -@linkTimeConstant -function readableStreamToJSON(stream) { - "use strict"; - - return @Bun.readableStreamToText(stream).@then(globalThis.JSON.parse); -} - -@linkTimeConstant -function readableStreamToBlob(stream) { - "use strict"; - return @Promise.resolve(@Bun.readableStreamToArray(stream)).@then(array => new Blob(array)); -} - -@linkTimeConstant -function consumeReadableStream(nativePtr, nativeType, inputStream) { - "use strict"; - const symbol = globalThis.Symbol.for("Bun.consumeReadableStreamPrototype"); - var cached = globalThis[symbol]; - if (!cached) { - cached = globalThis[symbol] = []; - } - var Prototype = cached[nativeType]; - if (Prototype === @undefined) { - var [doRead, doError, doReadMany, doClose, onClose, deinit] = globalThis[globalThis.Symbol.for("Bun.lazy")](nativeType); - - Prototype = class NativeReadableStreamSink { - constructor(reader, ptr) { - this.#ptr = ptr; - this.#reader = reader; - this.#didClose = false; - - this.handleError = this._handleError.bind(this); - this.handleClosed = this._handleClosed.bind(this); - this.processResult = this._processResult.bind(this); - - reader.closed.then(this.handleClosed, this.handleError); - } - - handleError; - handleClosed; - _handleClosed() { - if (this.#didClose) return; - this.#didClose = true; - var ptr = this.#ptr; - this.#ptr = 0; - doClose(ptr); - deinit(ptr); - } - - _handleError(error) { - if (this.#didClose) return; - this.#didClose = true; - var ptr = this.#ptr; - this.#ptr = 0; - doError(ptr, error); - deinit(ptr); - } - - #ptr; - #didClose = false; - #reader; - - _handleReadMany({value, done, size}) { - if (done) { - this.handleClosed(); - return; - } - - if (this.#didClose) return; - - - doReadMany(this.#ptr, value, done, size); - } - - - read() { - if (!this.#ptr) return @throwTypeError("ReadableStreamSink is already closed"); - - return this.processResult(this.#reader.read()); - - } - - _processResult(result) { - if (result && @isPromise(result)) { - const flags = @getPromiseInternalField(result, @promiseFieldFlags); - if (flags & @promiseStateFulfilled) { - const fulfilledValue = @getPromiseInternalField(result, @promiseFieldReactionsOrResult); - if (fulfilledValue) { - result = fulfilledValue; - } - } - } - - if (result && @isPromise(result)) { - result.then(this.processResult, this.handleError); - return null; - } - - if (result.done) { - this.handleClosed(); - return 0; - } else if (result.value) { - return result.value; - } else { - return -1; - } - - - } - - readMany() { - if (!this.#ptr) return @throwTypeError("ReadableStreamSink is already closed"); - return this.processResult(this.#reader.readMany()); - } - - - }; - - const minlength = nativeType + 1; - if (cached.length < minlength) { - cached.length = minlength; - } - @putByValDirect(cached, nativeType, Prototype); - } - - if (@isReadableStreamLocked(inputStream)) { - @throwTypeError("Cannot start reading from a locked stream"); - } - - return new Prototype(inputStream.getReader(), nativePtr); -} - -@linkTimeConstant -function createEmptyReadableStream() { - "use strict"; - - var stream = new @ReadableStream({ - pull() {}, - }); - @readableStreamClose(stream); - return stream; -} - -@linkTimeConstant -function createNativeReadableStream(nativePtr, nativeType, autoAllocateChunkSize) { - "use strict"; - return new @ReadableStream({ - @lazy: true, - @bunNativeType: nativeType, - @bunNativePtr: nativePtr, - autoAllocateChunkSize: autoAllocateChunkSize, - }); -} - -function cancel(reason) -{ - "use strict"; - - if (!@isReadableStream(this)) - return @Promise.@reject(@makeThisTypeError("ReadableStream", "cancel")); - - if (@isReadableStreamLocked(this)) - return @Promise.@reject(@makeTypeError("ReadableStream is locked")); - - return @readableStreamCancel(this, reason); -} - -function getReader(options) -{ - "use strict"; - - if (!@isReadableStream(this)) - throw @makeThisTypeError("ReadableStream", "getReader"); - - const mode = @toDictionary(options, { }, "ReadableStream.getReader takes an object as first argument").mode; - if (mode === @undefined) { - var start_ = @getByIdDirectPrivate(this, "start"); - if (start_) { - @putByIdDirectPrivate(this, "start", @undefined); - start_(); - } - - return new @ReadableStreamDefaultReader(this); - } - // String conversion is required by spec, hence double equals. - if (mode == 'byob') { - return new @ReadableStreamBYOBReader(this); - } - - - @throwTypeError("Invalid mode is specified"); -} - -function pipeThrough(streams, options) -{ - "use strict"; - - const transforms = streams; - - const readable = transforms["readable"]; - if (!@isReadableStream(readable)) - throw @makeTypeError("readable should be ReadableStream"); - - const writable = transforms["writable"]; - const internalWritable = @getInternalWritableStream(writable); - if (!@isWritableStream(internalWritable)) - throw @makeTypeError("writable should be WritableStream"); - - let preventClose = false; - let preventAbort = false; - let preventCancel = false; - let signal; - if (!@isUndefinedOrNull(options)) { - if (!@isObject(options)) - throw @makeTypeError("options must be an object"); - - preventAbort = !!options["preventAbort"]; - preventCancel = !!options["preventCancel"]; - preventClose = !!options["preventClose"]; - - signal = options["signal"]; - if (signal !== @undefined && !@isAbortSignal(signal)) - throw @makeTypeError("options.signal must be AbortSignal"); - } - - if (!@isReadableStream(this)) - throw @makeThisTypeError("ReadableStream", "pipeThrough"); - - if (@isReadableStreamLocked(this)) - throw @makeTypeError("ReadableStream is locked"); - - if (@isWritableStreamLocked(internalWritable)) - throw @makeTypeError("WritableStream is locked"); - - @readableStreamPipeToWritableStream(this, internalWritable, preventClose, preventAbort, preventCancel, signal); - - return readable; -} - -function pipeTo(destination) -{ - "use strict"; - if (!@isReadableStream(this)) - return @Promise.@reject(@makeThisTypeError("ReadableStream", "pipeTo")); - - if (@isReadableStreamLocked(this)) - return @Promise.@reject(@makeTypeError("ReadableStream is locked")); - - // FIXME: https://bugs.webkit.org/show_bug.cgi?id=159869. - // Built-in generator should be able to parse function signature to compute the function length correctly. - let options = @argument(1); - - let preventClose = false; - let preventAbort = false; - let preventCancel = false; - let signal; - if (!@isUndefinedOrNull(options)) { - if (!@isObject(options)) - return @Promise.@reject(@makeTypeError("options must be an object")); - - try { - preventAbort = !!options["preventAbort"]; - preventCancel = !!options["preventCancel"]; - preventClose = !!options["preventClose"]; - - signal = options["signal"]; - } catch(e) { - return @Promise.@reject(e); - } - - if (signal !== @undefined && !@isAbortSignal(signal)) - return @Promise.@reject(@makeTypeError("options.signal must be AbortSignal")); - } - - const internalDestination = @getInternalWritableStream(destination); - if (!@isWritableStream(internalDestination)) - return @Promise.@reject(@makeTypeError("ReadableStream pipeTo requires a WritableStream")); - - if (@isWritableStreamLocked(internalDestination)) - return @Promise.@reject(@makeTypeError("WritableStream is locked")); - - return @readableStreamPipeToWritableStream(this, internalDestination, preventClose, preventAbort, preventCancel, signal); -} - -function tee() -{ - "use strict"; - - if (!@isReadableStream(this)) - throw @makeThisTypeError("ReadableStream", "tee"); - - return @readableStreamTee(this, false); -} - -@getter -function locked() -{ - "use strict"; - - if (!@isReadableStream(this)) - throw @makeGetterTypeError("ReadableStream", "locked"); - - return @isReadableStreamLocked(this); -} - -function values(options) { - "use strict"; - var prototype = @ReadableStream.prototype; - @readableStreamDefineLazyIterators(prototype); - return prototype.values.@call(this, options); -} - -@linkTimeConstant -function lazyAsyncIterator() { - "use strict"; - var prototype = @ReadableStream.prototype; - @readableStreamDefineLazyIterators(prototype); - return prototype[globalThis.Symbol.asyncIterator].@call(this); -}
\ No newline at end of file diff --git a/src/bun.js/builtins/js/ReadableStreamBYOBReader.js b/src/bun.js/builtins/js/ReadableStreamBYOBReader.js deleted file mode 100644 index 16e4ebce5..000000000 --- a/src/bun.js/builtins/js/ReadableStreamBYOBReader.js +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2017 Canon Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -function initializeReadableStreamBYOBReader(stream) -{ - "use strict"; - - if (!@isReadableStream(stream)) - @throwTypeError("ReadableStreamBYOBReader needs a ReadableStream"); - if (!@isReadableByteStreamController(@getByIdDirectPrivate(stream, "readableStreamController"))) - @throwTypeError("ReadableStreamBYOBReader needs a ReadableByteStreamController"); - if (@isReadableStreamLocked(stream)) - @throwTypeError("ReadableStream is locked"); - - @readableStreamReaderGenericInitialize(this, stream); - @putByIdDirectPrivate(this, "readIntoRequests", @createFIFO()); - - return this; -} - -function cancel(reason) -{ - "use strict"; - - if (!@isReadableStreamBYOBReader(this)) - return @Promise.@reject(@makeThisTypeError("ReadableStreamBYOBReader", "cancel")); - - if (!@getByIdDirectPrivate(this, "ownerReadableStream")) - return @Promise.@reject(@makeTypeError("cancel() called on a reader owned by no readable stream")); - - return @readableStreamReaderGenericCancel(this, reason); -} - -function read(view) -{ - "use strict"; - - if (!@isReadableStreamBYOBReader(this)) - return @Promise.@reject(@makeThisTypeError("ReadableStreamBYOBReader", "read")); - - if (!@getByIdDirectPrivate(this, "ownerReadableStream")) - return @Promise.@reject(@makeTypeError("read() called on a reader owned by no readable stream")); - - if (!@isObject(view)) - return @Promise.@reject(@makeTypeError("Provided view is not an object")); - - if (!@ArrayBuffer.@isView(view)) - return @Promise.@reject(@makeTypeError("Provided view is not an ArrayBufferView")); - - if (view.byteLength === 0) - return @Promise.@reject(@makeTypeError("Provided view cannot have a 0 byteLength")); - - return @readableStreamBYOBReaderRead(this, view); -} - -function releaseLock() -{ - "use strict"; - - if (!@isReadableStreamBYOBReader(this)) - throw @makeThisTypeError("ReadableStreamBYOBReader", "releaseLock"); - - if (!@getByIdDirectPrivate(this, "ownerReadableStream")) - return; - - if (@getByIdDirectPrivate(this, "readIntoRequests")?.isNotEmpty()) - @throwTypeError("There are still pending read requests, cannot release the lock"); - - @readableStreamReaderGenericRelease(this); -} - -@getter -function closed() -{ - "use strict"; - - if (!@isReadableStreamBYOBReader(this)) - return @Promise.@reject(@makeGetterTypeError("ReadableStreamBYOBReader", "closed")); - - return @getByIdDirectPrivate(this, "closedPromiseCapability").@promise; -} diff --git a/src/bun.js/builtins/js/ReadableStreamBYOBRequest.js b/src/bun.js/builtins/js/ReadableStreamBYOBRequest.js deleted file mode 100644 index d97667165..000000000 --- a/src/bun.js/builtins/js/ReadableStreamBYOBRequest.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2017 Canon Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -function initializeReadableStreamBYOBRequest(controller, view) -{ - "use strict"; - - if (arguments.length !== 3 && arguments[2] !== @isReadableStream) - @throwTypeError("ReadableStreamBYOBRequest constructor should not be called directly"); - - return @privateInitializeReadableStreamBYOBRequest.@call(this, controller, view); -} - -function respond(bytesWritten) -{ - "use strict"; - - if (!@isReadableStreamBYOBRequest(this)) - throw @makeThisTypeError("ReadableStreamBYOBRequest", "respond"); - - if (@getByIdDirectPrivate(this, "associatedReadableByteStreamController") === @undefined) - @throwTypeError("ReadableStreamBYOBRequest.associatedReadableByteStreamController is undefined"); - - return @readableByteStreamControllerRespond(@getByIdDirectPrivate(this, "associatedReadableByteStreamController"), bytesWritten); -} - -function respondWithNewView(view) -{ - "use strict"; - - if (!@isReadableStreamBYOBRequest(this)) - throw @makeThisTypeError("ReadableStreamBYOBRequest", "respond"); - - if (@getByIdDirectPrivate(this, "associatedReadableByteStreamController") === @undefined) - @throwTypeError("ReadableStreamBYOBRequest.associatedReadableByteStreamController is undefined"); - - if (!@isObject(view)) - @throwTypeError("Provided view is not an object"); - - if (!@ArrayBuffer.@isView(view)) - @throwTypeError("Provided view is not an ArrayBufferView"); - - return @readableByteStreamControllerRespondWithNewView(@getByIdDirectPrivate(this, "associatedReadableByteStreamController"), view); -} - -@getter -function view() -{ - "use strict"; - - if (!@isReadableStreamBYOBRequest(this)) - throw @makeGetterTypeError("ReadableStreamBYOBRequest", "view"); - - return @getByIdDirectPrivate(this, "view"); -} diff --git a/src/bun.js/builtins/js/ReadableStreamDefaultController.js b/src/bun.js/builtins/js/ReadableStreamDefaultController.js deleted file mode 100644 index 07fc65cb1..000000000 --- a/src/bun.js/builtins/js/ReadableStreamDefaultController.js +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2015 Canon Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -function initializeReadableStreamDefaultController(stream, underlyingSource, size, highWaterMark) -{ - "use strict"; - - if (arguments.length !== 5 && arguments[4] !== @isReadableStream) - @throwTypeError("ReadableStreamDefaultController constructor should not be called directly"); - - return @privateInitializeReadableStreamDefaultController.@call(this, stream, underlyingSource, size, highWaterMark); -} - -function enqueue(chunk) -{ - "use strict"; - - if (!@isReadableStreamDefaultController(this)) - throw @makeThisTypeError("ReadableStreamDefaultController", "enqueue"); - - if (!@readableStreamDefaultControllerCanCloseOrEnqueue(this)) - @throwTypeError("ReadableStreamDefaultController is not in a state where chunk can be enqueued"); - - return @readableStreamDefaultControllerEnqueue(this, chunk); -} - -function error(error) -{ - "use strict"; - - if (!@isReadableStreamDefaultController(this)) - throw @makeThisTypeError("ReadableStreamDefaultController", "error"); - - @readableStreamDefaultControllerError(this, error); -} - -function close() -{ - "use strict"; - - if (!@isReadableStreamDefaultController(this)) - throw @makeThisTypeError("ReadableStreamDefaultController", "close"); - - if (!@readableStreamDefaultControllerCanCloseOrEnqueue(this)) - @throwTypeError("ReadableStreamDefaultController is not in a state where it can be closed"); - - @readableStreamDefaultControllerClose(this); -} - -@getter -function desiredSize() -{ - "use strict"; - - if (!@isReadableStreamDefaultController(this)) - throw @makeGetterTypeError("ReadableStreamDefaultController", "desiredSize"); - - return @readableStreamDefaultControllerGetDesiredSize(this); -} - diff --git a/src/bun.js/builtins/js/ReadableStreamDefaultReader.js b/src/bun.js/builtins/js/ReadableStreamDefaultReader.js deleted file mode 100644 index 77da965ed..000000000 --- a/src/bun.js/builtins/js/ReadableStreamDefaultReader.js +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2015 Canon Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -function initializeReadableStreamDefaultReader(stream) -{ - "use strict"; - - if (!@isReadableStream(stream)) - @throwTypeError("ReadableStreamDefaultReader needs a ReadableStream"); - if (@isReadableStreamLocked(stream)) - @throwTypeError("ReadableStream is locked"); - - @readableStreamReaderGenericInitialize(this, stream); - @putByIdDirectPrivate(this, "readRequests", @createFIFO()); - - return this; -} - -function cancel(reason) -{ - "use strict"; - - if (!@isReadableStreamDefaultReader(this)) - return @Promise.@reject(@makeThisTypeError("ReadableStreamDefaultReader", "cancel")); - - if (!@getByIdDirectPrivate(this, "ownerReadableStream")) - return @Promise.@reject(@makeTypeError("cancel() called on a reader owned by no readable stream")); - - return @readableStreamReaderGenericCancel(this, reason); -} - -function readMany() -{ - "use strict"; - - if (!@isReadableStreamDefaultReader(this)) - @throwTypeError("ReadableStreamDefaultReader.readMany() should not be called directly"); - - const stream = @getByIdDirectPrivate(this, "ownerReadableStream"); - if (!stream) - @throwTypeError("readMany() called on a reader owned by no readable stream"); - - const state = @getByIdDirectPrivate(stream, "state"); - @putByIdDirectPrivate(stream, "disturbed", true); - if (state === @streamClosed) - return {value: [], size: 0, done: true}; - else if (state === @streamErrored) { - throw @getByIdDirectPrivate(stream, "storedError"); - } - - - var controller = @getByIdDirectPrivate(stream, "readableStreamController"); - var queue = @getByIdDirectPrivate(controller, "queue"); - - if (!queue) { - // This is a ReadableStream direct controller implemented in JS - // It hasn't been started yet. - return controller.@pull( - controller - ).@then( - function({done, value}) { - return ( - done ? - { done: true, value: [], size: 0 } : - { value: [value], size: 1, done: false } - ); - } - ); - } - - const content = queue.content; - var size = queue.size; - var values = content.toArray(false); - - var length = values.length; - - if (length > 0) { - var outValues = @newArrayWithSize(length); - if (@isReadableByteStreamController(controller)) { - - { - const buf = values[0]; - if (!(@ArrayBuffer.@isView(buf) || buf instanceof @ArrayBuffer)) { - @putByValDirect(outValues, 0, new @Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)); - } else { - @putByValDirect(outValues, 0, buf); - } - } - - for (var i = 1; i < length; i++) { - const buf = values[i]; - if (!(@ArrayBuffer.@isView(buf) || buf instanceof @ArrayBuffer)) { - @putByValDirect(outValues, i, new @Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)); - } else { - @putByValDirect(outValues, i, buf); - } - } - - } else { - @putByValDirect(outValues, 0, values[0].value); - for (var i = 1; i < length; i++) { - @putByValDirect(outValues, i, values[i].value); - } - } - - @resetQueue(@getByIdDirectPrivate(controller, "queue")); - - if (@getByIdDirectPrivate(controller, "closeRequested")) - @readableStreamClose(@getByIdDirectPrivate(controller, "controlledReadableStream")); - else if (@isReadableStreamDefaultController(controller)) - @readableStreamDefaultControllerCallPullIfNeeded(controller); - else if (@isReadableByteStreamController(controller)) - @readableByteStreamControllerCallPullIfNeeded(controller); - - return {value: outValues, size, done: false}; - } - - var onPullMany = (result) => { - if (result.done) { - return {value: [], size: 0, done: true}; - } - var controller = @getByIdDirectPrivate(stream, "readableStreamController"); - - var queue = @getByIdDirectPrivate(controller, "queue"); - var value = [result.value].concat(queue.content.toArray(false)); - var length = value.length; - - if (@isReadableByteStreamController(controller)) { - for (var i = 0; i < length; i++) { - const buf = value[i]; - if (!(@ArrayBuffer.@isView(buf) || buf instanceof @ArrayBuffer)) { - const {buffer, byteOffset, byteLength} = buf; - @putByValDirect(value, i, new @Uint8Array(buffer, byteOffset, byteLength)); - } - } - } else { - for (var i = 1; i < length; i++) { - @putByValDirect(value, i, value[i].value); - } - } - - var size = queue.size; - @resetQueue(queue); - - if (@getByIdDirectPrivate(controller, "closeRequested")) - @readableStreamClose(@getByIdDirectPrivate(controller, "controlledReadableStream")); - else if (@isReadableStreamDefaultController(controller)) - @readableStreamDefaultControllerCallPullIfNeeded(controller); - else if (@isReadableByteStreamController(controller)) - @readableByteStreamControllerCallPullIfNeeded(controller); - - - - return {value: value, size: size, done: false}; - }; - - var pullResult = controller.@pull(controller); - if (pullResult && @isPromise(pullResult)) { - return pullResult.@then(onPullMany); - } - - return onPullMany(pullResult); -} - -function read() -{ - "use strict"; - - if (!@isReadableStreamDefaultReader(this)) - return @Promise.@reject(@makeThisTypeError("ReadableStreamDefaultReader", "read")); - if (!@getByIdDirectPrivate(this, "ownerReadableStream")) - return @Promise.@reject(@makeTypeError("read() called on a reader owned by no readable stream")); - - return @readableStreamDefaultReaderRead(this); -} - -function releaseLock() -{ - "use strict"; - - if (!@isReadableStreamDefaultReader(this)) - throw @makeThisTypeError("ReadableStreamDefaultReader", "releaseLock"); - - if (!@getByIdDirectPrivate(this, "ownerReadableStream")) - return; - - if (@getByIdDirectPrivate(this, "readRequests")?.isNotEmpty()) - @throwTypeError("There are still pending read requests, cannot release the lock"); - - @readableStreamReaderGenericRelease(this); -} - -@getter -function closed() -{ - "use strict"; - - if (!@isReadableStreamDefaultReader(this)) - return @Promise.@reject(@makeGetterTypeError("ReadableStreamDefaultReader", "closed")); - - return @getByIdDirectPrivate(this, "closedPromiseCapability").@promise; -} diff --git a/src/bun.js/builtins/js/ReadableStreamInternals.js b/src/bun.js/builtins/js/ReadableStreamInternals.js deleted file mode 100644 index ca7a1c355..000000000 --- a/src/bun.js/builtins/js/ReadableStreamInternals.js +++ /dev/null @@ -1,2209 +0,0 @@ -/* - * Copyright (C) 2015 Canon Inc. All rights reserved. - * Copyright (C) 2015 Igalia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// @internal - -function readableStreamReaderGenericInitialize(reader, stream) { - "use strict"; - - @putByIdDirectPrivate(reader, "ownerReadableStream", stream); - @putByIdDirectPrivate(stream, "reader", reader); - if (@getByIdDirectPrivate(stream, "state") === @streamReadable) - @putByIdDirectPrivate( - reader, - "closedPromiseCapability", - @newPromiseCapability(@Promise) - ); - else if (@getByIdDirectPrivate(stream, "state") === @streamClosed) - @putByIdDirectPrivate(reader, "closedPromiseCapability", { - @promise: @Promise.@resolve(), - }); - else { - @assert(@getByIdDirectPrivate(stream, "state") === @streamErrored); - @putByIdDirectPrivate(reader, "closedPromiseCapability", { - @promise: @newHandledRejectedPromise( - @getByIdDirectPrivate(stream, "storedError") - ), - }); - } -} - -function privateInitializeReadableStreamDefaultController( - stream, - underlyingSource, - size, - highWaterMark -) { - "use strict"; - - if (!@isReadableStream(stream)) - @throwTypeError("ReadableStreamDefaultController needs a ReadableStream"); - - // readableStreamController is initialized with null value. - if (@getByIdDirectPrivate(stream, "readableStreamController") !== null) - @throwTypeError("ReadableStream already has a controller"); - - @putByIdDirectPrivate(this, "controlledReadableStream", stream); - @putByIdDirectPrivate(this, "underlyingSource", underlyingSource); - @putByIdDirectPrivate(this, "queue", @newQueue()); - @putByIdDirectPrivate(this, "started", -1); - @putByIdDirectPrivate(this, "closeRequested", false); - @putByIdDirectPrivate(this, "pullAgain", false); - @putByIdDirectPrivate(this, "pulling", false); - @putByIdDirectPrivate( - this, - "strategy", - @validateAndNormalizeQueuingStrategy(size, highWaterMark) - ); - - return this; -} - -function readableStreamDefaultControllerError(controller, error) { - "use strict"; - - const stream = @getByIdDirectPrivate(controller, "controlledReadableStream"); - if (@getByIdDirectPrivate(stream, "state") !== @streamReadable) return; - @putByIdDirectPrivate(controller, "queue", @newQueue()); - - @readableStreamError(stream, error); -} - -function readableStreamPipeTo(stream, sink) { - "use strict"; - @assert(@isReadableStream(stream)); - - const reader = new @ReadableStreamDefaultReader(stream); - - @getByIdDirectPrivate(reader, "closedPromiseCapability").@promise.@then( - () => {}, - (e) => { - sink.error(e); - } - ); - - function doPipe() { - @readableStreamDefaultReaderRead(reader).@then( - function (result) { - if (result.done) { - sink.close(); - return; - } - try { - sink.enqueue(result.value); - } catch (e) { - sink.error("ReadableStream chunk enqueueing in the sink failed"); - return; - } - doPipe(); - }, - function (e) { - sink.error(e); - } - ); - } - doPipe(); -} - -function acquireReadableStreamDefaultReader(stream) { - "use strict"; - var start = @getByIdDirectPrivate(stream, "start"); - if (start) { - start.@call(stream); - } - - return new @ReadableStreamDefaultReader(stream); -} - -// https://streams.spec.whatwg.org/#set-up-readable-stream-default-controller, starting from step 6. -// The other part is implemented in privateInitializeReadableStreamDefaultController. -function setupReadableStreamDefaultController( - stream, - underlyingSource, - size, - highWaterMark, - startMethod, - pullMethod, - cancelMethod -) { - "use strict"; - - const controller = new @ReadableStreamDefaultController( - stream, - underlyingSource, - size, - highWaterMark, - @isReadableStream - ); - - const pullAlgorithm = () => - @promiseInvokeOrNoopMethod(underlyingSource, pullMethod, [controller]); - const cancelAlgorithm = (reason) => - @promiseInvokeOrNoopMethod(underlyingSource, cancelMethod, [reason]); - - @putByIdDirectPrivate(controller, "pullAlgorithm", pullAlgorithm); - @putByIdDirectPrivate(controller, "cancelAlgorithm", cancelAlgorithm); - @putByIdDirectPrivate( - controller, - "pull", - @readableStreamDefaultControllerPull - ); - @putByIdDirectPrivate( - controller, - "cancel", - @readableStreamDefaultControllerCancel - ); - @putByIdDirectPrivate(stream, "readableStreamController", controller); - - @readableStreamDefaultControllerStart(controller); -} - -function createReadableStreamController(stream, underlyingSource, strategy) { - "use strict"; - - const type = underlyingSource.type; - const typeString = @toString(type); - - if (typeString === "bytes") { - // if (!@readableByteStreamAPIEnabled()) - // @throwTypeError("ReadableByteStreamController is not implemented"); - - if (strategy.highWaterMark === @undefined) strategy.highWaterMark = 0; - if (strategy.size !== @undefined) - @throwRangeError( - "Strategy for a ReadableByteStreamController cannot have a size" - ); - - @putByIdDirectPrivate( - stream, - "readableStreamController", - new @ReadableByteStreamController( - stream, - underlyingSource, - strategy.highWaterMark, - @isReadableStream - ) - ); - } else if (typeString === "direct") { - var highWaterMark = strategy?.highWaterMark; - @initializeArrayBufferStream.@call( - stream, - underlyingSource, - highWaterMark - ); - } else if (type === @undefined) { - if (strategy.highWaterMark === @undefined) strategy.highWaterMark = 1; - - @setupReadableStreamDefaultController( - stream, - underlyingSource, - strategy.size, - strategy.highWaterMark, - underlyingSource.start, - underlyingSource.pull, - underlyingSource.cancel - ); - } else @throwRangeError("Invalid type for underlying source"); -} - -function readableStreamDefaultControllerStart(controller) { - "use strict"; - - if (@getByIdDirectPrivate(controller, "started") !== -1) return; - - const underlyingSource = @getByIdDirectPrivate( - controller, - "underlyingSource" - ); - const startMethod = underlyingSource.start; - @putByIdDirectPrivate(controller, "started", 0); - - @promiseInvokeOrNoopMethodNoCatch(underlyingSource, startMethod, [ - controller, - ]).@then( - () => { - @putByIdDirectPrivate(controller, "started", 1); - @assert(!@getByIdDirectPrivate(controller, "pulling")); - @assert(!@getByIdDirectPrivate(controller, "pullAgain")); - @readableStreamDefaultControllerCallPullIfNeeded(controller); - }, - (error) => { - @readableStreamDefaultControllerError(controller, error); - } - ); -} - -// FIXME: Replace readableStreamPipeTo by below function. -// This method implements the latest https://streams.spec.whatwg.org/#readable-stream-pipe-to. -function readableStreamPipeToWritableStream( - source, - destination, - preventClose, - preventAbort, - preventCancel, - signal -) { - "use strict"; - - const isDirectStream = !!@getByIdDirectPrivate(source, "start"); - - - @assert(@isReadableStream(source)); - @assert(@isWritableStream(destination)); - @assert(!@isReadableStreamLocked(source)); - @assert(!@isWritableStreamLocked(destination)); - @assert(signal === @undefined || @isAbortSignal(signal)); - - if (@getByIdDirectPrivate(source, "underlyingByteSource") !== @undefined) - return @Promise.@reject( - "Piping to a readable bytestream is not supported" - ); - - let pipeState = { - source: source, - destination: destination, - preventAbort: preventAbort, - preventCancel: preventCancel, - preventClose: preventClose, - signal: signal, - }; - - pipeState.reader = @acquireReadableStreamDefaultReader(source); - pipeState.writer = @acquireWritableStreamDefaultWriter(destination); - - @putByIdDirectPrivate(source, "disturbed", true); - - pipeState.finalized = false; - pipeState.shuttingDown = false; - pipeState.promiseCapability = @newPromiseCapability(@Promise); - pipeState.pendingReadPromiseCapability = @newPromiseCapability(@Promise); - pipeState.pendingReadPromiseCapability.@resolve.@call(); - pipeState.pendingWritePromise = @Promise.@resolve(); - - if (signal !== @undefined) { - const algorithm = (reason) => { - if (pipeState.finalized) return; - - @pipeToShutdownWithAction( - pipeState, - () => { - const shouldAbortDestination = - !pipeState.preventAbort && - @getByIdDirectPrivate(pipeState.destination, "state") === - "writable"; - const promiseDestination = shouldAbortDestination - ? @writableStreamAbort(pipeState.destination, reason) - : @Promise.@resolve(); - - const shouldAbortSource = - !pipeState.preventCancel && - @getByIdDirectPrivate(pipeState.source, "state") === - @streamReadable; - const promiseSource = shouldAbortSource - ? @readableStreamCancel(pipeState.source, reason) - : @Promise.@resolve(); - - let promiseCapability = @newPromiseCapability(@Promise); - let shouldWait = true; - let handleResolvedPromise = () => { - if (shouldWait) { - shouldWait = false; - return; - } - promiseCapability.@resolve.@call(); - }; - let handleRejectedPromise = (e) => { - promiseCapability.@reject.@call(@undefined, e); - }; - promiseDestination.@then( - handleResolvedPromise, - handleRejectedPromise - ); - promiseSource.@then(handleResolvedPromise, handleRejectedPromise); - return promiseCapability.@promise; - }, - reason - ); - }; - if (@whenSignalAborted(signal, algorithm)) - return pipeState.promiseCapability.@promise; - } - - @pipeToErrorsMustBePropagatedForward(pipeState); - @pipeToErrorsMustBePropagatedBackward(pipeState); - @pipeToClosingMustBePropagatedForward(pipeState); - @pipeToClosingMustBePropagatedBackward(pipeState); - - @pipeToLoop(pipeState); - - return pipeState.promiseCapability.@promise; -} - -function pipeToLoop(pipeState) { - "use strict"; - if (pipeState.shuttingDown) return; - - @pipeToDoReadWrite(pipeState).@then((result) => { - if (result) @pipeToLoop(pipeState); - }); -} - -function pipeToDoReadWrite(pipeState) { - "use strict"; - @assert(!pipeState.shuttingDown); - - pipeState.pendingReadPromiseCapability = @newPromiseCapability(@Promise); - @getByIdDirectPrivate(pipeState.writer, "readyPromise").@promise.@then( - () => { - if (pipeState.shuttingDown) { - pipeState.pendingReadPromiseCapability.@resolve.@call( - @undefined, - false - ); - return; - } - - @readableStreamDefaultReaderRead(pipeState.reader).@then( - (result) => { - const canWrite = - !result.done && - @getByIdDirectPrivate(pipeState.writer, "stream") !== @undefined; - pipeState.pendingReadPromiseCapability.@resolve.@call( - @undefined, - canWrite - ); - if (!canWrite) return; - - pipeState.pendingWritePromise = @writableStreamDefaultWriterWrite( - pipeState.writer, - result.value - ); - }, - (e) => { - pipeState.pendingReadPromiseCapability.@resolve.@call( - @undefined, - false - ); - } - ); - }, - (e) => { - pipeState.pendingReadPromiseCapability.@resolve.@call( - @undefined, - false - ); - } - ); - return pipeState.pendingReadPromiseCapability.@promise; -} - -function pipeToErrorsMustBePropagatedForward(pipeState) { - "use strict"; - - const action = () => { - pipeState.pendingReadPromiseCapability.@resolve.@call(@undefined, false); - const error = @getByIdDirectPrivate(pipeState.source, "storedError"); - if (!pipeState.preventAbort) { - @pipeToShutdownWithAction( - pipeState, - () => @writableStreamAbort(pipeState.destination, error), - error - ); - return; - } - @pipeToShutdown(pipeState, error); - }; - - if (@getByIdDirectPrivate(pipeState.source, "state") === @streamErrored) { - action(); - return; - } - - @getByIdDirectPrivate( - pipeState.reader, - "closedPromiseCapability" - ).@promise.@then(@undefined, action); -} - -function pipeToErrorsMustBePropagatedBackward(pipeState) { - "use strict"; - const action = () => { - const error = @getByIdDirectPrivate(pipeState.destination, "storedError"); - if (!pipeState.preventCancel) { - @pipeToShutdownWithAction( - pipeState, - () => @readableStreamCancel(pipeState.source, error), - error - ); - return; - } - @pipeToShutdown(pipeState, error); - }; - if (@getByIdDirectPrivate(pipeState.destination, "state") === "errored") { - action(); - return; - } - @getByIdDirectPrivate(pipeState.writer, "closedPromise").@promise.@then( - @undefined, - action - ); -} - -function pipeToClosingMustBePropagatedForward(pipeState) { - "use strict"; - const action = () => { - pipeState.pendingReadPromiseCapability.@resolve.@call(@undefined, false); - const error = @getByIdDirectPrivate(pipeState.source, "storedError"); - if (!pipeState.preventClose) { - @pipeToShutdownWithAction(pipeState, () => - @writableStreamDefaultWriterCloseWithErrorPropagation(pipeState.writer) - ); - return; - } - @pipeToShutdown(pipeState); - }; - if (@getByIdDirectPrivate(pipeState.source, "state") === @streamClosed) { - action(); - return; - } - @getByIdDirectPrivate( - pipeState.reader, - "closedPromiseCapability" - ).@promise.@then(action, @undefined); -} - -function pipeToClosingMustBePropagatedBackward(pipeState) { - "use strict"; - if ( - !@writableStreamCloseQueuedOrInFlight(pipeState.destination) && - @getByIdDirectPrivate(pipeState.destination, "state") !== "closed" - ) - return; - - // @assert no chunks have been read/written - - const error = @makeTypeError("closing is propagated backward"); - if (!pipeState.preventCancel) { - @pipeToShutdownWithAction( - pipeState, - () => @readableStreamCancel(pipeState.source, error), - error - ); - return; - } - @pipeToShutdown(pipeState, error); -} - -function pipeToShutdownWithAction(pipeState, action) { - "use strict"; - - if (pipeState.shuttingDown) return; - - pipeState.shuttingDown = true; - - const hasError = arguments.length > 2; - const error = arguments[2]; - const finalize = () => { - const promise = action(); - promise.@then( - () => { - if (hasError) @pipeToFinalize(pipeState, error); - else @pipeToFinalize(pipeState); - }, - (e) => { - @pipeToFinalize(pipeState, e); - } - ); - }; - - if ( - @getByIdDirectPrivate(pipeState.destination, "state") === "writable" && - !@writableStreamCloseQueuedOrInFlight(pipeState.destination) - ) { - pipeState.pendingReadPromiseCapability.@promise.@then( - () => { - pipeState.pendingWritePromise.@then(finalize, finalize); - }, - (e) => @pipeToFinalize(pipeState, e) - ); - return; - } - - finalize(); -} - -function pipeToShutdown(pipeState) { - "use strict"; - - if (pipeState.shuttingDown) return; - - pipeState.shuttingDown = true; - - const hasError = arguments.length > 1; - const error = arguments[1]; - const finalize = () => { - if (hasError) @pipeToFinalize(pipeState, error); - else @pipeToFinalize(pipeState); - }; - - if ( - @getByIdDirectPrivate(pipeState.destination, "state") === "writable" && - !@writableStreamCloseQueuedOrInFlight(pipeState.destination) - ) { - pipeState.pendingReadPromiseCapability.@promise.@then( - () => { - pipeState.pendingWritePromise.@then(finalize, finalize); - }, - (e) => @pipeToFinalize(pipeState, e) - ); - return; - } - finalize(); -} - -function pipeToFinalize(pipeState) { - "use strict"; - - @writableStreamDefaultWriterRelease(pipeState.writer); - @readableStreamReaderGenericRelease(pipeState.reader); - - // Instead of removing the abort algorithm as per spec, we make it a no-op which is equivalent. - pipeState.finalized = true; - - if (arguments.length > 1) - pipeState.promiseCapability.@reject.@call(@undefined, arguments[1]); - else pipeState.promiseCapability.@resolve.@call(); -} - -function readableStreamTee(stream, shouldClone) { - "use strict"; - - @assert(@isReadableStream(stream)); - @assert(typeof shouldClone === "boolean"); - - var start_ = @getByIdDirectPrivate(stream, "start"); - if (start_) { - @putByIdDirectPrivate(stream, "start", @undefined); - start_(); - } - - const reader = new @ReadableStreamDefaultReader(stream); - - const teeState = { - closedOrErrored: false, - canceled1: false, - canceled2: false, - reason1: @undefined, - reason2: @undefined, - }; - - teeState.cancelPromiseCapability = @newPromiseCapability(@Promise); - - const pullFunction = @readableStreamTeePullFunction( - teeState, - reader, - shouldClone - ); - - const branch1Source = {}; - @putByIdDirectPrivate(branch1Source, "pull", pullFunction); - @putByIdDirectPrivate( - branch1Source, - "cancel", - @readableStreamTeeBranch1CancelFunction(teeState, stream) - ); - - const branch2Source = {}; - @putByIdDirectPrivate(branch2Source, "pull", pullFunction); - @putByIdDirectPrivate( - branch2Source, - "cancel", - @readableStreamTeeBranch2CancelFunction(teeState, stream) - ); - - const branch1 = new @ReadableStream(branch1Source); - const branch2 = new @ReadableStream(branch2Source); - - @getByIdDirectPrivate(reader, "closedPromiseCapability").@promise.@then( - @undefined, - function (e) { - if (teeState.closedOrErrored) return; - @readableStreamDefaultControllerError( - branch1.@readableStreamController, - e - ); - @readableStreamDefaultControllerError( - branch2.@readableStreamController, - e - ); - teeState.closedOrErrored = true; - if (!teeState.canceled1 || !teeState.canceled2) - teeState.cancelPromiseCapability.@resolve.@call(); - } - ); - - // Additional fields compared to the spec, as they are needed within pull/cancel functions. - teeState.branch1 = branch1; - teeState.branch2 = branch2; - - return [branch1, branch2]; -} - -function readableStreamTeePullFunction(teeState, reader, shouldClone) { - "use strict"; - - return function () { - @Promise.prototype.@then.@call( - @readableStreamDefaultReaderRead(reader), - function (result) { - @assert(@isObject(result)); - @assert(typeof result.done === "boolean"); - if (result.done && !teeState.closedOrErrored) { - if (!teeState.canceled1) - @readableStreamDefaultControllerClose( - teeState.branch1.@readableStreamController - ); - if (!teeState.canceled2) - @readableStreamDefaultControllerClose( - teeState.branch2.@readableStreamController - ); - teeState.closedOrErrored = true; - if (!teeState.canceled1 || !teeState.canceled2) - teeState.cancelPromiseCapability.@resolve.@call(); - } - if (teeState.closedOrErrored) return; - if (!teeState.canceled1) - @readableStreamDefaultControllerEnqueue( - teeState.branch1.@readableStreamController, - result.value - ); - if (!teeState.canceled2) - @readableStreamDefaultControllerEnqueue( - teeState.branch2.@readableStreamController, - shouldClone - ? @structuredCloneForStream(result.value) - : result.value - ); - } - ); - }; -} - -function readableStreamTeeBranch1CancelFunction(teeState, stream) { - "use strict"; - - return function (r) { - teeState.canceled1 = true; - teeState.reason1 = r; - if (teeState.canceled2) { - @readableStreamCancel(stream, [ - teeState.reason1, - teeState.reason2, - ]).@then( - teeState.cancelPromiseCapability.@resolve, - teeState.cancelPromiseCapability.@reject - ); - } - return teeState.cancelPromiseCapability.@promise; - }; -} - -function readableStreamTeeBranch2CancelFunction(teeState, stream) { - "use strict"; - - return function (r) { - teeState.canceled2 = true; - teeState.reason2 = r; - if (teeState.canceled1) { - @readableStreamCancel(stream, [ - teeState.reason1, - teeState.reason2, - ]).@then( - teeState.cancelPromiseCapability.@resolve, - teeState.cancelPromiseCapability.@reject - ); - } - return teeState.cancelPromiseCapability.@promise; - }; -} - -function isReadableStream(stream) { - "use strict"; - - // Spec tells to return true only if stream has a readableStreamController internal slot. - // However, since it is a private slot, it cannot be checked using hasOwnProperty(). - // Therefore, readableStreamController is initialized with null value. - return ( - @isObject(stream) && - @getByIdDirectPrivate(stream, "readableStreamController") !== @undefined - ); -} - -function isReadableStreamDefaultReader(reader) { - "use strict"; - - // Spec tells to return true only if reader has a readRequests internal slot. - // However, since it is a private slot, it cannot be checked using hasOwnProperty(). - // Since readRequests is initialized with an empty array, the following test is ok. - return @isObject(reader) && !!@getByIdDirectPrivate(reader, "readRequests"); -} - -function isReadableStreamDefaultController(controller) { - "use strict"; - - // Spec tells to return true only if controller has an underlyingSource internal slot. - // However, since it is a private slot, it cannot be checked using hasOwnProperty(). - // underlyingSource is obtained in ReadableStream constructor: if undefined, it is set - // to an empty object. Therefore, following test is ok. - return ( - @isObject(controller) && - !!@getByIdDirectPrivate(controller, "underlyingSource") - ); -} - -function readDirectStream(stream, sink, underlyingSource) { - "use strict"; - - @putByIdDirectPrivate(stream, "underlyingSource", @undefined); - @putByIdDirectPrivate(stream, "start", @undefined); - - function close(stream, reason) { - if (reason && underlyingSource?.cancel) { - try { - var prom = underlyingSource.cancel(reason); - @markPromiseAsHandled(prom); - } catch (e) { - } - - underlyingSource = @undefined; - } - - if (stream) { - @putByIdDirectPrivate(stream, "readableStreamController", @undefined); - @putByIdDirectPrivate(stream, "reader", @undefined); - if (reason) { - @putByIdDirectPrivate(stream, "state", @streamErrored); - @putByIdDirectPrivate(stream, "storedError", reason); - } else { - @putByIdDirectPrivate(stream, "state", @streamClosed); - } - stream = @undefined; - } - } - - - - - - if (!underlyingSource.pull) { - close(); - return; - } - - if (!@isCallable(underlyingSource.pull)) { - close(); - @throwTypeError("pull is not a function"); - return; - } - - @putByIdDirectPrivate(stream, "readableStreamController", sink); - const highWaterMark = @getByIdDirectPrivate(stream, "highWaterMark"); - - sink.start({ - highWaterMark: !highWaterMark || highWaterMark < 64 ? 64 : highWaterMark, - }); - - @startDirectStream.@call(sink, stream, underlyingSource.pull, close); - @putByIdDirectPrivate(stream, "reader", {}); - - var maybePromise = underlyingSource.pull(sink); - sink = @undefined; - if (maybePromise && @isPromise(maybePromise)) { - return maybePromise.@then(() => {}); - } - - -} - -@linkTimeConstant; -function assignToStream(stream, sink) { - "use strict"; - - // The stream is either a direct stream or a "default" JS stream - var underlyingSource = @getByIdDirectPrivate(stream, "underlyingSource"); - - // we know it's a direct stream when @underlyingSource is set - if (underlyingSource) { - try { - return @readDirectStream(stream, sink, underlyingSource); - } catch(e) { - throw e; - } finally { - underlyingSource = @undefined; - stream = @undefined; - sink = @undefined; - } - - - } - - return @readStreamIntoSink(stream, sink, true); -} - -async function readStreamIntoSink(stream, sink, isNative) { - "use strict"; - - var didClose = false; - var didThrow = false; - try { - var reader = stream.getReader(); - var many = reader.readMany(); - if (many && @isPromise(many)) { - many = await many; - } - if (many.done) { - didClose = true; - return sink.end(); - } - var wroteCount = many.value.length; - const highWaterMark = @getByIdDirectPrivate(stream, "highWaterMark"); - if (isNative) @startDirectStream.@call(sink, stream, @undefined, () => !didThrow && @markPromiseAsHandled(stream.cancel())); - - sink.start({ highWaterMark: highWaterMark || 0 }); - - - for ( - var i = 0, values = many.value, length = many.value.length; - i < length; - i++ - ) { - sink.write(values[i]); - } - - var streamState = @getByIdDirectPrivate(stream, "state"); - if (streamState === @streamClosed) { - didClose = true; - return sink.end(); - } - - while (true) { - var { value, done } = await reader.read(); - if (done) { - didClose = true; - return sink.end(); - } - - sink.write(value); - } - } catch (e) { - didThrow = true; - - - try { - reader = @undefined; - const prom = stream.cancel(e); - @markPromiseAsHandled(prom); - } catch (j) {} - - if (sink && !didClose) { - didClose = true; - try { - sink.close(e); - } catch (j) { - throw new globalThis.AggregateError([e, j]); - } - } - - - throw e; - } finally { - if (reader) { - try { - reader.releaseLock(); - } catch (e) {} - reader = @undefined; - } - sink = @undefined; - var streamState = @getByIdDirectPrivate(stream, "state"); - if (stream) { - - // make it easy for this to be GC'd - // but don't do property transitions - var readableStreamController = @getByIdDirectPrivate( - stream, - "readableStreamController" - ); - if (readableStreamController) { - if ( - @getByIdDirectPrivate(readableStreamController, "underlyingSource") - ) - @putByIdDirectPrivate( - readableStreamController, - "underlyingSource", - @undefined - ); - if ( - @getByIdDirectPrivate( - readableStreamController, - "controlledReadableStream" - ) - ) - @putByIdDirectPrivate( - readableStreamController, - "controlledReadableStream", - @undefined - ); - - @putByIdDirectPrivate(stream, "readableStreamController", null); - if (@getByIdDirectPrivate(stream, "underlyingSource")) - @putByIdDirectPrivate(stream, "underlyingSource", @undefined); - readableStreamController = @undefined; - } - - if (!didThrow && streamState !== @streamClosed && streamState !== @streamErrored) { - @readableStreamClose(stream); - } - stream = @undefined; - - - } - } -} - -function handleDirectStreamError(e) { - "use strict"; - - var controller = this; - var sink = controller.@sink; - if (sink) { - @putByIdDirectPrivate(controller, "sink", @undefined); - try { - sink.close(e); - } catch (f) {} - } - - this.error = - this.flush = - this.write = - this.close = - this.end = - @onReadableStreamDirectControllerClosed; - - if (typeof this.@underlyingSource.close === "function") { - try { - this.@underlyingSource.close.@call(this.@underlyingSource, e); - } catch (e) {} - } - - try { - var pend = controller._pendingRead; - if (pend) { - controller._pendingRead = @undefined; - @rejectPromise(pend, e); - } - } catch (f) {} - var stream = controller.@controlledReadableStream; - if (stream) @readableStreamError(stream, e); -} - -function handleDirectStreamErrorReject(e) { - @handleDirectStreamError.@call(this, e); - return @Promise.@reject(e); -} - -function onPullDirectStream(controller) { - "use strict"; - - var stream = controller.@controlledReadableStream; - if (!stream || @getByIdDirectPrivate(stream, "state") !== @streamReadable) - return; - - // pull is in progress - // this is a recursive call - // ignore it - if (controller._deferClose === -1) { - return; - } - - controller._deferClose = -1; - controller._deferFlush = -1; - var deferClose; - var deferFlush; - - // Direct streams allow @pull to be called multiple times, unlike the spec. - // Backpressure is handled by the destination, not by the underlying source. - // In this case, we rely on the heuristic that repeatedly draining in the same tick - // is bad for performance - // this code is only run when consuming a direct stream from JS - // without the HTTP server or anything else - try { - var result = controller.@underlyingSource.pull(controller); - - if (result && @isPromise(result)) { - if (controller._handleError === @undefined) { - controller._handleError = - @handleDirectStreamErrorReject.bind(controller); - } - - @Promise.prototype.catch.@call(result, controller._handleError); - } - } catch (e) { - return @handleDirectStreamErrorReject.@call(controller, e); - } finally { - deferClose = controller._deferClose; - deferFlush = controller._deferFlush; - controller._deferFlush = controller._deferClose = 0; - } - - var promiseToReturn; - - if (controller._pendingRead === @undefined) { - controller._pendingRead = promiseToReturn = @newPromise(); - } else { - promiseToReturn = @readableStreamAddReadRequest(stream); - } - - // they called close during @pull() - // we delay that - if (deferClose === 1) { - var reason = controller._deferCloseReason; - controller._deferCloseReason = @undefined; - @onCloseDirectStream.@call(controller, reason); - return promiseToReturn; - } - - // not done, but they called flush() - if (deferFlush === 1) { - @onFlushDirectStream.@call(controller); - } - - return promiseToReturn; -} - -function noopDoneFunction() { - return @Promise.@resolve({ value: @undefined, done: true }); -} - -function onReadableStreamDirectControllerClosed(reason) { - "use strict"; - @throwTypeError("ReadableStreamDirectController is now closed"); -} - -function onCloseDirectStream(reason) { - "use strict"; - var stream = this.@controlledReadableStream; - if (!stream || @getByIdDirectPrivate(stream, "state") !== @streamReadable) - return; - - if (this._deferClose !== 0) { - this._deferClose = 1; - this._deferCloseReason = reason; - return; - } - - @putByIdDirectPrivate(stream, "state", @streamClosing); - if (typeof this.@underlyingSource.close === "function") { - try { - this.@underlyingSource.close.@call(this.@underlyingSource, reason); - } catch (e) {} - } - - var flushed; - try { - flushed = this.@sink.end(); - @putByIdDirectPrivate(this, "sink", @undefined); - } catch (e) { - if (this._pendingRead) { - var read = this._pendingRead; - this._pendingRead = @undefined; - @rejectPromise(read, e); - } - @readableStreamError(stream, e); - return; - } - - this.error = - this.flush = - this.write = - this.close = - this.end = - @onReadableStreamDirectControllerClosed; - - var reader = @getByIdDirectPrivate(stream, "reader"); - - if (reader && @isReadableStreamDefaultReader(reader)) { - var _pendingRead = this._pendingRead; - if (_pendingRead && @isPromise(_pendingRead) && flushed?.byteLength) { - this._pendingRead = @undefined; - @fulfillPromise(_pendingRead, { value: flushed, done: false }); - @readableStreamClose(stream); - return; - } - } - - if (flushed?.byteLength) { - var requests = @getByIdDirectPrivate(reader, "readRequests"); - if (requests?.isNotEmpty()) { - @readableStreamFulfillReadRequest(stream, flushed, false); - @readableStreamClose(stream); - return; - } - - @putByIdDirectPrivate(stream, "state", @streamReadable); - this.@pull = () => { - var thisResult = @createFulfilledPromise({ - value: flushed, - done: false, - }); - flushed = @undefined; - @readableStreamClose(stream); - stream = @undefined; - return thisResult; - }; - } else if (this._pendingRead) { - var read = this._pendingRead; - this._pendingRead = @undefined; - @putByIdDirectPrivate(this, "pull", @noopDoneFunction); - @fulfillPromise(read, { value: @undefined, done: true }); - } - - @readableStreamClose(stream); -} - -function onFlushDirectStream() { - "use strict"; - - var stream = this.@controlledReadableStream; - var reader = @getByIdDirectPrivate(stream, "reader"); - if (!reader || !@isReadableStreamDefaultReader(reader)) { - return; - } - - var _pendingRead = this._pendingRead; - this._pendingRead = @undefined; - if (_pendingRead && @isPromise(_pendingRead)) { - var flushed = this.@sink.flush(); - if (flushed?.byteLength) { - this._pendingRead = @getByIdDirectPrivate( - stream, - "readRequests" - )?.shift(); - @fulfillPromise(_pendingRead, { value: flushed, done: false }); - } else { - this._pendingRead = _pendingRead; - } - } else if (@getByIdDirectPrivate(stream, "readRequests")?.isNotEmpty()) { - var flushed = this.@sink.flush(); - if (flushed?.byteLength) { - @readableStreamFulfillReadRequest(stream, flushed, false); - } - } else if (this._deferFlush === -1) { - this._deferFlush = 1; - } -} - -function createTextStream(highWaterMark) { - "use strict"; - - var sink; - var array = []; - var hasString = false; - var hasBuffer = false; - var rope = ""; - var estimatedLength = @toLength(0); - var capability = @newPromiseCapability(@Promise); - var calledDone = false; - - sink = { - start() {}, - write(chunk) { - if (typeof chunk === "string") { - var chunkLength = @toLength(chunk.length); - if (chunkLength > 0) { - rope += chunk; - hasString = true; - // TODO: utf16 byte length - estimatedLength += chunkLength; - } - - return chunkLength; - } - - if ( - !chunk || - !(@ArrayBuffer.@isView(chunk) || chunk instanceof @ArrayBuffer) - ) { - @throwTypeError("Expected text, ArrayBuffer or ArrayBufferView"); - } - - const byteLength = @toLength(chunk.byteLength); - if (byteLength > 0) { - hasBuffer = true; - if (rope.length > 0) { - @arrayPush(array, rope, chunk); - rope = ""; - } else { - @arrayPush(array, chunk); - } - } - estimatedLength += byteLength; - return byteLength; - }, - - flush() { - return 0; - }, - - end() { - if (calledDone) { - return ""; - } - return sink.fulfill(); - }, - - fulfill() { - calledDone = true; - const result = sink.finishInternal(); - - @fulfillPromise(capability.@promise, result); - return result; - }, - - finishInternal() { - if (!hasString && !hasBuffer) { - return ""; - } - - if (hasString && !hasBuffer) { - return rope; - } - - if (hasBuffer && !hasString) { - return new globalThis.TextDecoder().decode( - @Bun.concatArrayBuffers(array) - ); - } - - // worst case: mixed content - - var arrayBufferSink = new @Bun.ArrayBufferSink(); - arrayBufferSink.start({ - highWaterMark: estimatedLength, - asUint8Array: true, - }); - for (let item of array) { - arrayBufferSink.write(item); - } - array.length = 0; - if (rope.length > 0) { - arrayBufferSink.write(rope); - rope = ""; - } - - // TODO: use builtin - return new globalThis.TextDecoder().decode(arrayBufferSink.end()); - }, - - close() { - try { - if (!calledDone) { - calledDone = true; - sink.fulfill(); - } - } catch (e) {} - }, - }; - - return [sink, capability]; -} - -function initializeTextStream(underlyingSource, highWaterMark) { - "use strict"; - var [sink, closingPromise] = @createTextStream(highWaterMark); - - var controller = { - @underlyingSource: underlyingSource, - @pull: @onPullDirectStream, - @controlledReadableStream: this, - @sink: sink, - close: @onCloseDirectStream, - write: sink.write, - error: @handleDirectStreamError, - end: @onCloseDirectStream, - @close: @onCloseDirectStream, - flush: @onFlushDirectStream, - _pendingRead: @undefined, - _deferClose: 0, - _deferFlush: 0, - _deferCloseReason: @undefined, - _handleError: @undefined, - }; - - @putByIdDirectPrivate(this, "readableStreamController", controller); - @putByIdDirectPrivate(this, "underlyingSource", @undefined); - @putByIdDirectPrivate(this, "start", @undefined); - return closingPromise; -} - -function initializeArrayStream(underlyingSource, highWaterMark) { - "use strict"; - - var array = []; - var closingPromise = @newPromiseCapability(@Promise); - var calledDone = false; - - function fulfill() { - calledDone = true; - closingPromise.@resolve.@call(@undefined, array); - return array; - } - - var sink = { - start() {}, - write(chunk) { - @arrayPush(array, chunk); - return chunk.byteLength || chunk.length; - }, - - flush() { - return 0; - }, - - end() { - if (calledDone) { - return []; - } - return fulfill(); - }, - - close() { - if (!calledDone) { - fulfill(); - } - }, - }; - - var controller = { - @underlyingSource: underlyingSource, - @pull: @onPullDirectStream, - @controlledReadableStream: this, - @sink: sink, - close: @onCloseDirectStream, - write: sink.write, - error: @handleDirectStreamError, - end: @onCloseDirectStream, - @close: @onCloseDirectStream, - flush: @onFlushDirectStream, - _pendingRead: @undefined, - _deferClose: 0, - _deferFlush: 0, - _deferCloseReason: @undefined, - _handleError: @undefined, - }; - - @putByIdDirectPrivate(this, "readableStreamController", controller); - @putByIdDirectPrivate(this, "underlyingSource", @undefined); - @putByIdDirectPrivate(this, "start", @undefined); - return closingPromise; -} - -function initializeArrayBufferStream(underlyingSource, highWaterMark) { - "use strict"; - - // This is the fallback implementation for direct streams - // When we don't know what the destination type is - // We assume it is a Uint8Array. - - var opts = - highWaterMark && typeof highWaterMark === "number" - ? { highWaterMark, stream: true, asUint8Array: true } - : { stream: true, asUint8Array: true }; - var sink = new @Bun.ArrayBufferSink(); - sink.start(opts); - - var controller = { - @underlyingSource: underlyingSource, - @pull: @onPullDirectStream, - @controlledReadableStream: this, - @sink: sink, - close: @onCloseDirectStream, - write: sink.write.bind(sink), - error: @handleDirectStreamError, - end: @onCloseDirectStream, - @close: @onCloseDirectStream, - flush: @onFlushDirectStream, - _pendingRead: @undefined, - _deferClose: 0, - _deferFlush: 0, - _deferCloseReason: @undefined, - _handleError: @undefined, - }; - - @putByIdDirectPrivate(this, "readableStreamController", controller); - @putByIdDirectPrivate(this, "underlyingSource", @undefined); - @putByIdDirectPrivate(this, "start", @undefined); -} - -function readableStreamError(stream, error) { - "use strict"; - - @assert(@isReadableStream(stream)); - @assert(@getByIdDirectPrivate(stream, "state") === @streamReadable); - @putByIdDirectPrivate(stream, "state", @streamErrored); - @putByIdDirectPrivate(stream, "storedError", error); - - const reader = @getByIdDirectPrivate(stream, "reader"); - - if (!reader) return; - - if (@isReadableStreamDefaultReader(reader)) { - const requests = @getByIdDirectPrivate(reader, "readRequests"); - @putByIdDirectPrivate(reader, "readRequests", @createFIFO()); - for (var request = requests.shift(); request; request = requests.shift()) - @rejectPromise(request, error); - } else { - @assert(@isReadableStreamBYOBReader(reader)); - const requests = @getByIdDirectPrivate(reader, "readIntoRequests"); - @putByIdDirectPrivate(reader, "readIntoRequests", @createFIFO()); - for (var request = requests.shift(); request; request = requests.shift()) - @rejectPromise(request, error); - } - - @getByIdDirectPrivate(reader, "closedPromiseCapability").@reject.@call( - @undefined, - error - ); - const promise = @getByIdDirectPrivate( - reader, - "closedPromiseCapability" - ).@promise; - @markPromiseAsHandled(promise); -} - -function readableStreamDefaultControllerShouldCallPull(controller) { - "use strict"; - - const stream = @getByIdDirectPrivate(controller, "controlledReadableStream"); - - if (!@readableStreamDefaultControllerCanCloseOrEnqueue(controller)) - return false; - if (!(@getByIdDirectPrivate(controller, "started") === 1)) return false; - if ( - (!@isReadableStreamLocked(stream) || - !@getByIdDirectPrivate( - @getByIdDirectPrivate(stream, "reader"), - "readRequests" - )?.isNotEmpty()) && - @readableStreamDefaultControllerGetDesiredSize(controller) <= 0 - ) - return false; - const desiredSize = - @readableStreamDefaultControllerGetDesiredSize(controller); - @assert(desiredSize !== null); - return desiredSize > 0; -} - -function readableStreamDefaultControllerCallPullIfNeeded(controller) { - "use strict"; - - // FIXME: use @readableStreamDefaultControllerShouldCallPull - const stream = @getByIdDirectPrivate(controller, "controlledReadableStream"); - - if (!@readableStreamDefaultControllerCanCloseOrEnqueue(controller)) return; - if (!(@getByIdDirectPrivate(controller, "started") === 1)) return; - if ( - (!@isReadableStreamLocked(stream) || - !@getByIdDirectPrivate( - @getByIdDirectPrivate(stream, "reader"), - "readRequests" - )?.isNotEmpty()) && - @readableStreamDefaultControllerGetDesiredSize(controller) <= 0 - ) - return; - - if (@getByIdDirectPrivate(controller, "pulling")) { - @putByIdDirectPrivate(controller, "pullAgain", true); - return; - } - - @assert(!@getByIdDirectPrivate(controller, "pullAgain")); - @putByIdDirectPrivate(controller, "pulling", true); - - @getByIdDirectPrivate(controller, "pullAlgorithm") - .@call(@undefined) - .@then( - function () { - @putByIdDirectPrivate(controller, "pulling", false); - if (@getByIdDirectPrivate(controller, "pullAgain")) { - @putByIdDirectPrivate(controller, "pullAgain", false); - - @readableStreamDefaultControllerCallPullIfNeeded(controller); - } - }, - function (error) { - @readableStreamDefaultControllerError(controller, error); - } - ); -} - -function isReadableStreamLocked(stream) { - "use strict"; - - @assert(@isReadableStream(stream)); - return !!@getByIdDirectPrivate(stream, "reader"); -} - -function readableStreamDefaultControllerGetDesiredSize(controller) { - "use strict"; - - const stream = @getByIdDirectPrivate(controller, "controlledReadableStream"); - const state = @getByIdDirectPrivate(stream, "state"); - - if (state === @streamErrored) return null; - if (state === @streamClosed) return 0; - - return ( - @getByIdDirectPrivate(controller, "strategy").highWaterMark - - @getByIdDirectPrivate(controller, "queue").size - ); -} - -function readableStreamReaderGenericCancel(reader, reason) { - "use strict"; - - const stream = @getByIdDirectPrivate(reader, "ownerReadableStream"); - @assert(!!stream); - return @readableStreamCancel(stream, reason); -} - -function readableStreamCancel(stream, reason) { - "use strict"; - - @putByIdDirectPrivate(stream, "disturbed", true); - const state = @getByIdDirectPrivate(stream, "state"); - if (state === @streamClosed) return @Promise.@resolve(); - if (state === @streamErrored) - return @Promise.@reject(@getByIdDirectPrivate(stream, "storedError")); - @readableStreamClose(stream); - - var controller = @getByIdDirectPrivate(stream, "readableStreamController"); - var cancel = controller.@cancel; - if (cancel) { - return cancel(controller, reason).@then(function () {}); - } - - var close = controller.close; - if (close) { - return @Promise.@resolve(controller.close(reason)); - } - - @throwTypeError("ReadableStreamController has no cancel or close method"); -} - -function readableStreamDefaultControllerCancel(controller, reason) { - "use strict"; - - @putByIdDirectPrivate(controller, "queue", @newQueue()); - return @getByIdDirectPrivate(controller, "cancelAlgorithm").@call( - @undefined, - reason - ); -} - -function readableStreamDefaultControllerPull(controller) { - "use strict"; - - var queue = @getByIdDirectPrivate(controller, "queue"); - if (queue.content.isNotEmpty()) { - const chunk = @dequeueValue(queue); - if ( - @getByIdDirectPrivate(controller, "closeRequested") && - queue.content.isEmpty() - ) - @readableStreamClose( - @getByIdDirectPrivate(controller, "controlledReadableStream") - ); - else @readableStreamDefaultControllerCallPullIfNeeded(controller); - - return @createFulfilledPromise({ value: chunk, done: false }); - } - const pendingPromise = @readableStreamAddReadRequest( - @getByIdDirectPrivate(controller, "controlledReadableStream") - ); - @readableStreamDefaultControllerCallPullIfNeeded(controller); - return pendingPromise; -} - -function readableStreamDefaultControllerClose(controller) { - "use strict"; - - @assert(@readableStreamDefaultControllerCanCloseOrEnqueue(controller)); - @putByIdDirectPrivate(controller, "closeRequested", true); - if (@getByIdDirectPrivate(controller, "queue")?.content?.isEmpty()) - @readableStreamClose( - @getByIdDirectPrivate(controller, "controlledReadableStream") - ); -} - -function readableStreamClose(stream) { - "use strict"; - - @assert(@getByIdDirectPrivate(stream, "state") === @streamReadable); - @putByIdDirectPrivate(stream, "state", @streamClosed); - if (!@getByIdDirectPrivate(stream, "reader")) return; - - if ( - @isReadableStreamDefaultReader(@getByIdDirectPrivate(stream, "reader")) - ) { - const requests = @getByIdDirectPrivate( - @getByIdDirectPrivate(stream, "reader"), - "readRequests" - ); - if (requests.isNotEmpty()) { - @putByIdDirectPrivate( - @getByIdDirectPrivate(stream, "reader"), - "readRequests", - @createFIFO() - ); - - for (var request = requests.shift(); request; request = requests.shift()) - @fulfillPromise(request, { value: @undefined, done: true }); - } - } - - @getByIdDirectPrivate( - @getByIdDirectPrivate(stream, "reader"), - "closedPromiseCapability" - ).@resolve.@call(); -} - -function readableStreamFulfillReadRequest(stream, chunk, done) { - "use strict"; - const readRequest = @getByIdDirectPrivate( - @getByIdDirectPrivate(stream, "reader"), - "readRequests" - ).shift(); - @fulfillPromise(readRequest, { value: chunk, done: done }); -} - -function readableStreamDefaultControllerEnqueue(controller, chunk) { - "use strict"; - - const stream = @getByIdDirectPrivate(controller, "controlledReadableStream"); - // this is checked by callers - @assert(@readableStreamDefaultControllerCanCloseOrEnqueue(controller)); - - if ( - @isReadableStreamLocked(stream) && - @getByIdDirectPrivate( - @getByIdDirectPrivate(stream, "reader"), - "readRequests" - )?.isNotEmpty() - ) { - @readableStreamFulfillReadRequest(stream, chunk, false); - @readableStreamDefaultControllerCallPullIfNeeded(controller); - return; - } - - try { - let chunkSize = 1; - if (@getByIdDirectPrivate(controller, "strategy").size !== @undefined) - chunkSize = @getByIdDirectPrivate(controller, "strategy").size(chunk); - @enqueueValueWithSize( - @getByIdDirectPrivate(controller, "queue"), - chunk, - chunkSize - ); - } catch (error) { - @readableStreamDefaultControllerError(controller, error); - throw error; - } - @readableStreamDefaultControllerCallPullIfNeeded(controller); -} - -function readableStreamDefaultReaderRead(reader) { - "use strict"; - - const stream = @getByIdDirectPrivate(reader, "ownerReadableStream"); - @assert(!!stream); - const state = @getByIdDirectPrivate(stream, "state"); - - @putByIdDirectPrivate(stream, "disturbed", true); - if (state === @streamClosed) - return @createFulfilledPromise({ value: @undefined, done: true }); - if (state === @streamErrored) - return @Promise.@reject(@getByIdDirectPrivate(stream, "storedError")); - @assert(state === @streamReadable); - - return @getByIdDirectPrivate(stream, "readableStreamController").@pull( - @getByIdDirectPrivate(stream, "readableStreamController") - ); -} - -function readableStreamAddReadRequest(stream) { - "use strict"; - - @assert( - @isReadableStreamDefaultReader(@getByIdDirectPrivate(stream, "reader")) - ); - @assert(@getByIdDirectPrivate(stream, "state") == @streamReadable); - - const readRequest = @newPromise(); - - @getByIdDirectPrivate( - @getByIdDirectPrivate(stream, "reader"), - "readRequests" - ).push(readRequest); - - return readRequest; -} - -function isReadableStreamDisturbed(stream) { - "use strict"; - - @assert(@isReadableStream(stream)); - return @getByIdDirectPrivate(stream, "disturbed"); -} - -function readableStreamReaderGenericRelease(reader) { - "use strict"; - - @assert(!!@getByIdDirectPrivate(reader, "ownerReadableStream")); - @assert( - @getByIdDirectPrivate( - @getByIdDirectPrivate(reader, "ownerReadableStream"), - "reader" - ) === reader - ); - - if ( - @getByIdDirectPrivate( - @getByIdDirectPrivate(reader, "ownerReadableStream"), - "state" - ) === @streamReadable - ) - @getByIdDirectPrivate(reader, "closedPromiseCapability").@reject.@call( - @undefined, - @makeTypeError( - "releasing lock of reader whose stream is still in readable state" - ) - ); - else - @putByIdDirectPrivate(reader, "closedPromiseCapability", { - @promise: @newHandledRejectedPromise( - @makeTypeError("reader released lock") - ), - }); - - const promise = @getByIdDirectPrivate( - reader, - "closedPromiseCapability" - ).@promise; - @markPromiseAsHandled(promise); - @putByIdDirectPrivate( - @getByIdDirectPrivate(reader, "ownerReadableStream"), - "reader", - @undefined - ); - @putByIdDirectPrivate(reader, "ownerReadableStream", @undefined); -} - -function readableStreamDefaultControllerCanCloseOrEnqueue(controller) { - "use strict"; - - return ( - !@getByIdDirectPrivate(controller, "closeRequested") && - @getByIdDirectPrivate( - @getByIdDirectPrivate(controller, "controlledReadableStream"), - "state" - ) === @streamReadable - ); -} - -function lazyLoadStream(stream, autoAllocateChunkSize) { - "use strict"; - - var nativeType = @getByIdDirectPrivate(stream, "bunNativeType"); - var nativePtr = @getByIdDirectPrivate(stream, "bunNativePtr"); - var Prototype = @lazyStreamPrototypeMap.@get(nativeType); - if (Prototype === @undefined) { - var [pull, start, cancel, setClose, deinit, setRefOrUnref, drain] = @lazyLoad(nativeType); - var closer = [false]; - var handleResult; - function handleNativeReadableStreamPromiseResult(val) { - "use strict"; - var { c, v } = this; - this.c = @undefined; - this.v = @undefined; - handleResult(val, c, v); - } - - function callClose(controller) { - try { - controller.close(); - } catch(e) { - globalThis.reportError(e); - } - } - - handleResult = function handleResult(result, controller, view) { - "use strict"; - if (result && @isPromise(result)) { - return result.then( - handleNativeReadableStreamPromiseResult.bind({ - c: controller, - v: view, - }), - (err) => controller.error(err) - ); - } else if (typeof result === 'number') { - if (view && view.byteLength === result && view.buffer === controller.byobRequest?.view?.buffer) { - controller.byobRequest.respondWithNewView(view); - } else { - controller.byobRequest.respond(result); - } - } else if (result.constructor === @Uint8Array) { - controller.enqueue(result); - } - - if (closer[0] || result === false) { - @enqueueJob(callClose, controller); - closer[0] = false; - } - }; - - function createResult(tag, controller, view, closer) { - closer[0] = false; - - var result; - try { - result = pull(tag, view, closer); - } catch (err) { - return controller.error(err); - } - - return handleResult(result, controller, view); - } - - const registry = deinit ? new FinalizationRegistry(deinit) : null; - Prototype = class NativeReadableStreamSource { - constructor(tag, autoAllocateChunkSize, drainValue) { - this.#tag = tag; - this.#cancellationToken = {}; - this.pull = this.#pull.bind(this); - this.cancel = this.#cancel.bind(this); - this.autoAllocateChunkSize = autoAllocateChunkSize; - - if (drainValue !== @undefined) { - this.start = (controller) => { - controller.enqueue(drainValue); - }; - } - - if (registry) { - registry.register(this, tag, this.#cancellationToken); - } - } - - #cancellationToken; - pull; - cancel; - start; - - #tag; - type = "bytes"; - autoAllocateChunkSize = 0; - - static startSync = start; - - - #pull(controller) { - var tag = this.#tag; - - if (!tag) { - controller.close(); - return; - } - - createResult(tag, controller, controller.byobRequest.view, closer); - } - - #cancel(reason) { - var tag = this.#tag; - - registry && registry.unregister(this.#cancellationToken); - setRefOrUnref && setRefOrUnref(tag, false); - cancel(tag, reason); - } - static deinit = deinit; - static drain = drain; - }; - @lazyStreamPrototypeMap.@set(nativeType, Prototype); - } - - const chunkSize = Prototype.startSync(nativePtr, autoAllocateChunkSize); - var drainValue; - const {drain: drainFn, deinit: deinitFn} = Prototype; - if (drainFn) { - drainValue = drainFn(nativePtr); - } - - // empty file, no need for native back-and-forth on this - if (chunkSize === 0) { - deinit && nativePtr && @enqueueJob(deinit, nativePtr); - - if ((drainValue?.byteLength ?? 0) > 0) { - return { - start(controller) { - controller.enqueue(drainValue); - controller.close(); - }, - type: "bytes", - }; - } - - return { - start(controller) { - controller.close(); - }, - type: "bytes", - }; - } - - return new Prototype(nativePtr, chunkSize, drainValue); -} - -function readableStreamIntoArray(stream) { - "use strict"; - - var reader = stream.getReader(); - var manyResult = reader.readMany(); - - async function processManyResult(result) { - if (result.done) { - return []; - } - - var chunks = result.value || []; - - while (true) { - var thisResult = await reader.read(); - if (thisResult.done) { - break; - } - chunks = chunks.concat(thisResult.value); - } - - return chunks; - } - - if (manyResult && @isPromise(manyResult)) { - return manyResult.@then(processManyResult); - } - - return processManyResult(manyResult); -} - -function readableStreamIntoText(stream) { - "use strict"; - - const [textStream, closer] = @createTextStream( - @getByIdDirectPrivate(stream, "highWaterMark") - ); - const prom = @readStreamIntoSink(stream, textStream, false); - if (prom && @isPromise(prom)) { - return @Promise.@resolve(prom).@then(closer.@promise); - } - return closer.@promise; -} - -function readableStreamToArrayBufferDirect(stream, underlyingSource) { - "use strict"; - - var sink = new @Bun.ArrayBufferSink(); - @putByIdDirectPrivate(stream, "underlyingSource", @undefined); - var highWaterMark = @getByIdDirectPrivate(stream, "highWaterMark"); - sink.start(highWaterMark ? { highWaterMark } : {}); - var capability = @newPromiseCapability(@Promise); - var ended = false; - var pull = underlyingSource.pull; - var close = underlyingSource.close; - - var controller = { - start() {}, - close(reason) { - if (!ended) { - ended = true; - if (close) { - close(); - } - - @fulfillPromise(capability.@promise, sink.end()); - } - }, - end() { - if (!ended) { - ended = true; - if (close) { - close(); - } - @fulfillPromise(capability.@promise, sink.end()); - } - }, - flush() { - return 0; - }, - write: sink.write.bind(sink), - }; - - var didError = false; - try { - const firstPull = pull(controller); - if (firstPull && @isObject(firstPull) && @isPromise(firstPull)) { - return (async function (controller, promise, pull) { - while (!ended) { - await pull(controller); - } - return await promise; - })(controller, promise, pull); - } - - return capability.@promise; - } catch (e) { - didError = true; - @readableStreamError(stream, e); - return @Promise.@reject(e); - } finally { - if (!didError && stream) @readableStreamClose(stream); - controller = close = sink = pull = stream = @undefined; - } -} - -async function readableStreamToTextDirect(stream, underlyingSource) { - "use strict"; - const capability = @initializeTextStream.@call( - stream, - underlyingSource, - @undefined - ); - var reader = stream.getReader(); - - while (@getByIdDirectPrivate(stream, "state") === @streamReadable) { - var thisResult = await reader.read(); - if (thisResult.done) { - break; - } - } - - try { - reader.releaseLock(); - } catch (e) {} - reader = @undefined; - stream = @undefined; - - return capability.@promise; -} - -async function readableStreamToArrayDirect(stream, underlyingSource) { - const capability = @initializeArrayStream.@call( - stream, - underlyingSource, - @undefined - ); - underlyingSource = @undefined; - var reader = stream.getReader(); - try { - while (@getByIdDirectPrivate(stream, "state") === @streamReadable) { - var thisResult = await reader.read(); - if (thisResult.done) { - break; - } - } - - try { - reader.releaseLock(); - } catch (e) {} - reader = @undefined; - - return @Promise.@resolve(capability.@promise); - } catch (e) { - throw e; - } finally { - stream = @undefined; - reader = @undefined; - } - - return capability.@promise; -} - - -function readableStreamDefineLazyIterators(prototype) { - "use strict"; - - var asyncIterator = globalThis.Symbol.asyncIterator; - - var ReadableStreamAsyncIterator = async function* ReadableStreamAsyncIterator(stream, preventCancel) { - var reader = stream.getReader(); - var deferredError; - try { - while (true) { - var done, value; - const firstResult = reader.readMany(); - if (@isPromise(firstResult)) { - ({done, value} = await firstResult); - } else { - ({done, value} = firstResult); - } - - if (done) { - return; - } - yield* value; - } - } catch(e) { - deferredError = e; - } finally { - reader.releaseLock(); - - if (!preventCancel) { - stream.cancel(deferredError); - } - - if (deferredError) { - throw deferredError; - } - } - }; - var createAsyncIterator = function asyncIterator() { - return ReadableStreamAsyncIterator(this, false); - }; - var createValues = function values({preventCancel = false} = {preventCancel: false}) { - return ReadableStreamAsyncIterator(this, preventCancel); - }; - @Object.@defineProperty(prototype, asyncIterator, { value: createAsyncIterator }); - @Object.@defineProperty(prototype, "values", { value: createValues }); - return prototype; -}
\ No newline at end of file diff --git a/src/bun.js/builtins/js/StreamInternals.js b/src/bun.js/builtins/js/StreamInternals.js deleted file mode 100644 index 0f08b7901..000000000 --- a/src/bun.js/builtins/js/StreamInternals.js +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (C) 2015 Canon Inc. - * Copyright (C) 2015 Igalia. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// @internal - -function markPromiseAsHandled(promise) -{ - "use strict"; - - @assert(@isPromise(promise)); - @putPromiseInternalField(promise, @promiseFieldFlags, @getPromiseInternalField(promise, @promiseFieldFlags) | @promiseFlagsIsHandled); -} - -function shieldingPromiseResolve(result) -{ - "use strict"; - - const promise = @Promise.@resolve(result); - if (promise.@then === @undefined) - promise.@then = @Promise.prototype.@then; - return promise; -} - -function promiseInvokeOrNoopMethodNoCatch(object, method, args) -{ - "use strict"; - - if (method === @undefined) - return @Promise.@resolve(); - return @shieldingPromiseResolve(method.@apply(object, args)); -} - -function promiseInvokeOrNoopNoCatch(object, key, args) -{ - "use strict"; - - return @promiseInvokeOrNoopMethodNoCatch(object, object[key], args); -} - -function promiseInvokeOrNoopMethod(object, method, args) -{ - "use strict"; - - try { - return @promiseInvokeOrNoopMethodNoCatch(object, method, args); - } - catch(error) { - return @Promise.@reject(error); - } -} - -function promiseInvokeOrNoop(object, key, args) -{ - "use strict"; - - try { - return @promiseInvokeOrNoopNoCatch(object, key, args); - } - catch(error) { - return @Promise.@reject(error); - } -} - -function promiseInvokeOrFallbackOrNoop(object, key1, args1, key2, args2) -{ - "use strict"; - - try { - const method = object[key1]; - if (method === @undefined) - return @promiseInvokeOrNoopNoCatch(object, key2, args2); - return @shieldingPromiseResolve(method.@apply(object, args1)); - } - catch(error) { - return @Promise.@reject(error); - } -} - -function validateAndNormalizeQueuingStrategy(size, highWaterMark) -{ - "use strict"; - - if (size !== @undefined && typeof size !== "function") - @throwTypeError("size parameter must be a function"); - - const newHighWaterMark = @toNumber(highWaterMark); - - if (@isNaN(newHighWaterMark) || newHighWaterMark < 0) - @throwRangeError("highWaterMark value is negative or not a number"); - - return { size: size, highWaterMark: newHighWaterMark }; -} - -@linkTimeConstant -function createFIFO() { - "use strict"; - var slice = @Array.prototype.slice; - - class Denqueue { - constructor() { - this._head = 0; - this._tail = 0; - // this._capacity = 0; - this._capacityMask = 0x3; - this._list = @newArrayWithSize(4); - } - - _head; - _tail; - _capacityMask; - _list; - - size() { - if (this._head === this._tail) return 0; - if (this._head < this._tail) return this._tail - this._head; - else return this._capacityMask + 1 - (this._head - this._tail); - } - - isEmpty() { - return this.size() == 0; - } - - isNotEmpty() { - return this.size() > 0; - } - - shift() { - var { _head: head, _tail, _list, _capacityMask } = this; - if (head === _tail) return @undefined; - var item = _list[head]; - @putByValDirect(_list, head, @undefined); - head = this._head = (head + 1) & _capacityMask; - if (head < 2 && _tail > 10000 && _tail <= _list.length >>> 2) this._shrinkArray(); - return item; - } - - peek() { - if (this._head === this._tail) return @undefined; - return this._list[this._head]; - } - - push(item) { - var tail = this._tail; - @putByValDirect(this._list, tail, item); - this._tail = (tail + 1) & this._capacityMask; - if (this._tail === this._head) { - this._growArray(); - } - // if (this._capacity && this.size() > this._capacity) { - // this.shift(); - // } - } - - toArray(fullCopy) { - var list = this._list; - var len = @toLength(list.length); - - if (fullCopy || this._head > this._tail) { - var _head = @toLength(this._head); - var _tail = @toLength(this._tail); - var total = @toLength((len - _head) + _tail); - var array = @newArrayWithSize(total); - var j = 0; - for (var i = _head; i < len; i++) @putByValDirect(array, j++, list[i]); - for (var i = 0; i < _tail; i++) @putByValDirect(array, j++, list[i]); - return array; - } else { - return slice.@call(list, this._head, this._tail); - } - } - - clear() { - this._head = 0; - this._tail = 0; - this._list.fill(undefined); - } - - _growArray() { - if (this._head) { - // copy existing data, head to end, then beginning to tail. - this._list = this.toArray(true); - this._head = 0; - } - - // head is at 0 and array is now full, safe to extend - this._tail = @toLength(this._list.length); - - this._list.length <<= 1; - this._capacityMask = (this._capacityMask << 1) | 1; - } - - shrinkArray() { - this._list.length >>>= 1; - this._capacityMask >>>= 1; - } - } - - - return new Denqueue(); -} - -function newQueue() -{ - "use strict"; - - return { content: @createFIFO(), size: 0 }; -} - -function dequeueValue(queue) -{ - "use strict"; - - const record = queue.content.shift(); - queue.size -= record.size; - // As described by spec, below case may occur due to rounding errors. - if (queue.size < 0) - queue.size = 0; - return record.value; -} - -function enqueueValueWithSize(queue, value, size) -{ - "use strict"; - - size = @toNumber(size); - if (!@isFinite(size) || size < 0) - @throwRangeError("size has an incorrect value"); - - queue.content.push({ value, size }); - queue.size += size; -} - -function peekQueueValue(queue) -{ - "use strict"; - return queue.content.peek()?.value; -} - -function resetQueue(queue) -{ - "use strict"; - - @assert("content" in queue); - @assert("size" in queue); - queue.content.clear(); - queue.size = 0; -} - -function extractSizeAlgorithm(strategy) -{ - const sizeAlgorithm = strategy.size; - - if (sizeAlgorithm === @undefined) - return () => 1; - - if (typeof sizeAlgorithm !== "function") - @throwTypeError("strategy.size must be a function"); - - return (chunk) => { return sizeAlgorithm(chunk); }; -} - -function extractHighWaterMark(strategy, defaultHWM) -{ - const highWaterMark = strategy.highWaterMark; - - if (highWaterMark === @undefined) - return defaultHWM; - - if (@isNaN(highWaterMark) || highWaterMark < 0) - @throwRangeError("highWaterMark value is negative or not a number"); - - return @toNumber(highWaterMark); -} - -function extractHighWaterMarkFromQueuingStrategyInit(init) -{ - "use strict"; - - if (!@isObject(init)) - @throwTypeError("QueuingStrategyInit argument must be an object."); - const {highWaterMark} = init; - if (highWaterMark === @undefined) - @throwTypeError("QueuingStrategyInit.highWaterMark member is required."); - - return @toNumber(highWaterMark); -} - -function createFulfilledPromise(value) -{ - const promise = @newPromise(); - @fulfillPromise(promise, value); - return promise; -} - -function toDictionary(value, defaultValue, errorMessage) -{ - if (value === @undefined || value === null) - return defaultValue; - if (!@isObject(value)) - @throwTypeError(errorMessage); - return value; -} diff --git a/src/bun.js/builtins/js/TransformStream.js b/src/bun.js/builtins/js/TransformStream.js deleted file mode 100644 index 8d82d87d8..000000000 --- a/src/bun.js/builtins/js/TransformStream.js +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2020 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -function initializeTransformStream() -{ - "use strict"; - - let transformer = arguments[0]; - - // This is the path for CreateTransformStream. - if (@isObject(transformer) && @getByIdDirectPrivate(transformer, "TransformStream")) - return this; - - let writableStrategy = arguments[1]; - let readableStrategy = arguments[2]; - - if (transformer === @undefined) - transformer = null; - - if (readableStrategy === @undefined) - readableStrategy = { }; - - if (writableStrategy === @undefined) - writableStrategy = { }; - - let transformerDict = { }; - if (transformer !== null) { - if ("start" in transformer) { - transformerDict["start"] = transformer["start"]; - if (typeof transformerDict["start"] !== "function") - @throwTypeError("transformer.start should be a function"); - } - if ("transform" in transformer) { - transformerDict["transform"] = transformer["transform"]; - if (typeof transformerDict["transform"] !== "function") - @throwTypeError("transformer.transform should be a function"); - } - if ("flush" in transformer) { - transformerDict["flush"] = transformer["flush"]; - if (typeof transformerDict["flush"] !== "function") - @throwTypeError("transformer.flush should be a function"); - } - - if ("readableType" in transformer) - @throwRangeError("TransformStream transformer has a readableType"); - if ("writableType" in transformer) - @throwRangeError("TransformStream transformer has a writableType"); - } - - const readableHighWaterMark = @extractHighWaterMark(readableStrategy, 0); - const readableSizeAlgorithm = @extractSizeAlgorithm(readableStrategy); - - const writableHighWaterMark = @extractHighWaterMark(writableStrategy, 1); - const writableSizeAlgorithm = @extractSizeAlgorithm(writableStrategy); - - const startPromiseCapability = @newPromiseCapability(@Promise); - @initializeTransformStream(this, startPromiseCapability.@promise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm); - @setUpTransformStreamDefaultControllerFromTransformer(this, transformer, transformerDict); - - if ("start" in transformerDict) { - const controller = @getByIdDirectPrivate(this, "controller"); - const startAlgorithm = () => @promiseInvokeOrNoopMethodNoCatch(transformer, transformerDict["start"], [controller]); - startAlgorithm().@then(() => { - // FIXME: We probably need to resolve start promise with the result of the start algorithm. - startPromiseCapability.@resolve.@call(); - }, (error) => { - startPromiseCapability.@reject.@call(@undefined, error); - }); - } else - startPromiseCapability.@resolve.@call(); - - return this; -} - -@getter -function readable() -{ - "use strict"; - - if (!@isTransformStream(this)) - throw @makeThisTypeError("TransformStream", "readable"); - - return @getByIdDirectPrivate(this, "readable"); -} - -function writable() -{ - "use strict"; - - if (!@isTransformStream(this)) - throw @makeThisTypeError("TransformStream", "writable"); - - return @getByIdDirectPrivate(this, "writable"); -} diff --git a/src/bun.js/builtins/js/TransformStreamDefaultController.js b/src/bun.js/builtins/js/TransformStreamDefaultController.js deleted file mode 100644 index 5ed7d0dfa..000000000 --- a/src/bun.js/builtins/js/TransformStreamDefaultController.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2020 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -function initializeTransformStreamDefaultController() -{ - "use strict"; - - return this; -} - -@getter -function desiredSize() -{ - "use strict"; - - if (!@isTransformStreamDefaultController(this)) - throw @makeThisTypeError("TransformStreamDefaultController", "enqueue"); - - const stream = @getByIdDirectPrivate(this, "stream"); - const readable = @getByIdDirectPrivate(stream, "readable"); - const readableController = @getByIdDirectPrivate(readable, "readableStreamController"); - - return @readableStreamDefaultControllerGetDesiredSize(readableController); -} - -function enqueue(chunk) -{ - "use strict"; - - if (!@isTransformStreamDefaultController(this)) - throw @makeThisTypeError("TransformStreamDefaultController", "enqueue"); - - @transformStreamDefaultControllerEnqueue(this, chunk); -} - -function error(e) -{ - "use strict"; - - if (!@isTransformStreamDefaultController(this)) - throw @makeThisTypeError("TransformStreamDefaultController", "error"); - - @transformStreamDefaultControllerError(this, e); -} - -function terminate() -{ - "use strict"; - - if (!@isTransformStreamDefaultController(this)) - throw @makeThisTypeError("TransformStreamDefaultController", "terminate"); - - @transformStreamDefaultControllerTerminate(this); -} diff --git a/src/bun.js/builtins/js/TransformStreamInternals.js b/src/bun.js/builtins/js/TransformStreamInternals.js deleted file mode 100644 index 4263e3991..000000000 --- a/src/bun.js/builtins/js/TransformStreamInternals.js +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2020 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -// @internal - -function isTransformStream(stream) -{ - "use strict"; - - return @isObject(stream) && !!@getByIdDirectPrivate(stream, "readable"); -} - -function isTransformStreamDefaultController(controller) -{ - "use strict"; - - return @isObject(controller) && !!@getByIdDirectPrivate(controller, "transformAlgorithm"); -} - -function createTransformStream(startAlgorithm, transformAlgorithm, flushAlgorithm, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm) -{ - if (writableHighWaterMark === @undefined) - writableHighWaterMark = 1; - if (writableSizeAlgorithm === @undefined) - writableSizeAlgorithm = () => 1; - if (readableHighWaterMark === @undefined) - readableHighWaterMark = 0; - if (readableSizeAlgorithm === @undefined) - readableSizeAlgorithm = () => 1; - @assert(writableHighWaterMark >= 0); - @assert(readableHighWaterMark >= 0); - - const transform = {}; - @putByIdDirectPrivate(transform, "TransformStream", true); - - const stream = new @TransformStream(transform); - const startPromiseCapability = @newPromiseCapability(@Promise); - @initializeTransformStream(stream, startPromiseCapability.@promise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm); - - const controller = new @TransformStreamDefaultController(); - @setUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm); - - startAlgorithm().@then(() => { - startPromiseCapability.@resolve.@call(); - }, (error) => { - startPromiseCapability.@reject.@call(@undefined, error); - }); - - return stream; -} - -function initializeTransformStream(stream, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm) -{ - "use strict"; - - const startAlgorithm = () => { return startPromise; }; - const writeAlgorithm = (chunk) => { return @transformStreamDefaultSinkWriteAlgorithm(stream, chunk); } - const abortAlgorithm = (reason) => { return @transformStreamDefaultSinkAbortAlgorithm(stream, reason); } - const closeAlgorithm = () => { return @transformStreamDefaultSinkCloseAlgorithm(stream); } - const writable = @createWritableStream(startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, writableHighWaterMark, writableSizeAlgorithm); - - const pullAlgorithm = () => { return @transformStreamDefaultSourcePullAlgorithm(stream); }; - const cancelAlgorithm = (reason) => { - @transformStreamErrorWritableAndUnblockWrite(stream, reason); - return @Promise.@resolve(); - }; - const underlyingSource = { }; - @putByIdDirectPrivate(underlyingSource, "start", startAlgorithm); - @putByIdDirectPrivate(underlyingSource, "pull", pullAlgorithm); - @putByIdDirectPrivate(underlyingSource, "cancel", cancelAlgorithm); - const options = { }; - @putByIdDirectPrivate(options, "size", readableSizeAlgorithm); - @putByIdDirectPrivate(options, "highWaterMark", readableHighWaterMark); - const readable = new @ReadableStream(underlyingSource, options); - - // The writable to expose to JS through writable getter. - @putByIdDirectPrivate(stream, "writable", writable); - // The writable to use for the actual transform algorithms. - @putByIdDirectPrivate(stream, "internalWritable", @getInternalWritableStream(writable)); - - @putByIdDirectPrivate(stream, "readable", readable); - @putByIdDirectPrivate(stream, "backpressure", @undefined); - @putByIdDirectPrivate(stream, "backpressureChangePromise", @undefined); - - @transformStreamSetBackpressure(stream, true); - @putByIdDirectPrivate(stream, "controller", @undefined); -} - -function transformStreamError(stream, e) -{ - "use strict"; - - const readable = @getByIdDirectPrivate(stream, "readable"); - const readableController = @getByIdDirectPrivate(readable, "readableStreamController"); - @readableStreamDefaultControllerError(readableController, e); - - @transformStreamErrorWritableAndUnblockWrite(stream, e); -} - -function transformStreamErrorWritableAndUnblockWrite(stream, e) -{ - "use strict"; - - @transformStreamDefaultControllerClearAlgorithms(@getByIdDirectPrivate(stream, "controller")); - - const writable = @getByIdDirectPrivate(stream, "internalWritable"); - @writableStreamDefaultControllerErrorIfNeeded(@getByIdDirectPrivate(writable, "controller"), e); - - if (@getByIdDirectPrivate(stream, "backpressure")) - @transformStreamSetBackpressure(stream, false); -} - -function transformStreamSetBackpressure(stream, backpressure) -{ - "use strict"; - - @assert(@getByIdDirectPrivate(stream, "backpressure") !== backpressure); - - const backpressureChangePromise = @getByIdDirectPrivate(stream, "backpressureChangePromise"); - if (backpressureChangePromise !== @undefined) - backpressureChangePromise.@resolve.@call(); - - @putByIdDirectPrivate(stream, "backpressureChangePromise", @newPromiseCapability(@Promise)); - @putByIdDirectPrivate(stream, "backpressure", backpressure); -} - -function setUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm) -{ - "use strict"; - - @assert(@isTransformStream(stream)); - @assert(@getByIdDirectPrivate(stream, "controller") === @undefined); - - @putByIdDirectPrivate(controller, "stream", stream); - @putByIdDirectPrivate(stream, "controller", controller); - @putByIdDirectPrivate(controller, "transformAlgorithm", transformAlgorithm); - @putByIdDirectPrivate(controller, "flushAlgorithm", flushAlgorithm); -} - - -function setUpTransformStreamDefaultControllerFromTransformer(stream, transformer, transformerDict) -{ - "use strict"; - - const controller = new @TransformStreamDefaultController(); - let transformAlgorithm = (chunk) => { - try { - @transformStreamDefaultControllerEnqueue(controller, chunk); - } catch (e) { - return @Promise.@reject(e); - } - return @Promise.@resolve(); - }; - let flushAlgorithm = () => { return @Promise.@resolve(); }; - - if ("transform" in transformerDict) - transformAlgorithm = (chunk) => { - return @promiseInvokeOrNoopMethod(transformer, transformerDict["transform"], [chunk, controller]); - }; - - if ("flush" in transformerDict) { - flushAlgorithm = () => { - return @promiseInvokeOrNoopMethod(transformer, transformerDict["flush"], [controller]); - }; - } - - @setUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm); -} - -function transformStreamDefaultControllerClearAlgorithms(controller) -{ - "use strict"; - - // We set transformAlgorithm to true to allow GC but keep the isTransformStreamDefaultController check. - @putByIdDirectPrivate(controller, "transformAlgorithm", true); - @putByIdDirectPrivate(controller, "flushAlgorithm", @undefined); -} - -function transformStreamDefaultControllerEnqueue(controller, chunk) -{ - "use strict"; - - const stream = @getByIdDirectPrivate(controller, "stream"); - const readable = @getByIdDirectPrivate(stream, "readable"); - const readableController = @getByIdDirectPrivate(readable, "readableStreamController"); - - @assert(readableController !== @undefined); - if (!@readableStreamDefaultControllerCanCloseOrEnqueue(readableController)) - @throwTypeError("TransformStream.readable cannot close or enqueue"); - - try { - @readableStreamDefaultControllerEnqueue(readableController, chunk); - } catch (e) { - @transformStreamErrorWritableAndUnblockWrite(stream, e); - throw @getByIdDirectPrivate(readable, "storedError"); - } - - const backpressure = !@readableStreamDefaultControllerShouldCallPull(readableController); - if (backpressure !== @getByIdDirectPrivate(stream, "backpressure")) { - @assert(backpressure); - @transformStreamSetBackpressure(stream, true); - } -} - -function transformStreamDefaultControllerError(controller, e) -{ - "use strict"; - - @transformStreamError(@getByIdDirectPrivate(controller, "stream"), e); -} - -function transformStreamDefaultControllerPerformTransform(controller, chunk) -{ - "use strict"; - - const promiseCapability = @newPromiseCapability(@Promise); - - const transformPromise = @getByIdDirectPrivate(controller, "transformAlgorithm").@call(@undefined, chunk); - transformPromise.@then(() => { - promiseCapability.@resolve(); - }, (r) => { - @transformStreamError(@getByIdDirectPrivate(controller, "stream"), r); - promiseCapability.@reject.@call(@undefined, r); - }); - return promiseCapability.@promise; -} - -function transformStreamDefaultControllerTerminate(controller) -{ - "use strict"; - - const stream = @getByIdDirectPrivate(controller, "stream"); - const readable = @getByIdDirectPrivate(stream, "readable"); - const readableController = @getByIdDirectPrivate(readable, "readableStreamController"); - - // FIXME: Update readableStreamDefaultControllerClose to make this check. - if (@readableStreamDefaultControllerCanCloseOrEnqueue(readableController)) - @readableStreamDefaultControllerClose(readableController); - const error = @makeTypeError("the stream has been terminated"); - @transformStreamErrorWritableAndUnblockWrite(stream, error); -} - -function transformStreamDefaultSinkWriteAlgorithm(stream, chunk) -{ - "use strict"; - - const writable = @getByIdDirectPrivate(stream, "internalWritable"); - - @assert(@getByIdDirectPrivate(writable, "state") === "writable"); - - const controller = @getByIdDirectPrivate(stream, "controller"); - - if (@getByIdDirectPrivate(stream, "backpressure")) { - const promiseCapability = @newPromiseCapability(@Promise); - - const backpressureChangePromise = @getByIdDirectPrivate(stream, "backpressureChangePromise"); - @assert(backpressureChangePromise !== @undefined); - backpressureChangePromise.@promise.@then(() => { - const state = @getByIdDirectPrivate(writable, "state"); - if (state === "erroring") { - promiseCapability.@reject.@call(@undefined, @getByIdDirectPrivate(writable, "storedError")); - return; - } - - @assert(state === "writable"); - @transformStreamDefaultControllerPerformTransform(controller, chunk).@then(() => { - promiseCapability.@resolve(); - }, (e) => { - promiseCapability.@reject.@call(@undefined, e); - }); - }, (e) => { - promiseCapability.@reject.@call(@undefined, e); - }); - - return promiseCapability.@promise; - } - return @transformStreamDefaultControllerPerformTransform(controller, chunk); -} - -function transformStreamDefaultSinkAbortAlgorithm(stream, reason) -{ - "use strict"; - - @transformStreamError(stream, reason); - return @Promise.@resolve(); -} - -function transformStreamDefaultSinkCloseAlgorithm(stream) -{ - "use strict"; - const readable = @getByIdDirectPrivate(stream, "readable"); - const controller = @getByIdDirectPrivate(stream, "controller"); - const readableController = @getByIdDirectPrivate(readable, "readableStreamController"); - - const flushAlgorithm = @getByIdDirectPrivate(controller, "flushAlgorithm"); - @assert(flushAlgorithm !== @undefined); - const flushPromise = @getByIdDirectPrivate(controller, "flushAlgorithm").@call(); - @transformStreamDefaultControllerClearAlgorithms(controller); - - const promiseCapability = @newPromiseCapability(@Promise); - flushPromise.@then(() => { - if (@getByIdDirectPrivate(readable, "state") === @streamErrored) { - promiseCapability.@reject.@call(@undefined, @getByIdDirectPrivate(readable, "storedError")); - return; - } - - // FIXME: Update readableStreamDefaultControllerClose to make this check. - if (@readableStreamDefaultControllerCanCloseOrEnqueue(readableController)) - @readableStreamDefaultControllerClose(readableController); - promiseCapability.@resolve(); - }, (r) => { - @transformStreamError(@getByIdDirectPrivate(controller, "stream"), r); - promiseCapability.@reject.@call(@undefined, @getByIdDirectPrivate(readable, "storedError")); - }); - return promiseCapability.@promise; -} - -function transformStreamDefaultSourcePullAlgorithm(stream) -{ - "use strict"; - - @assert(@getByIdDirectPrivate(stream, "backpressure")); - @assert(@getByIdDirectPrivate(stream, "backpressureChangePromise") !== @undefined); - - @transformStreamSetBackpressure(stream, false); - - return @getByIdDirectPrivate(stream, "backpressureChangePromise").@promise; -} diff --git a/src/bun.js/builtins/js/WritableStreamDefaultController.js b/src/bun.js/builtins/js/WritableStreamDefaultController.js deleted file mode 100644 index 8c42212e0..000000000 --- a/src/bun.js/builtins/js/WritableStreamDefaultController.js +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2020 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - - -function initializeWritableStreamDefaultController() -{ - "use strict"; - - @putByIdDirectPrivate(this, "queue", @newQueue()); - @putByIdDirectPrivate(this, "abortSteps", (reason) => { - const result = @getByIdDirectPrivate(this, "abortAlgorithm").@call(@undefined, reason); - @writableStreamDefaultControllerClearAlgorithms(this); - return result; - }); - - @putByIdDirectPrivate(this, "errorSteps", () => { - @resetQueue(@getByIdDirectPrivate(this, "queue")); - }); - - return this; -} - -function error(e) -{ - "use strict"; - - if (@getByIdDirectPrivate(this, "abortSteps") === @undefined) - throw @makeThisTypeError("WritableStreamDefaultController", "error"); - - const stream = @getByIdDirectPrivate(this, "stream"); - if (@getByIdDirectPrivate(stream, "state") !== "writable") - return; - @writableStreamDefaultControllerError(this, e); -} diff --git a/src/bun.js/builtins/js/WritableStreamDefaultWriter.js b/src/bun.js/builtins/js/WritableStreamDefaultWriter.js deleted file mode 100644 index 69a953fc3..000000000 --- a/src/bun.js/builtins/js/WritableStreamDefaultWriter.js +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2020 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF - * THE POSSIBILITY OF SUCH DAMAGE. - */ - -function initializeWritableStreamDefaultWriter(stream) -{ - "use strict"; - - // stream can be a WritableStream if WritableStreamDefaultWriter constructor is called directly from JS - // or an InternalWritableStream in other code paths. - const internalStream = @getInternalWritableStream(stream); - if (internalStream) - stream = internalStream; - - if (!@isWritableStream(stream)) - @throwTypeError("WritableStreamDefaultWriter constructor takes a WritableStream"); - - @setUpWritableStreamDefaultWriter(this, stream); - return this; -} - -@getter -function closed() -{ - "use strict"; - - if (!@isWritableStreamDefaultWriter(this)) - return @Promise.@reject(@makeGetterTypeError("WritableStreamDefaultWriter", "closed")); - - return @getByIdDirectPrivate(this, "closedPromise").@promise; -} - -@getter -function desiredSize() -{ - "use strict"; - - if (!@isWritableStreamDefaultWriter(this)) - throw @makeThisTypeError("WritableStreamDefaultWriter", "desiredSize"); - - if (@getByIdDirectPrivate(this, "stream") === @undefined) - @throwTypeError("WritableStreamDefaultWriter has no stream"); - - return @writableStreamDefaultWriterGetDesiredSize(this); -} - -@getter -function ready() -{ - "use strict"; - - if (!@isWritableStreamDefaultWriter(this)) - return @Promise.@reject(@makeThisTypeError("WritableStreamDefaultWriter", "ready")); - - return @getByIdDirectPrivate(this, "readyPromise").@promise; -} - -function abort(reason) -{ - "use strict"; - - if (!@isWritableStreamDefaultWriter(this)) - return @Promise.@reject(@makeThisTypeError("WritableStreamDefaultWriter", "abort")); - - if (@getByIdDirectPrivate(this, "stream") === @undefined) - return @Promise.@reject(@makeTypeError("WritableStreamDefaultWriter has no stream")); - - return @writableStreamDefaultWriterAbort(this, reason); -} - -function close() -{ - "use strict"; - - if (!@isWritableStreamDefaultWriter(this)) - return @Promise.@reject(@makeThisTypeError("WritableStreamDefaultWriter", "close")); - - const stream = @getByIdDirectPrivate(this, "stream"); - if (stream === @undefined) - return @Promise.@reject(@makeTypeError("WritableStreamDefaultWriter has no stream")); - - if (@writableStreamCloseQueuedOrInFlight(stream)) - return @Promise.@reject(@makeTypeError("WritableStreamDefaultWriter is being closed")); - - return @writableStreamDefaultWriterClose(this); -} - -function releaseLock() -{ - "use strict"; - - if (!@isWritableStreamDefaultWriter(this)) - throw @makeThisTypeError("WritableStreamDefaultWriter", "releaseLock"); - - const stream = @getByIdDirectPrivate(this, "stream"); - if (stream === @undefined) - return; - - @assert(@getByIdDirectPrivate(stream, "writer") !== @undefined); - @writableStreamDefaultWriterRelease(this); -} - -function write(chunk) -{ - "use strict"; - - if (!@isWritableStreamDefaultWriter(this)) - return @Promise.@reject(@makeThisTypeError("WritableStreamDefaultWriter", "write")); - - if (@getByIdDirectPrivate(this, "stream") === @undefined) - return @Promise.@reject(@makeTypeError("WritableStreamDefaultWriter has no stream")); - - return @writableStreamDefaultWriterWrite(this, chunk); -} diff --git a/src/bun.js/builtins/js/WritableStreamInternals.js b/src/bun.js/builtins/js/WritableStreamInternals.js deleted file mode 100644 index 58c4ee87c..000000000 --- a/src/bun.js/builtins/js/WritableStreamInternals.js +++ /dev/null @@ -1,858 +0,0 @@ -/* - * Copyright (C) 2015 Canon Inc. - * Copyright (C) 2015 Igalia - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// @internal - -function isWritableStream(stream) -{ - "use strict"; - - return @isObject(stream) && !!@getByIdDirectPrivate(stream, "underlyingSink"); -} - -function isWritableStreamDefaultWriter(writer) -{ - "use strict"; - - return @isObject(writer) && !!@getByIdDirectPrivate(writer, "closedPromise"); -} - -function acquireWritableStreamDefaultWriter(stream) -{ - return new @WritableStreamDefaultWriter(stream); -} - -// https://streams.spec.whatwg.org/#create-writable-stream -function createWritableStream(startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm) -{ - @assert(typeof highWaterMark === "number" && !@isNaN(highWaterMark) && highWaterMark >= 0); - - const internalStream = { }; - @initializeWritableStreamSlots(internalStream, { }); - const controller = new @WritableStreamDefaultController(); - - @setUpWritableStreamDefaultController(internalStream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm); - - return @createWritableStreamFromInternal(internalStream); -} - -function createInternalWritableStreamFromUnderlyingSink(underlyingSink, strategy) -{ - "use strict"; - - const stream = { }; - - if (underlyingSink === @undefined) - underlyingSink = { }; - - if (strategy === @undefined) - strategy = { }; - - if (!@isObject(underlyingSink)) - @throwTypeError("WritableStream constructor takes an object as first argument"); - - if ("type" in underlyingSink) - @throwRangeError("Invalid type is specified"); - - const sizeAlgorithm = @extractSizeAlgorithm(strategy); - const highWaterMark = @extractHighWaterMark(strategy, 1); - - const underlyingSinkDict = { }; - if ("start" in underlyingSink) { - underlyingSinkDict["start"] = underlyingSink["start"]; - if (typeof underlyingSinkDict["start"] !== "function") - @throwTypeError("underlyingSink.start should be a function"); - } - if ("write" in underlyingSink) { - underlyingSinkDict["write"] = underlyingSink["write"]; - if (typeof underlyingSinkDict["write"] !== "function") - @throwTypeError("underlyingSink.write should be a function"); - } - if ("close" in underlyingSink) { - underlyingSinkDict["close"] = underlyingSink["close"]; - if (typeof underlyingSinkDict["close"] !== "function") - @throwTypeError("underlyingSink.close should be a function"); - } - if ("abort" in underlyingSink) { - underlyingSinkDict["abort"] = underlyingSink["abort"]; - if (typeof underlyingSinkDict["abort"] !== "function") - @throwTypeError("underlyingSink.abort should be a function"); - } - - @initializeWritableStreamSlots(stream, underlyingSink); - @setUpWritableStreamDefaultControllerFromUnderlyingSink(stream, underlyingSink, underlyingSinkDict, highWaterMark, sizeAlgorithm); - - return stream; -} - -function initializeWritableStreamSlots(stream, underlyingSink) -{ "use strict"; - - @putByIdDirectPrivate(stream, "state", "writable"); - @putByIdDirectPrivate(stream, "storedError", @undefined); - @putByIdDirectPrivate(stream, "writer", @undefined); - @putByIdDirectPrivate(stream, "controller", @undefined); - @putByIdDirectPrivate(stream, "inFlightWriteRequest", @undefined); - @putByIdDirectPrivate(stream, "closeRequest", @undefined); - @putByIdDirectPrivate(stream, "inFlightCloseRequest", @undefined); - @putByIdDirectPrivate(stream, "pendingAbortRequest", @undefined); - @putByIdDirectPrivate(stream, "writeRequests", @createFIFO()); - @putByIdDirectPrivate(stream, "backpressure", false); - @putByIdDirectPrivate(stream, "underlyingSink", underlyingSink); -} - -function writableStreamCloseForBindings(stream) -{ "use strict"; - - if (@isWritableStreamLocked(stream)) - return @Promise.@reject(@makeTypeError("WritableStream.close method can only be used on non locked WritableStream")); - - if (@writableStreamCloseQueuedOrInFlight(stream)) - return @Promise.@reject(@makeTypeError("WritableStream.close method can only be used on a being close WritableStream")); - - return @writableStreamClose(stream); -} - -function writableStreamAbortForBindings(stream, reason) -{ "use strict"; - - if (@isWritableStreamLocked(stream)) - return @Promise.@reject(@makeTypeError("WritableStream.abort method can only be used on non locked WritableStream")); - - return @writableStreamAbort(stream, reason); -} - -function isWritableStreamLocked(stream) -{ "use strict"; - - return @getByIdDirectPrivate(stream, "writer") !== @undefined; -} - -function setUpWritableStreamDefaultWriter(writer, stream) -{ "use strict"; - - if (@isWritableStreamLocked(stream)) - @throwTypeError("WritableStream is locked"); - - @putByIdDirectPrivate(writer, "stream", stream); - @putByIdDirectPrivate(stream, "writer", writer); - - const readyPromiseCapability = @newPromiseCapability(@Promise); - const closedPromiseCapability = @newPromiseCapability(@Promise); - @putByIdDirectPrivate(writer, "readyPromise", readyPromiseCapability); - @putByIdDirectPrivate(writer, "closedPromise", closedPromiseCapability); - - const state = @getByIdDirectPrivate(stream, "state"); - if (state === "writable") { - if (@writableStreamCloseQueuedOrInFlight(stream) || !@getByIdDirectPrivate(stream, "backpressure")) - readyPromiseCapability.@resolve.@call(); - } else if (state === "erroring") { - readyPromiseCapability.@reject.@call(@undefined, @getByIdDirectPrivate(stream, "storedError")); - @markPromiseAsHandled(readyPromiseCapability.@promise); - } else if (state === "closed") { - readyPromiseCapability.@resolve.@call(); - closedPromiseCapability.@resolve.@call(); - } else { - @assert(state === "errored"); - const storedError = @getByIdDirectPrivate(stream, "storedError"); - readyPromiseCapability.@reject.@call(@undefined, storedError); - @markPromiseAsHandled(readyPromiseCapability.@promise); - closedPromiseCapability.@reject.@call(@undefined, storedError); - @markPromiseAsHandled(closedPromiseCapability.@promise); - } -} - -function writableStreamAbort(stream, reason) -{ - "use strict"; - const state = @getByIdDirectPrivate(stream, "state"); - if (state === "closed" || state === "errored") - return @Promise.@resolve(); - - const pendingAbortRequest = @getByIdDirectPrivate(stream, "pendingAbortRequest"); - if (pendingAbortRequest !== @undefined) - return pendingAbortRequest.promise.@promise; - - @assert(state === "writable" || state === "erroring"); - let wasAlreadyErroring = false; - if (state === "erroring") { - wasAlreadyErroring = true; - reason = @undefined; - } - - const abortPromiseCapability = @newPromiseCapability(@Promise); - @putByIdDirectPrivate(stream, "pendingAbortRequest", { promise : abortPromiseCapability, reason : reason, wasAlreadyErroring : wasAlreadyErroring }); - - if (!wasAlreadyErroring) - @writableStreamStartErroring(stream, reason); - return abortPromiseCapability.@promise; -} - -function writableStreamClose(stream) -{ - "use strict"; - - const state = @getByIdDirectPrivate(stream, "state"); - if (state === "closed" || state === "errored") - return @Promise.@reject(@makeTypeError("Cannot close a writable stream that is closed or errored")); - - @assert(state === "writable" || state === "erroring"); - @assert(!@writableStreamCloseQueuedOrInFlight(stream)); - - const closePromiseCapability = @newPromiseCapability(@Promise); - @putByIdDirectPrivate(stream, "closeRequest", closePromiseCapability); - - const writer = @getByIdDirectPrivate(stream, "writer"); - if (writer !== @undefined && @getByIdDirectPrivate(stream, "backpressure") && state === "writable") - @getByIdDirectPrivate(writer, "readyPromise").@resolve.@call(); - - @writableStreamDefaultControllerClose(@getByIdDirectPrivate(stream, "controller")); - - return closePromiseCapability.@promise; -} - -function writableStreamAddWriteRequest(stream) -{ - "use strict"; - - @assert(@isWritableStreamLocked(stream)) - @assert(@getByIdDirectPrivate(stream, "state") === "writable"); - - const writePromiseCapability = @newPromiseCapability(@Promise); - const writeRequests = @getByIdDirectPrivate(stream, "writeRequests"); - writeRequests.push(writePromiseCapability); - return writePromiseCapability.@promise; -} - -function writableStreamCloseQueuedOrInFlight(stream) -{ - "use strict"; - - return @getByIdDirectPrivate(stream, "closeRequest") !== @undefined || @getByIdDirectPrivate(stream, "inFlightCloseRequest") !== @undefined; -} - -function writableStreamDealWithRejection(stream, error) -{ - "use strict"; - - const state = @getByIdDirectPrivate(stream, "state"); - if (state === "writable") { - @writableStreamStartErroring(stream, error); - return; - } - - @assert(state === "erroring"); - @writableStreamFinishErroring(stream); -} - -function writableStreamFinishErroring(stream) -{ - "use strict"; - - @assert(@getByIdDirectPrivate(stream, "state") === "erroring"); - @assert(!@writableStreamHasOperationMarkedInFlight(stream)); - - @putByIdDirectPrivate(stream, "state", "errored"); - - const controller = @getByIdDirectPrivate(stream, "controller"); - @getByIdDirectPrivate(controller, "errorSteps").@call(); - - const storedError = @getByIdDirectPrivate(stream, "storedError"); - const requests = @getByIdDirectPrivate(stream, "writeRequests"); - for (var request = requests.shift(); request; request = requests.shift()) - request.@reject.@call(@undefined, storedError); - - // TODO: is this still necessary? - @putByIdDirectPrivate(stream, "writeRequests", @createFIFO()); - - const abortRequest = @getByIdDirectPrivate(stream, "pendingAbortRequest"); - if (abortRequest === @undefined) { - @writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - return; - } - - @putByIdDirectPrivate(stream, "pendingAbortRequest", @undefined); - if (abortRequest.wasAlreadyErroring) { - abortRequest.promise.@reject.@call(@undefined, storedError); - @writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - return; - } - - @getByIdDirectPrivate(controller, "abortSteps").@call(@undefined, abortRequest.reason).@then(() => { - abortRequest.promise.@resolve.@call(); - @writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - }, (reason) => { - abortRequest.promise.@reject.@call(@undefined, reason); - @writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); - }); -} - -function writableStreamFinishInFlightClose(stream) -{ - "use strict"; - - const inFlightCloseRequest = @getByIdDirectPrivate(stream, "inFlightCloseRequest"); - inFlightCloseRequest.@resolve.@call(); - - @putByIdDirectPrivate(stream, "inFlightCloseRequest", @undefined); - - const state = @getByIdDirectPrivate(stream, "state"); - @assert(state === "writable" || state === "erroring"); - - if (state === "erroring") { - @putByIdDirectPrivate(stream, "storedError", @undefined); - const abortRequest = @getByIdDirectPrivate(stream, "pendingAbortRequest"); - if (abortRequest !== @undefined) { - abortRequest.promise.@resolve.@call(); - @putByIdDirectPrivate(stream, "pendingAbortRequest", @undefined); - } - } - - @putByIdDirectPrivate(stream, "state", "closed"); - - const writer = @getByIdDirectPrivate(stream, "writer"); - if (writer !== @undefined) - @getByIdDirectPrivate(writer, "closedPromise").@resolve.@call(); - - @assert(@getByIdDirectPrivate(stream, "pendingAbortRequest") === @undefined); - @assert(@getByIdDirectPrivate(stream, "storedError") === @undefined); -} - -function writableStreamFinishInFlightCloseWithError(stream, error) -{ - "use strict"; - - const inFlightCloseRequest = @getByIdDirectPrivate(stream, "inFlightCloseRequest"); - @assert(inFlightCloseRequest !== @undefined); - inFlightCloseRequest.@reject.@call(@undefined, error); - - @putByIdDirectPrivate(stream, "inFlightCloseRequest", @undefined); - - const state = @getByIdDirectPrivate(stream, "state"); - @assert(state === "writable" || state === "erroring"); - - const abortRequest = @getByIdDirectPrivate(stream, "pendingAbortRequest"); - if (abortRequest !== @undefined) { - abortRequest.promise.@reject.@call(@undefined, error); - @putByIdDirectPrivate(stream, "pendingAbortRequest", @undefined); - } - - @writableStreamDealWithRejection(stream, error); -} - -function writableStreamFinishInFlightWrite(stream) -{ - "use strict"; - - const inFlightWriteRequest = @getByIdDirectPrivate(stream, "inFlightWriteRequest"); - @assert(inFlightWriteRequest !== @undefined); - inFlightWriteRequest.@resolve.@call(); - - @putByIdDirectPrivate(stream, "inFlightWriteRequest", @undefined); -} - -function writableStreamFinishInFlightWriteWithError(stream, error) -{ - "use strict"; - - const inFlightWriteRequest = @getByIdDirectPrivate(stream, "inFlightWriteRequest"); - @assert(inFlightWriteRequest !== @undefined); - inFlightWriteRequest.@reject.@call(@undefined, error); - - @putByIdDirectPrivate(stream, "inFlightWriteRequest", @undefined); - - const state = @getByIdDirectPrivate(stream, "state"); - @assert(state === "writable" || state === "erroring"); - - @writableStreamDealWithRejection(stream, error); -} - -function writableStreamHasOperationMarkedInFlight(stream) -{ - "use strict"; - - return @getByIdDirectPrivate(stream, "inFlightWriteRequest") !== @undefined || @getByIdDirectPrivate(stream, "inFlightCloseRequest") !== @undefined; -} - -function writableStreamMarkCloseRequestInFlight(stream) -{ - "use strict"; - - const closeRequest = @getByIdDirectPrivate(stream, "closeRequest"); - @assert(@getByIdDirectPrivate(stream, "inFlightCloseRequest") === @undefined); - @assert(closeRequest !== @undefined); - - @putByIdDirectPrivate(stream, "inFlightCloseRequest", closeRequest); - @putByIdDirectPrivate(stream, "closeRequest", @undefined); -} - -function writableStreamMarkFirstWriteRequestInFlight(stream) -{ - "use strict"; - - const writeRequests = @getByIdDirectPrivate(stream, "writeRequests"); - @assert(@getByIdDirectPrivate(stream, "inFlightWriteRequest") === @undefined); - @assert(writeRequests.isNotEmpty()); - - const writeRequest = writeRequests.shift(); - @putByIdDirectPrivate(stream, "inFlightWriteRequest", writeRequest); -} - -function writableStreamRejectCloseAndClosedPromiseIfNeeded(stream) -{ - "use strict"; - - @assert(@getByIdDirectPrivate(stream, "state") === "errored"); - - const storedError = @getByIdDirectPrivate(stream, "storedError"); - - const closeRequest = @getByIdDirectPrivate(stream, "closeRequest"); - if (closeRequest !== @undefined) { - @assert(@getByIdDirectPrivate(stream, "inFlightCloseRequest") === @undefined); - closeRequest.@reject.@call(@undefined, storedError); - @putByIdDirectPrivate(stream, "closeRequest", @undefined); - } - - const writer = @getByIdDirectPrivate(stream, "writer"); - if (writer !== @undefined) { - const closedPromise = @getByIdDirectPrivate(writer, "closedPromise"); - closedPromise.@reject.@call(@undefined, storedError); - @markPromiseAsHandled(closedPromise.@promise); - } -} - -function writableStreamStartErroring(stream, reason) -{ - "use strict"; - - @assert(@getByIdDirectPrivate(stream, "storedError") === @undefined); - @assert(@getByIdDirectPrivate(stream, "state") === "writable"); - - const controller = @getByIdDirectPrivate(stream, "controller"); - @assert(controller !== @undefined); - - @putByIdDirectPrivate(stream, "state", "erroring"); - @putByIdDirectPrivate(stream, "storedError", reason); - - const writer = @getByIdDirectPrivate(stream, "writer"); - if (writer !== @undefined) - @writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason); - - if (!@writableStreamHasOperationMarkedInFlight(stream) && @getByIdDirectPrivate(controller, "started") === 1) - @writableStreamFinishErroring(stream); -} - -function writableStreamUpdateBackpressure(stream, backpressure) -{ - "use strict"; - @assert(@getByIdDirectPrivate(stream, "state") === "writable"); - @assert(!@writableStreamCloseQueuedOrInFlight(stream)); - - const writer = @getByIdDirectPrivate(stream, "writer"); - if (writer !== @undefined && backpressure !== @getByIdDirectPrivate(stream, "backpressure")) { - if (backpressure) - @putByIdDirectPrivate(writer, "readyPromise", @newPromiseCapability(@Promise)); - else - @getByIdDirectPrivate(writer, "readyPromise").@resolve.@call(); - } - @putByIdDirectPrivate(stream, "backpressure", backpressure); -} - -function writableStreamDefaultWriterAbort(writer, reason) -{ - "use strict"; - const stream = @getByIdDirectPrivate(writer, "stream"); - @assert(stream !== @undefined); - return @writableStreamAbort(stream, reason); -} - -function writableStreamDefaultWriterClose(writer) -{ - "use strict"; - const stream = @getByIdDirectPrivate(writer, "stream"); - @assert(stream !== @undefined); - return @writableStreamClose(stream); -} - -function writableStreamDefaultWriterCloseWithErrorPropagation(writer) -{ - "use strict"; - const stream = @getByIdDirectPrivate(writer, "stream"); - @assert(stream !== @undefined); - - const state = @getByIdDirectPrivate(stream, "state"); - - if (@writableStreamCloseQueuedOrInFlight(stream) || state === "closed") - return @Promise.@resolve(); - - if (state === "errored") - return @Promise.@reject(@getByIdDirectPrivate(stream, "storedError")); - - @assert(state === "writable" || state === "erroring"); - return @writableStreamDefaultWriterClose(writer); -} - -function writableStreamDefaultWriterEnsureClosedPromiseRejected(writer, error) -{ - "use strict"; - let closedPromiseCapability = @getByIdDirectPrivate(writer, "closedPromise"); - let closedPromise = closedPromiseCapability.@promise; - - if ((@getPromiseInternalField(closedPromise, @promiseFieldFlags) & @promiseStateMask) !== @promiseStatePending) { - closedPromiseCapability = @newPromiseCapability(@Promise); - closedPromise = closedPromiseCapability.@promise; - @putByIdDirectPrivate(writer, "closedPromise", closedPromiseCapability); - } - - closedPromiseCapability.@reject.@call(@undefined, error); - @markPromiseAsHandled(closedPromise); -} - -function writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error) -{ - "use strict"; - let readyPromiseCapability = @getByIdDirectPrivate(writer, "readyPromise"); - let readyPromise = readyPromiseCapability.@promise; - - if ((@getPromiseInternalField(readyPromise, @promiseFieldFlags) & @promiseStateMask) !== @promiseStatePending) { - readyPromiseCapability = @newPromiseCapability(@Promise); - readyPromise = readyPromiseCapability.@promise; - @putByIdDirectPrivate(writer, "readyPromise", readyPromiseCapability); - } - - readyPromiseCapability.@reject.@call(@undefined, error); - @markPromiseAsHandled(readyPromise); -} - -function writableStreamDefaultWriterGetDesiredSize(writer) -{ - "use strict"; - const stream = @getByIdDirectPrivate(writer, "stream"); - @assert(stream !== @undefined); - - const state = @getByIdDirectPrivate(stream, "state"); - - if (state === "errored" || state === "erroring") - return null; - - if (state === "closed") - return 0; - - return @writableStreamDefaultControllerGetDesiredSize(@getByIdDirectPrivate(stream, "controller")); -} - -function writableStreamDefaultWriterRelease(writer) -{ - "use strict"; - - const stream = @getByIdDirectPrivate(writer, "stream"); - @assert(stream !== @undefined); - @assert(@getByIdDirectPrivate(stream, "writer") === writer); - - const releasedError = @makeTypeError("writableStreamDefaultWriterRelease"); - - @writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError); - @writableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError); - - @putByIdDirectPrivate(stream, "writer", @undefined); - @putByIdDirectPrivate(writer, "stream", @undefined); -} - -function writableStreamDefaultWriterWrite(writer, chunk) -{ - "use strict"; - - const stream = @getByIdDirectPrivate(writer, "stream"); - @assert(stream !== @undefined); - - const controller = @getByIdDirectPrivate(stream, "controller"); - @assert(controller !== @undefined); - const chunkSize = @writableStreamDefaultControllerGetChunkSize(controller, chunk); - - if (stream !== @getByIdDirectPrivate(writer, "stream")) - return @Promise.@reject(@makeTypeError("writer is not stream's writer")); - - const state = @getByIdDirectPrivate(stream, "state"); - if (state === "errored") - return @Promise.@reject(@getByIdDirectPrivate(stream, "storedError")); - - if (@writableStreamCloseQueuedOrInFlight(stream) || state === "closed") - return @Promise.@reject(@makeTypeError("stream is closing or closed")); - - if (@writableStreamCloseQueuedOrInFlight(stream) || state === "closed") - return @Promise.@reject(@makeTypeError("stream is closing or closed")); - - if (state === "erroring") - return @Promise.@reject(@getByIdDirectPrivate(stream, "storedError")); - - @assert(state === "writable"); - - const promise = @writableStreamAddWriteRequest(stream); - @writableStreamDefaultControllerWrite(controller, chunk, chunkSize); - return promise; -} - -function setUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm) -{ - "use strict"; - - @assert(@isWritableStream(stream)); - @assert(@getByIdDirectPrivate(stream, "controller") === @undefined); - - @putByIdDirectPrivate(controller, "stream", stream); - @putByIdDirectPrivate(stream, "controller", controller); - - @resetQueue(@getByIdDirectPrivate(controller, "queue")); - - @putByIdDirectPrivate(controller, "started", -1); - @putByIdDirectPrivate(controller, "startAlgorithm", startAlgorithm); - @putByIdDirectPrivate(controller, "strategySizeAlgorithm", sizeAlgorithm); - @putByIdDirectPrivate(controller, "strategyHWM", highWaterMark); - @putByIdDirectPrivate(controller, "writeAlgorithm", writeAlgorithm); - @putByIdDirectPrivate(controller, "closeAlgorithm", closeAlgorithm); - @putByIdDirectPrivate(controller, "abortAlgorithm", abortAlgorithm); - - const backpressure = @writableStreamDefaultControllerGetBackpressure(controller); - @writableStreamUpdateBackpressure(stream, backpressure); - - @writableStreamDefaultControllerStart(controller); -} - -function writableStreamDefaultControllerStart(controller) { - "use strict"; - - if (@getByIdDirectPrivate(controller, "started") !== -1) - return; - - @putByIdDirectPrivate(controller, "started", 0); - - const startAlgorithm = @getByIdDirectPrivate(controller, "startAlgorithm"); - @putByIdDirectPrivate(controller, "startAlgorithm", @undefined); - const stream = @getByIdDirectPrivate(controller, "stream"); - return @Promise.@resolve(startAlgorithm.@call()).@then(() => { - const state = @getByIdDirectPrivate(stream, "state"); - @assert(state === "writable" || state === "erroring"); - @putByIdDirectPrivate(controller, "started", 1); - @writableStreamDefaultControllerAdvanceQueueIfNeeded(controller); - }, (error) => { - const state = @getByIdDirectPrivate(stream, "state"); - @assert(state === "writable" || state === "erroring"); - @putByIdDirectPrivate(controller, "started", 1); - @writableStreamDealWithRejection(stream, error); - }); -} - -function setUpWritableStreamDefaultControllerFromUnderlyingSink(stream, underlyingSink, underlyingSinkDict, highWaterMark, sizeAlgorithm) -{ - "use strict"; - const controller = new @WritableStreamDefaultController(); - - let startAlgorithm = () => { }; - let writeAlgorithm = () => { return @Promise.@resolve(); }; - let closeAlgorithm = () => { return @Promise.@resolve(); }; - let abortAlgorithm = () => { return @Promise.@resolve(); }; - - if ("start" in underlyingSinkDict) { - const startMethod = underlyingSinkDict["start"]; - startAlgorithm = () => @promiseInvokeOrNoopMethodNoCatch(underlyingSink, startMethod, [controller]); - } - if ("write" in underlyingSinkDict) { - const writeMethod = underlyingSinkDict["write"]; - writeAlgorithm = (chunk) => @promiseInvokeOrNoopMethod(underlyingSink, writeMethod, [chunk, controller]); - } - if ("close" in underlyingSinkDict) { - const closeMethod = underlyingSinkDict["close"]; - closeAlgorithm = () => @promiseInvokeOrNoopMethod(underlyingSink, closeMethod, []); - } - if ("abort" in underlyingSinkDict) { - const abortMethod = underlyingSinkDict["abort"]; - abortAlgorithm = (reason) => @promiseInvokeOrNoopMethod(underlyingSink, abortMethod, [reason]); - } - - @setUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm); -} - -function writableStreamDefaultControllerAdvanceQueueIfNeeded(controller) -{ - "use strict"; - const stream = @getByIdDirectPrivate(controller, "stream"); - - if (@getByIdDirectPrivate(controller, "started") !== 1) - return; - - @assert(stream !== @undefined); - if (@getByIdDirectPrivate(stream, "inFlightWriteRequest") !== @undefined) - return; - - const state = @getByIdDirectPrivate(stream, "state"); - @assert(state !== "closed" || state !== "errored"); - if (state === "erroring") { - @writableStreamFinishErroring(stream); - return; - } - - const queue = @getByIdDirectPrivate(controller, "queue"); - - if (queue.content?.isEmpty() ?? false) - return; - - const value = @peekQueueValue(queue); - if (value === @isCloseSentinel) - @writableStreamDefaultControllerProcessClose(controller); - else - @writableStreamDefaultControllerProcessWrite(controller, value); -} - -function isCloseSentinel() -{ -} - -function writableStreamDefaultControllerClearAlgorithms(controller) -{ - "use strict"; - @putByIdDirectPrivate(controller, "writeAlgorithm", @undefined); - @putByIdDirectPrivate(controller, "closeAlgorithm", @undefined); - @putByIdDirectPrivate(controller, "abortAlgorithm", @undefined); - @putByIdDirectPrivate(controller, "strategySizeAlgorithm", @undefined); -} - -function writableStreamDefaultControllerClose(controller) -{ - "use strict"; - @enqueueValueWithSize(@getByIdDirectPrivate(controller, "queue"), @isCloseSentinel, 0); - @writableStreamDefaultControllerAdvanceQueueIfNeeded(controller); -} - -function writableStreamDefaultControllerError(controller, error) -{ - "use strict"; - const stream = @getByIdDirectPrivate(controller, "stream"); - @assert(stream !== @undefined); - @assert(@getByIdDirectPrivate(stream, "state") === "writable"); - - @writableStreamDefaultControllerClearAlgorithms(controller); - @writableStreamStartErroring(stream, error); -} - -function writableStreamDefaultControllerErrorIfNeeded(controller, error) -{ - "use strict"; - const stream = @getByIdDirectPrivate(controller, "stream"); - if (@getByIdDirectPrivate(stream, "state") === "writable") - @writableStreamDefaultControllerError(controller, error); -} - -function writableStreamDefaultControllerGetBackpressure(controller) -{ - "use strict"; - const desiredSize = @writableStreamDefaultControllerGetDesiredSize(controller); - return desiredSize <= 0; -} - -function writableStreamDefaultControllerGetChunkSize(controller, chunk) -{ - "use strict"; - try { - return @getByIdDirectPrivate(controller, "strategySizeAlgorithm").@call(@undefined, chunk); - } catch (e) { - @writableStreamDefaultControllerErrorIfNeeded(controller, e); - return 1; - } -} - -function writableStreamDefaultControllerGetDesiredSize(controller) -{ - "use strict"; - return @getByIdDirectPrivate(controller, "strategyHWM") - @getByIdDirectPrivate(controller, "queue").size; -} - -function writableStreamDefaultControllerProcessClose(controller) -{ - "use strict"; - const stream = @getByIdDirectPrivate(controller, "stream"); - - @writableStreamMarkCloseRequestInFlight(stream); - @dequeueValue(@getByIdDirectPrivate(controller, "queue")); - - @assert(@getByIdDirectPrivate(controller, "queue").content?.isEmpty()); - - const sinkClosePromise = @getByIdDirectPrivate(controller, "closeAlgorithm").@call(); - @writableStreamDefaultControllerClearAlgorithms(controller); - - sinkClosePromise.@then(() => { - @writableStreamFinishInFlightClose(stream); - }, (reason) => { - @writableStreamFinishInFlightCloseWithError(stream, reason); - }); -} - -function writableStreamDefaultControllerProcessWrite(controller, chunk) -{ - "use strict"; - const stream = @getByIdDirectPrivate(controller, "stream"); - - @writableStreamMarkFirstWriteRequestInFlight(stream); - - const sinkWritePromise = @getByIdDirectPrivate(controller, "writeAlgorithm").@call(@undefined, chunk); - - sinkWritePromise.@then(() => { - @writableStreamFinishInFlightWrite(stream); - const state = @getByIdDirectPrivate(stream, "state"); - @assert(state === "writable" || state === "erroring"); - - @dequeueValue(@getByIdDirectPrivate(controller, "queue")); - if (!@writableStreamCloseQueuedOrInFlight(stream) && state === "writable") { - const backpressure = @writableStreamDefaultControllerGetBackpressure(controller); - @writableStreamUpdateBackpressure(stream, backpressure); - } - @writableStreamDefaultControllerAdvanceQueueIfNeeded(controller); - }, (reason) => { - const state = @getByIdDirectPrivate(stream, "state"); - if (state === "writable") - @writableStreamDefaultControllerClearAlgorithms(controller); - - @writableStreamFinishInFlightWriteWithError(stream, reason); - }); -} - -function writableStreamDefaultControllerWrite(controller, chunk, chunkSize) -{ - "use strict"; - try { - @enqueueValueWithSize(@getByIdDirectPrivate(controller, "queue"), chunk, chunkSize); - - const stream = @getByIdDirectPrivate(controller, "stream"); - - const state = @getByIdDirectPrivate(stream, "state"); - if (!@writableStreamCloseQueuedOrInFlight(stream) && state === "writable") { - const backpressure = @writableStreamDefaultControllerGetBackpressure(controller); - @writableStreamUpdateBackpressure(stream, backpressure); - } - @writableStreamDefaultControllerAdvanceQueueIfNeeded(controller); - } catch (e) { - @writableStreamDefaultControllerErrorIfNeeded(controller, e); - } -} |