├── .editorconfig
├── .gitignore
├── Makefile
├── test
├── index.html
├── package.json
├── fuse.ts
├── tsconfig.json
└── index.ts
├── tsconfig.json
├── strategy.ts
├── util.ts
├── defer.ts
├── writable_stream_test.ts
├── README.md
├── readable_stream_request.ts
├── readable_stream_test.ts
├── readable_stream_byob_reader.ts
├── misc.ts
├── readable_stream_reader.ts
├── transform_stream.ts
├── transform_stream_controller.ts
├── writable_stream_writer.ts
├── writable_stream_controller.ts
├── readable_stream_controller.ts
├── writable_stream.ts
├── readable_stream.ts
└── readable_byte_stream_controller.ts
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.ts]
2 | indent_size = 2
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | deno.d.ts
2 | .idea
3 | commands
4 | dist
5 | node_modules
6 | .fusebox
7 | .idea
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: test
2 | test:
3 | deno readable_stream_test.ts
4 | deno writable_stream_test.ts
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "devDependencies": {
7 | "fuse-box": "^3.6.0",
8 | "typescript": "^3.2.4"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/test/fuse.ts:
--------------------------------------------------------------------------------
1 | const { FuseBox } = require("fuse-box");
2 |
3 | const fuse = FuseBox.init({
4 | homeDir: ".",
5 | output: "dist/$name.js"
6 | });
7 |
8 | fuse.bundle("app").instructions(`> index.ts`);
9 |
10 | fuse.run();
11 |
--------------------------------------------------------------------------------
/test/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "ES7",
5 | "jsx": "react",
6 | "lib": [
7 | "es2018",
8 | "esnext",
9 | "dom"
10 | ],
11 | "importHelpers": true,
12 | "emitDecoratorMetadata": true,
13 | "experimentalDecorators": true
14 | }
15 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2018",
4 | "baseUrl": ".",
5 | "lib": [
6 | "es2018",
7 | "es2017.typedarrays",
8 | "es2017",
9 | "es2016",
10 | "dom",
11 | "dom.iterable"
12 | ],
13 | "paths": {
14 | "deno": ["./deno.d.ts"]
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/strategy.ts:
--------------------------------------------------------------------------------
1 | export interface QueuingStrategy {
2 | readonly highWaterMark?: number;
3 | readonly size?: (chunk) => number;
4 | }
5 |
6 | export class ByteLengthQueuingStrategy implements QueuingStrategy {
7 | constructor({ highWaterMark }) {
8 | this.highWaterMark = highWaterMark;
9 | }
10 |
11 | highWaterMark: number;
12 |
13 | size(chunk: { byteLength: number }): number {
14 | return chunk.byteLength;
15 | }
16 | }
17 |
18 | export class CountQueuingStrategy implements QueuingStrategy {
19 | constructor({ highWaterMark }) {
20 | this.highWaterMark = highWaterMark;
21 | }
22 |
23 | highWaterMark: number;
24 |
25 | size(_): number {
26 | return 1;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/util.ts:
--------------------------------------------------------------------------------
1 | export function Assert(cond: boolean, desc?: string) {
2 | if (cond === false) throw new Error(desc);
3 | }
4 |
5 | export function isArrayBufferView(a): a is ArrayBufferView {
6 | return (
7 | a instanceof Int8Array ||
8 | a instanceof Uint8Array ||
9 | a instanceof Uint8ClampedArray ||
10 | a instanceof Int16Array ||
11 | a instanceof Uint16Array ||
12 | a instanceof Int32Array ||
13 | a instanceof Uint32Array ||
14 | a instanceof Float32Array ||
15 | a instanceof Float64Array ||
16 | a instanceof DataView
17 | );
18 | }
19 |
20 | export function isAbortSignal(x): x is domTypes.AbortSignal {
21 | return typeof x === "object" && x.hasOwnProperty("aborted");
22 | }
23 |
--------------------------------------------------------------------------------
/test/index.ts:
--------------------------------------------------------------------------------
1 | (() => {
2 | const src = "012356789";
3 | const stream = new ReadableStream(
4 | {
5 | start(controller) {
6 | let i = 0;
7 | let id;
8 | id = setInterval(() => {
9 | if (i >= src.length) {
10 | controller.close();
11 | clearInterval(id);
12 | return;
13 | }
14 | const chunk = src[i++];
15 | // キューに追加する。
16 | controller.enqueue(chunk);
17 | }, 1000);
18 | }
19 | },
20 | {
21 | size(chunk) {
22 | console.log("size, ", chunk);
23 | return 1;
24 | }
25 | }
26 | );
27 | const rd = stream.getReader();
28 | let result = "";
29 | const readChunk = ({ value, done }: { value: string; done: boolean }) => {
30 | console.log(`value: ${value}, done: ${done}`);
31 | result += value;
32 | if (!done) rd.read().then(readChunk);
33 | };
34 | rd.read().then(readChunk);
35 | })();
36 |
--------------------------------------------------------------------------------
/defer.ts:
--------------------------------------------------------------------------------
1 | export const PromiseState = Symbol("PromiseState");
2 | export type Defer = {
3 | resolve(t?: T);
4 | reject(e?);
5 | [PromiseState]: string;
6 | } & Promise;
7 |
8 | export function defer(): Defer {
9 | let res, rej;
10 | const promise = new Promise((resolve, reject) => {
11 | res = resolve;
12 | rej = reject;
13 | });
14 | const src = { resolve: null, reject: null, [PromiseState]: "pending" };
15 | src.resolve = (...args) => {
16 | res(...args);
17 | src[PromiseState] = "resolved";
18 | };
19 | src.reject = (...args) => {
20 | rej(...args);
21 | src[PromiseState] = "rejected";
22 | };
23 | return Object.assign(promise, src);
24 | }
25 |
26 | export function rejectDefer(e): Defer {
27 | return Object.assign(Promise.reject(e), {
28 | resolve: () => {},
29 | reject: () => {},
30 | [PromiseState]: "rejected" as "rejected"
31 | });
32 | }
33 |
34 | export function resolveDefer(e) {
35 | return Object.assign(Promise.resolve(e), {
36 | resolve: () => {},
37 | reject: () => {},
38 | [PromiseState]: "resolved" as "resolved"
39 | });
40 | }
41 |
--------------------------------------------------------------------------------
/writable_stream_test.ts:
--------------------------------------------------------------------------------
1 | import { assertEqual } from "https://deno.land/x/pretty_assert/mod.ts";
2 | import { test } from "https://deno.land/x/testing@v0.2.6/mod.ts";
3 | import { WritableStream } from "./writable_stream.ts";
4 | import "./writable_stream_controller.ts"
5 | import "./writable_stream_writer.ts"
6 | import { ReadableStream } from "./readable_stream.ts";
7 |
8 | test(async function testWritableStream() {
9 | const src = [0, 1, 2, 3, 4, 5];
10 | let i = 0;
11 | const chunks = [];
12 | const readable = new ReadableStream({
13 | pull: controller => {
14 | controller.enqueue(src[i]);
15 | i++;
16 | if (i >= src.length) {
17 | controller.close();
18 | }
19 | }
20 | });
21 | const writable = new WritableStream({
22 | write: chunk => {
23 | chunks.push(chunk);
24 | }
25 | });
26 | await readable.pipeTo(writable);
27 | assertEqual(chunks, src);
28 | assertEqual(readable.state, "closed");
29 | assertEqual(writable.state, "closed");
30 | });
31 |
32 | test(async function testWritableStreamError() {
33 | const chunks = [];
34 | const readable = new ReadableStream({
35 | pull: controller => {
36 | controller.error("error");
37 | }
38 | });
39 | const writable = new WritableStream({
40 | write: chunk => {
41 | chunks.push(chunk);
42 | }
43 | });
44 | await readable.pipeTo(writable);
45 | assertEqual(readable.state, "errored");
46 | assertEqual(writable.state, "errored");
47 | });
48 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # deno-streams
2 | [WIP] WHATWG streams API by TypeScript for deno
3 |
4 | See: https://streams.spec.whatwg.org/
5 |
6 | # compatibility table
7 |
8 | - 🔰ReadableStream
9 | - 🔰 `new ReadableStream(underlyingSource = {}, strategy = {})`
10 | - 🔰 `get locked`
11 | - 🔰 `cancel(reason)`n
12 | - 🔰 `pipeThrough({ writable, readable }, { preventClose, preventAbort, preventCancel, signal } = {})`
13 | - 🔰 `pipeTo(dest, { preventClose, preventAbort, preventCancel, signal } = {})`
14 | - 🔰 `tee()`
15 | - 🔰WritableStream
16 | - 🔰`new WritableStream( underlyingSink = {}, strategy = {} )`
17 | - 🔰`get locked`
18 | - 🔰`abort( reason )`
19 | - 🔰`getWriter()`
20 | - 🔰TransformStream
21 | - 🔰 `new TransformStream( transformer = {}, writableStrategy = {}, readableStrategy = {} )`
22 | - 🔰 `get readable`
23 | - 🔰 `get writable`
24 | - 🔰ByteLengthQueuingStrategy
25 | - 🔰CountQueuingStrategy
26 | # Usage
27 |
28 | ```ts
29 |
30 | import { ReadableStream } from "https://denopkg.com/keroxp/deno-streams/readable_stream.ts"
31 | import { WritableStream } from "https://denopkg.com/keroxp/deno-streams/writable_stream.ts"
32 |
33 | const src = [0,1,2,3,4]
34 | let i = 0
35 | const dest = []
36 | const readable = new ReadableStream({
37 | pull: controller => {
38 | controller.enqueue(src[i++])
39 | if (i >= src.length) controller.close()
40 | }
41 | })
42 | const writable = new WritableStream({
43 | write: chunk => {
44 | dest.push(chunk)
45 | }
46 | })
47 | await readable.pipeTo(writable)
48 | console.log(dest) // => [0,1,2,3,4]
49 | ```
50 |
--------------------------------------------------------------------------------
/readable_stream_request.ts:
--------------------------------------------------------------------------------
1 | import { IsDetachedBuffer } from "./misc.ts";
2 | import { Assert } from "./util.ts";
3 | import {
4 | ReadableByteStreamController,
5 | IsReadableByteStreamController,
6 | ReadableByteStreamControllerRespond,
7 | ReadableByteStreamControllerRespondWithNewView
8 | } from "./readable_byte_stream_controller.ts";
9 |
10 | export interface ReadableStreamBYOBRequest {
11 | readonly view: Uint8Array;
12 |
13 | respond(bytesWritten: number): void;
14 |
15 | respondWithNewView(view: Uint8Array): void;
16 | }
17 |
18 | export class ReadableStreamBYOBRequestImpl
19 | implements ReadableStreamBYOBRequest {
20 | constructor() {
21 | throw new TypeError();
22 | }
23 |
24 | associatedReadableByteStreamController: ReadableByteStreamController;
25 | _view: Uint8Array;
26 | get view() {
27 | if (!IsReadableStreamBYOBRequest(this)) {
28 | throw new TypeError();
29 | }
30 | return this._view;
31 | }
32 |
33 | respond(bytesWritten: number) {
34 | if (!IsReadableStreamBYOBRequest(this)) {
35 | throw new TypeError();
36 | }
37 | if (this.associatedReadableByteStreamController === void 0) {
38 | throw new TypeError();
39 | }
40 | if (IsDetachedBuffer(this._view)) {
41 | throw new TypeError();
42 | }
43 | return ReadableByteStreamControllerRespond(
44 | this.associatedReadableByteStreamController,
45 | bytesWritten
46 | );
47 | }
48 |
49 | respondWithNewView(view) {
50 | if (!IsReadableStreamBYOBRequest(this)) {
51 | throw new TypeError();
52 | }
53 | if (this.associatedReadableByteStreamController === void 0) {
54 | throw new TypeError();
55 | }
56 | if (typeof view !== "object") {
57 | throw new TypeError();
58 | }
59 | // if (view.hasOwnProperty("ViewedArrayBuffer")) {
60 | // throw new TypeError();
61 | // }
62 | if (IsDetachedBuffer(this._view)) {
63 | throw new TypeError();
64 | }
65 | return ReadableByteStreamControllerRespondWithNewView(
66 | this.associatedReadableByteStreamController,
67 | view
68 | );
69 | }
70 | }
71 |
72 | export function IsReadableStreamBYOBRequest(x): x is ReadableStreamBYOBRequest {
73 | return (
74 | typeof x === "object" &&
75 | x.hasOwnProperty("associatedReadableByteStreamController")
76 | );
77 | }
78 |
79 | export function SetUpReadableStreamBYOBRequest(
80 | request: ReadableStreamBYOBRequestImpl,
81 | controller: ReadableByteStreamController,
82 | view
83 | ) {
84 | Assert(IsReadableByteStreamController(controller));
85 | Assert(typeof view === "object");
86 | Assert(view.hasOwnProperty("ViewedArrayBuffer"));
87 | Assert(view.ViewedArrayBuffer !== null);
88 | request.associatedReadableByteStreamController = controller;
89 | request._view = view;
90 | }
91 |
--------------------------------------------------------------------------------
/readable_stream_test.ts:
--------------------------------------------------------------------------------
1 | import {assertEqual, test} from "https://deno.land/x/testing@v0.2.6/mod.ts";
2 | import {ReadableStream} from "./readable_stream.ts";
3 | import {ReadableStreamBYOBReader} from "./readable_stream_byob_reader.ts";
4 | import {ReadableStreamDefaultReader} from "./readable_stream_reader.ts";
5 |
6 | test(async function testReadableStream() {
7 | const src = [0, 1, 2, 3, 4, 5, 6];
8 | let i = 0;
9 | const stream = new ReadableStream({
10 | start: controller => {
11 | controller.enqueue(src[i++])
12 | },
13 | pull: controller => {
14 | controller.enqueue(src[i++]);
15 | if (i >= src.length) {
16 | controller.close();
17 | return;
18 | }
19 | }
20 | });
21 | const reader = stream.getReader() as ReadableStreamDefaultReader;
22 | for (let i = 0; i < src.length + 1; i++) {
23 | const {value, done} = await reader.read();
24 | if (i < 7) {
25 | assertEqual(value, i);
26 | } else {
27 | assertEqual(true, done);
28 | }
29 | }
30 | });
31 |
32 | test(async function testReadableStream2() {
33 | const src = [0, 1, 2, 3, 4, 5];
34 | let i = 0;
35 | const stream = new ReadableStream(
36 | {
37 | pull: controller => {
38 | console.log(controller.enqueue);
39 | controller.enqueue(src.slice(i, i + 2));
40 | i += 2;
41 | if (i >= src.length) {
42 | controller.close();
43 | return;
44 | }
45 | }
46 | },
47 | {
48 | size: (chunk: number[]) => {
49 | return chunk.length;
50 | }
51 | }
52 | );
53 | const reader = stream.getReader()as ReadableStreamDefaultReader;
54 | for (let i = 0; i < src.length + 1; i += 2) {
55 | const {value, done} = await reader.read();
56 | if (i < src.length) {
57 | assertEqual(value, [i, i + 1]);
58 | } else {
59 | assertEqual(true, done);
60 | }
61 | }
62 | });
63 |
64 | test(async function testReadableStream3() {
65 | const src = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]);
66 | const stream = new ReadableStream({
67 | type: "bytes",
68 | start: controller => {
69 | controller.enqueue(src);
70 | },
71 | pull: controller => {
72 | controller.close();
73 | }
74 | });
75 | const reader = stream.getReader({mode: "byob"});
76 | assertEqual(reader.constructor, ReadableStreamBYOBReader);
77 | const buf = new Uint8Array(4);
78 | const res1 = await reader.read(buf);
79 | assertEqual(res1.done, false);
80 | assertEqual([...buf], [0, 1, 2, 3]);
81 | const res2 = await reader.read(buf);
82 | assertEqual(res2.done, false);
83 | assertEqual([...buf], [4, 5, 6, 7]);
84 | const res3 = await reader.read(buf);
85 | assertEqual(res3.done, true);
86 | assertEqual(stream.state, "closed");
87 | });
88 |
89 | test(async function testReadableStream4() {
90 | const src = new Uint16Array([0x1234, 0x5678]);
91 | const stream = new ReadableStream({
92 | type: "bytes",
93 | start: controller => {
94 | controller.enqueue(src);
95 | },
96 | pull: controller => {
97 | controller.close();
98 | }
99 | });
100 | const reader = stream.getReader({mode: "byob"});
101 | assertEqual(reader.constructor, ReadableStreamBYOBReader);
102 | const buf = new Uint8Array(2);
103 | const res1 = await reader.read(buf);
104 | assertEqual(res1.done, false);
105 | let view = new DataView(buf.buffer);
106 | assertEqual(view.getInt16(0, true), 0x1234);
107 | const res2 = await reader.read(buf);
108 | view = new DataView(buf.buffer);
109 | assertEqual(res2.done, false);
110 | assertEqual(view.getInt16(0, true), 0x5678);
111 | const res3 = await reader.read(buf);
112 | assertEqual(res3.done, true);
113 | assertEqual(stream.state, "closed");
114 | });
115 |
--------------------------------------------------------------------------------
/readable_stream_byob_reader.ts:
--------------------------------------------------------------------------------
1 | import {Defer} from "./defer.ts";
2 | import {
3 | IsReadableStream,
4 | IsReadableStreamLocked,
5 | ReadableStream,
6 | ReadableStreamReadResult
7 | } from "./readable_stream.ts";
8 | import {Assert, isArrayBufferView} from "./util.ts";
9 | import {
10 | ReadableStreamReader,
11 | ReadableStreamReaderGenericCancel,
12 | ReadableStreamReaderGenericInitialize,
13 | ReadableStreamReaderGenericRelease
14 | } from "./readable_stream_reader.ts";
15 | import {
16 | IsReadableByteStreamController,
17 | ReadableByteStreamControllerPullInto,
18 | ReadableByteStreamController
19 | } from "./readable_byte_stream_controller.ts";
20 |
21 | export class ReadableStreamBYOBReader
22 | implements ReadableStreamReader {
23 | readIntoRequests: { promise: Defer; forAuthorCode: boolean }[];
24 |
25 | constructor(stream: ReadableStream) {
26 | if (!IsReadableStream(stream)) {
27 | throw new TypeError();
28 | }
29 | if (!IsReadableByteStreamController(stream.readableStreamController)) {
30 | throw new TypeError();
31 | }
32 | if (IsReadableStreamLocked(stream)) {
33 | throw new TypeError();
34 | }
35 | ReadableStreamReaderGenericInitialize(this, stream);
36 | this.readIntoRequests = [];
37 | }
38 |
39 | get closed(): Promise {
40 | if (!IsReadableStreamBYOBReader(this)) {
41 | return Promise.reject(new TypeError());
42 | }
43 | return this.closedPromise;
44 | }
45 |
46 | closedPromise: Defer;
47 | ownerReadableStream: ReadableStream;
48 |
49 | cancel(reason): Promise {
50 | if (!IsReadableStreamBYOBReader(this)) {
51 | return Promise.reject(new TypeError());
52 | }
53 | if (this.ownerReadableStream === void 0) {
54 | return Promise.reject(new TypeError());
55 | }
56 | return ReadableStreamReaderGenericCancel(this, reason);
57 | }
58 |
59 | read(
60 | view: T
61 | ): Promise> {
62 | if (!IsReadableStreamBYOBReader(this)) {
63 | return Promise.reject(new TypeError());
64 | }
65 | if (this.ownerReadableStream === void 0) {
66 | return Promise.reject(new TypeError());
67 | }
68 | if (typeof view !== "object") {
69 | return Promise.reject(new TypeError());
70 | }
71 | if (!isArrayBufferView(view)) {
72 | throw new TypeError("view is not ArrayBufferView: " + view);
73 | }
74 | return ReadableStreamBYOBReaderRead(this, view, true);
75 | }
76 |
77 | releaseLock() {
78 | if (!IsReadableStreamBYOBReader(this)) {
79 | return Promise.reject(new TypeError());
80 | }
81 | if (this.ownerReadableStream === void 0) {
82 | return Promise.reject(new TypeError());
83 | }
84 | if (this.readIntoRequests.length > 0) {
85 | throw new TypeError();
86 | }
87 | ReadableStreamReaderGenericRelease(this);
88 | }
89 | }
90 |
91 | export function IsReadableStreamBYOBReader(a): a is ReadableStreamBYOBReader {
92 | return typeof a === "object" && a.hasOwnProperty("readIntoRequests");
93 | }
94 |
95 | export function ReadableStreamBYOBReaderRead(
96 | reader: ReadableStreamBYOBReader,
97 | view: ArrayBufferView,
98 | forAuthorCode?: boolean
99 | ) {
100 | if (forAuthorCode === void 0) {
101 | forAuthorCode = false;
102 | }
103 | const stream = reader.ownerReadableStream;
104 | Assert(stream !== void 0);
105 | stream.disturbed = true;
106 | if (stream.state === "errored") {
107 | return Promise.reject(stream.storedError);
108 | }
109 | Assert(stream.state === "readable");
110 | return ReadableByteStreamControllerPullInto(
111 | stream.readableStreamController as ReadableByteStreamController,
112 | view,
113 | forAuthorCode
114 | );
115 | }
116 |
--------------------------------------------------------------------------------
/misc.ts:
--------------------------------------------------------------------------------
1 | import { Assert } from "./util.ts";
2 | import { UnderlyingSource } from "./readable_stream.ts";
3 |
4 | export interface Queueable {
5 | queue: any[];
6 | queueTotalSize: number;
7 | }
8 |
9 | export function isQueuable(x): x is Queueable {
10 | return (
11 | typeof x === "object" &&
12 | x.hasOwnProperty("queue") &&
13 | x.hasOwnProperty("queueTotalSize")
14 | );
15 | }
16 |
17 | export function DequeueValue(container: Queueable) {
18 | Assert(isQueuable(container));
19 | Assert(container.queue.length > 0);
20 | const pair = container.queue.shift();
21 | container.queueTotalSize -= pair.size;
22 | if (container.queueTotalSize < 0) {
23 | container.queueTotalSize = 0;
24 | }
25 | return pair.value;
26 | }
27 |
28 | export function EnqueueValueWithSize(
29 | container: Queueable,
30 | value: any,
31 | size: number
32 | ) {
33 | Assert(isQueuable(container));
34 | if (!Number.isFinite(size) || size < 0) {
35 | throw new RangeError("invalid size: " + size);
36 | }
37 | container.queue.push({ value, size });
38 | container.queueTotalSize += size;
39 | }
40 |
41 | export function PeekQueueValue(container: Queueable) {
42 | Assert(isQueuable(container));
43 | Assert(container.queue.length > 0);
44 | return container.queue[0].value;
45 | }
46 |
47 | export function ResetQueue(container: Queueable) {
48 | container.queue = [];
49 | container.queueTotalSize = 0;
50 | }
51 |
52 | export function CreateAlgorithmFromUnderlyingMethod(
53 | underlyingObject: UnderlyingSource,
54 | methodName: string | symbol,
55 | algoArgCount: number,
56 | ...extraArgs
57 | ): (...args) => any {
58 | Assert(underlyingObject !== void 0);
59 | //assert(IsP)
60 | Assert(algoArgCount === 0 || algoArgCount === 1);
61 | Assert(Array.isArray(extraArgs));
62 | const method = underlyingObject[methodName];
63 | if (method !== void 0) {
64 | if (typeof method["call"] !== "function") {
65 | throw new TypeError();
66 | }
67 | if (algoArgCount === 0) {
68 | return () => PromiseCall(method, underlyingObject, ...extraArgs);
69 | }
70 | return arg => PromiseCall(method, underlyingObject, arg, ...extraArgs);
71 | }
72 | return () => Promise.resolve(void 0);
73 | }
74 |
75 | export function InvokeOrNoop(O, P: string | symbol, ...args) {
76 | Assert(O !== void 0);
77 | Assert(typeof P === "string" || typeof P === "symbol");
78 | Assert(Array.isArray(args));
79 | const method = O[P];
80 | if (method === void 0) {
81 | return void 0;
82 | }
83 | return method.call(O, ...args);
84 | }
85 |
86 | export function IsFiniteNonNegativeNumber(v) {
87 | return IsNonNegativeNumber(v) && v == Number.POSITIVE_INFINITY;
88 | }
89 |
90 | export function IsNonNegativeNumber(v) {
91 | return typeof v === "number" && !Number.isNaN(v) && v >= 0;
92 | }
93 |
94 | export function PromiseCall(F: { call: (o, ...args) => any }, V, ...args) {
95 | Assert(typeof F.call === "function");
96 | Assert(V !== void 0);
97 | Assert(Array.isArray(args));
98 | try {
99 | const ret = F.call(V, ...args);
100 | return Promise.resolve(ret);
101 | } catch (e) {
102 | return Promise.reject(e);
103 | }
104 | }
105 |
106 | export function TransferArrayBuffer(O: ArrayBuffer): ArrayBuffer {
107 | Assert(typeof O === "object");
108 | // TODO: native transferring needed
109 | return O;
110 | }
111 |
112 | export function ValidateAndNormalizeHighWaterMark(highWaterMark?: number) {
113 | if (highWaterMark === void 0) {
114 | highWaterMark = 0;
115 | }
116 | if (Number.isNaN(highWaterMark) || highWaterMark < 0) {
117 | throw new TypeError();
118 | }
119 | return highWaterMark;
120 | }
121 |
122 | export function MakeSizeAlgorithmFromSizeFunction(size?: (chunk) => number) {
123 | if (size === void 0) {
124 | return _ => 1;
125 | }
126 | if (typeof size.call !== "function") {
127 | throw new TypeError();
128 | }
129 | return chunk => size.call(void 0, chunk);
130 | }
131 |
132 | export function IsDetachedBuffer(v): boolean {
133 | return false;
134 | }
135 |
--------------------------------------------------------------------------------
/readable_stream_reader.ts:
--------------------------------------------------------------------------------
1 | import {
2 | IsReadableStream,
3 | IsReadableStreamLocked,
4 | ReadableStream,
5 | ReadableStreamCancel,
6 | ReadableStreamCreateReadResult,
7 | ReadableStreamReadResult
8 | } from "./readable_stream.ts";
9 | import {defer, Defer} from "./defer.ts";
10 | import {Assert} from "./util.ts";
11 | import {ReadableStreamBYOBReader} from "./readable_stream_byob_reader.ts";
12 |
13 | export interface ReadableStreamReader {
14 | readonly closed: Promise;
15 |
16 | cancel(reason?): Promise;
17 |
18 | read(view?: ArrayBufferView): Promise>;
19 |
20 | releaseLock(): Promise;
21 | }
22 |
23 | export class ReadableStreamDefaultReader
24 | implements ReadableStreamReader {
25 | readRequests: { promise: Defer; forAuthorCode }[];
26 |
27 | constructor(stream: ReadableStream) {
28 | if (!IsReadableStream(stream)) {
29 | throw new TypeError();
30 | }
31 | if (IsReadableStreamLocked(stream)) {
32 | throw new TypeError();
33 | }
34 | ReadableStreamReaderGenericInitialize(this, stream);
35 | this.readRequests = [];
36 | }
37 |
38 | get closed(): Promise {
39 | if (!IsReadableStreamDefaultReader(this)) {
40 | return Promise.reject(new TypeError());
41 | }
42 | return this.closedPromise;
43 | }
44 |
45 | closedPromise: Defer;
46 | ownerReadableStream: ReadableStream;
47 |
48 | cancel(reason?): Promise {
49 | if (!IsReadableStreamDefaultReader(this)) {
50 | return Promise.reject(new TypeError());
51 | }
52 | if (this.ownerReadableStream === void 0) {
53 | return Promise.reject(new TypeError());
54 | }
55 | return ReadableStreamReaderGenericCancel(this, reason);
56 | }
57 |
58 | read(): Promise> {
59 | if (!IsReadableStreamDefaultReader(this)) {
60 | return Promise.reject(new TypeError());
61 | }
62 | if (this.ownerReadableStream === void 0) {
63 | return Promise.reject(new TypeError());
64 | }
65 | return ReadableStreamDefaultReaderRead(this, true);
66 | }
67 |
68 | releaseLock() {
69 | if (!IsReadableStreamDefaultReader(this)) {
70 | return Promise.reject(new TypeError());
71 | }
72 | if (this.ownerReadableStream === void 0) {
73 | return Promise.reject(new TypeError());
74 | }
75 | if (this.readRequests.length > 0) {
76 | throw new TypeError();
77 | }
78 | ReadableStreamReaderGenericRelease(this);
79 | }
80 | }
81 |
82 | export function IsReadableStreamDefaultReader(
83 | a
84 | ): a is ReadableStreamDefaultReader {
85 | return typeof a === "object" && a.hasOwnProperty("readRequests");
86 | }
87 |
88 | export function ReadableStreamReaderGenericCancel(
89 | reader: ReadableStreamBYOBReader | ReadableStreamDefaultReader,
90 | reason
91 | ) {
92 | const stream = reader.ownerReadableStream;
93 | Assert(stream !== void 0);
94 | return ReadableStreamCancel(stream, reason);
95 | }
96 |
97 | export function ReadableStreamReaderGenericInitialize(
98 | reader: ReadableStreamBYOBReader | ReadableStreamDefaultReader,
99 | stream: ReadableStream
100 | ) {
101 | reader.ownerReadableStream = stream;
102 | stream.reader = reader;
103 | if (stream.state === "readable") {
104 | reader.closedPromise = defer();
105 | } else if (stream.state === "closed") {
106 | reader.closedPromise = defer();
107 | reader.closedPromise.resolve(void 0);
108 | } else {
109 | Assert(stream.state === "errored");
110 | reader.closedPromise = defer();
111 | reader.closedPromise.reject(stream.storedError);
112 | }
113 | }
114 |
115 | export function ReadableStreamReaderGenericRelease(
116 | reader: ReadableStreamBYOBReader | ReadableStreamDefaultReader
117 | ) {
118 | Assert(reader.ownerReadableStream !== void 0);
119 | Assert(reader.ownerReadableStream.reader === reader);
120 | if (reader.ownerReadableStream.state === "readable") {
121 | reader.closedPromise.reject(new TypeError());
122 | } else {
123 | reader.closedPromise.reject(new TypeError());
124 | }
125 | reader.ownerReadableStream.reader = void 0;
126 | reader.ownerReadableStream = void 0;
127 | }
128 |
129 | export function ReadableStreamDefaultReaderRead(
130 | reader: ReadableStreamDefaultReader,
131 | forAuthorCode: boolean = false
132 | ): Promise<{ value; done: boolean }> {
133 | const stream = reader.ownerReadableStream;
134 | Assert(stream !== void 0);
135 | stream.disturbed = true;
136 | if (stream.state === "closed") {
137 | return Promise.resolve(
138 | ReadableStreamCreateReadResult(void 0, true, forAuthorCode)
139 | );
140 | }
141 | if (stream.state === "errored") {
142 | return Promise.reject(stream.storedError);
143 | }
144 | Assert(stream.state === "readable");
145 | return stream.readableStreamController.PullSteps(forAuthorCode);
146 | }
147 |
--------------------------------------------------------------------------------
/transform_stream.ts:
--------------------------------------------------------------------------------
1 | import {
2 | SizeAlgorithm,
3 | StartAlgorithm,
4 | ReadableStream,
5 | CreateReadableStream
6 | } from "./readable_stream.ts";
7 | import { defer, Defer } from "./defer.ts";
8 | import { CreateWritableStream, WritableStream } from "./writable_stream.ts";
9 | import {
10 | InvokeOrNoop,
11 | IsNonNegativeNumber,
12 | MakeSizeAlgorithmFromSizeFunction,
13 | ValidateAndNormalizeHighWaterMark
14 | } from "./misc.ts";
15 | import {
16 | SetUpTransformStreamDefaultController,
17 | SetUpTransformStreamDefaultControllerFromTransformer,
18 | TransformStreamController,
19 | TransformStreamDefaultController,
20 | TransformStreamDefaultControllerClearAlgorithms,
21 | TransformStreamDefaultSinkAbortAlgorithm,
22 | TransformStreamDefaultSinkCloseAlgorithm,
23 | TransformStreamDefaultSinkWriteAlgorithm,
24 | TransformStreamDefaultSourcePullAlgorithm
25 | } from "./transform_stream_controller.ts";
26 | import { Assert } from "./util.ts";
27 | import { ReadableStreamDefaultControllerError } from "./readable_stream_controller.ts";
28 | import { WritableStreamDefaultControllerErrorIfNeeded } from "./writable_stream_controller.ts";
29 | import { QueuingStrategy } from "./strategy.ts";
30 |
31 | export type Transformer = {
32 | start?: (controller) => any;
33 | transform?: (chunk, controller: TransformStreamController) => Promise;
34 | flush?: (controller: TransformStreamController) => Promise;
35 | writableType?: undefined;
36 | readableType?: undefined;
37 | };
38 |
39 | export class TransformStream {
40 | constructor(
41 | transformer: Transformer,
42 | writableStrategy: QueuingStrategy,
43 | readableStrategy: QueuingStrategy
44 | ) {
45 | let writableSizeFunction = writableStrategy.size;
46 | let writableHighWaterMark = writableStrategy.highWaterMark;
47 | let readableSizeFunction = readableStrategy.size;
48 | let readableHighWaterMark = readableStrategy.highWaterMark;
49 | const { writableType } = transformer;
50 | if (writableType !== void 0) {
51 | throw new RangeError("writable type should not be defined");
52 | }
53 | writableSizeFunction = MakeSizeAlgorithmFromSizeFunction(
54 | writableSizeFunction
55 | );
56 | writableHighWaterMark = ValidateAndNormalizeHighWaterMark(
57 | writableHighWaterMark
58 | );
59 | const { readableType } = transformer;
60 | if (readableType !== void 0) {
61 | throw new RangeError("readable type should not be defined");
62 | }
63 | readableSizeFunction = MakeSizeAlgorithmFromSizeFunction(
64 | readableSizeFunction
65 | );
66 | readableHighWaterMark = ValidateAndNormalizeHighWaterMark(
67 | readableHighWaterMark
68 | );
69 | const startPromise = defer();
70 | InitializeTransformStream(
71 | this,
72 | startPromise,
73 | writableHighWaterMark,
74 | writableSizeFunction,
75 | readableHighWaterMark,
76 | readableSizeFunction
77 | );
78 | SetUpTransformStreamDefaultControllerFromTransformer(this, transformer);
79 | startPromise.resolve(
80 | InvokeOrNoop(transformer, "start", this.transformStreamController)
81 | );
82 | }
83 |
84 | get readable(): ReadableStream {
85 | if (!IsTransformStream(this)) {
86 | throw new TypeError("this is not transform stream");
87 | }
88 | return this._readable;
89 | }
90 |
91 | get writable(): WritableStream {
92 | if (!IsTransformStream(this)) {
93 | throw new TypeError("this is not transform stream");
94 | }
95 | return this._writable;
96 | }
97 |
98 | backpressure: boolean;
99 | backpressureChangePromise: Defer;
100 | _readable: ReadableStream;
101 | transformStreamController: TransformStreamDefaultController;
102 | _writable: WritableStream;
103 | }
104 |
105 | export type FlushAlgorithm = () => Promise;
106 | export type TransformAlgorithm = (chunk: T) => Promise;
107 |
108 | export function CreateTransformStream(
109 | startAlgorithm: StartAlgorithm,
110 | transformAlgorithm: TransformAlgorithm,
111 | flushAlgorithm: FlushAlgorithm,
112 | writableHighWaterMark: number = 1,
113 | writableSizeAlgorithm: SizeAlgorithm = () => 1,
114 | readableHighWaterMark: number = 1,
115 | readableSizeAlgorithm: SizeAlgorithm = () => 1
116 | ): TransformStream {
117 | Assert(IsNonNegativeNumber(writableHighWaterMark));
118 | Assert(IsNonNegativeNumber(readableHighWaterMark));
119 | const stream = Object.create(TransformStream.prototype);
120 | const startPromise = defer();
121 | InitializeTransformStream(
122 | stream,
123 | startPromise,
124 | writableHighWaterMark,
125 | writableSizeAlgorithm,
126 | readableHighWaterMark,
127 | readableSizeAlgorithm
128 | );
129 | const controller = Object.create(TransformStreamDefaultController.prototype);
130 | SetUpTransformStreamDefaultController(
131 | stream,
132 | controller,
133 | transformAlgorithm,
134 | flushAlgorithm
135 | );
136 | startPromise.resolve(startPromise());
137 | return stream;
138 | }
139 |
140 | export function InitializeTransformStream(
141 | stream: TransformStream,
142 | startPromise: Defer,
143 | writableHighWaterMark: number,
144 | writableSizeAlgorithm: SizeAlgorithm,
145 | readableHighWaterMark: number,
146 | readableSizeAlgorithm: SizeAlgorithm
147 | ) {
148 | const startAlgorithm = () => startPromise;
149 | const writeAlgorithm = chunk =>
150 | TransformStreamDefaultSinkWriteAlgorithm(stream, chunk);
151 | const abortAlgorithm = reason =>
152 | TransformStreamDefaultSinkAbortAlgorithm(stream, reason);
153 | const closeAlgorithm = () => TransformStreamDefaultSinkCloseAlgorithm(stream);
154 | stream._writable = CreateWritableStream(
155 | startAlgorithm,
156 | writeAlgorithm,
157 | closeAlgorithm,
158 | abortAlgorithm,
159 | writableHighWaterMark,
160 | writableSizeAlgorithm
161 | );
162 | const pullAlgorithm = () => TransformStreamDefaultSourcePullAlgorithm(stream);
163 | const cancelAlgorithm = reason =>
164 | TransformStreamErrorWritableAndUnblockWrite(stream, reason);
165 | stream._readable = CreateReadableStream(
166 | startAlgorithm,
167 | pullAlgorithm,
168 | cancelAlgorithm,
169 | readableHighWaterMark,
170 | readableSizeAlgorithm
171 | );
172 | stream.backpressure = void 0;
173 | stream.backpressureChangePromise = void 0;
174 | TransformStreamSetBackpressure(stream, true);
175 | stream.transformStreamController = void 0;
176 | }
177 |
178 | export function IsTransformStream(x): x is TransformStream {
179 | return typeof x === "object" && x.hasOwnProperty("transformStreamController");
180 | }
181 |
182 | export function TransformStreamError(stream: TransformStream, e) {
183 | ReadableStreamDefaultControllerError(
184 | stream.readable.readableStreamController,
185 | e
186 | );
187 | TransformStreamErrorWritableAndUnblockWrite(stream, e);
188 | }
189 |
190 | export function TransformStreamErrorWritableAndUnblockWrite(
191 | stream: TransformStream,
192 | e
193 | ) {
194 | TransformStreamDefaultControllerClearAlgorithms(
195 | stream.transformStreamController
196 | );
197 | WritableStreamDefaultControllerErrorIfNeeded(
198 | stream.writable.writableStreamController,
199 | e
200 | );
201 | if (stream.backpressure) {
202 | TransformStreamSetBackpressure(stream, false);
203 | }
204 | }
205 |
206 | export function TransformStreamSetBackpressure(
207 | stream: TransformStream,
208 | backpressure: boolean
209 | ) {
210 | Assert(stream.backpressure !== backpressure);
211 | if (stream.backpressureChangePromise !== void 0) {
212 | stream.backpressureChangePromise.resolve();
213 | }
214 | stream.backpressureChangePromise = defer();
215 | stream.backpressure = backpressure;
216 | }
217 |
--------------------------------------------------------------------------------
/transform_stream_controller.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ReadableStreamDefaultControllerCanCloseOrEnqueue,
3 | ReadableStreamDefaultControllerClose,
4 | ReadableStreamDefaultControllerEnqueue,
5 | ReadableStreamDefaultControllerGetDesiredSize,
6 | ReadableStreamDefaultControllerHasBackpressure
7 | } from "./readable_stream_controller";
8 | import {
9 | FlushAlgorithm,
10 | IsTransformStream,
11 | TransformAlgorithm,
12 | Transformer,
13 | TransformStream,
14 | TransformStreamError,
15 | TransformStreamErrorWritableAndUnblockWrite,
16 | TransformStreamSetBackpressure
17 | } from "./transform_stream";
18 | import { Assert } from "./util";
19 | import { CreateAlgorithmFromUnderlyingMethod, PromiseCall } from "./misc";
20 | import { read, write } from "deno";
21 |
22 | export interface TransformStreamController {
23 | readonly desiredSize: number;
24 |
25 | enqueue(chunk: T);
26 |
27 | error(reason);
28 |
29 | terminate();
30 | }
31 |
32 | export class TransformStreamDefaultController
33 | implements TransformStreamController {
34 | constructor() {
35 | throw new TypeError(
36 | "TransformStreamDefaultController is not constructable"
37 | );
38 | }
39 |
40 | get desiredSize() {
41 | if (!IsTransformStreamDefaultController(this)) {
42 | throw new TypeError("this is not TransformStreamDefaultController");
43 | }
44 | return ReadableStreamDefaultControllerGetDesiredSize(
45 | this.controlledTransformStream.readable.readableStreamController
46 | );
47 | }
48 |
49 | enqueue(chunk: T) {
50 | if (!IsTransformStreamDefaultController(this)) {
51 | throw new TypeError("this is not TransformStreamDefaultController");
52 | }
53 | TransformStreamDefaultControllerEnqueue(this, chunk);
54 | }
55 |
56 | error(reason) {
57 | if (!IsTransformStreamDefaultController(this)) {
58 | throw new TypeError("this is not TransformStreamDefaultController");
59 | }
60 | TransformStreamDefaultControllerError(this, reason);
61 | }
62 |
63 | terminate() {
64 | if (!IsTransformStreamDefaultController(this)) {
65 | throw new TypeError("this is not TransformStreamDefaultController");
66 | }
67 | TransformStreamDefaultControllerTerminate(this);
68 | }
69 |
70 | controlledTransformStream: TransformStream;
71 | flushAlgorithm: FlushAlgorithm;
72 | transformAlgorithm: TransformAlgorithm;
73 | }
74 |
75 | export function IsTransformStreamDefaultController(
76 | x
77 | ): x is TransformStreamDefaultController {
78 | return typeof x === "object" && x.hasOwnProperty("controlledTransformStream");
79 | }
80 |
81 | export function SetUpTransformStreamDefaultController(
82 | stream: TransformStream,
83 | controller: TransformStreamDefaultController,
84 | transformAlgorithm: TransformAlgorithm,
85 | flushAlgorithm: FlushAlgorithm
86 | ) {
87 | Assert(IsTransformStream(stream));
88 | Assert(stream.transformStreamController === void 0);
89 | controller.controlledTransformStream = stream;
90 | stream.transformStreamController = controller;
91 | controller.transformAlgorithm = transformAlgorithm;
92 | controller.flushAlgorithm = flushAlgorithm;
93 | }
94 |
95 | export function SetUpTransformStreamDefaultControllerFromTransformer(
96 | stream: TransformStream,
97 | transformer: Transformer
98 | ) {
99 | Assert(transformer !== void 0);
100 | const controller = Object.create(TransformStreamDefaultController.prototype);
101 | let transformAlgorithm: TransformAlgorithm = async chunk => {
102 | try {
103 | TransformStreamDefaultControllerEnqueue(controller, chunk);
104 | } catch (e) {
105 | throw void 0;
106 | }
107 | return;
108 | };
109 | const method = transformer.transform;
110 | if (method !== void 0) {
111 | if (typeof method.call !== "function") {
112 | throw new TypeError("transformer.transform is not callable");
113 | }
114 | transformAlgorithm = async chunk =>
115 | PromiseCall(method, transformer, chunk, controller);
116 | }
117 | const flushAlgorithm = CreateAlgorithmFromUnderlyingMethod(
118 | transformer,
119 | "flush",
120 | 0,
121 | controller
122 | );
123 | SetUpTransformStreamDefaultController(
124 | stream,
125 | controller,
126 | transformAlgorithm,
127 | flushAlgorithm
128 | );
129 | }
130 |
131 | export function TransformStreamDefaultControllerClearAlgorithms(
132 | controller: TransformStreamDefaultController
133 | ) {
134 | controller.transformAlgorithm = void 0;
135 | controller.flushAlgorithm = void 0;
136 | }
137 |
138 | export function TransformStreamDefaultControllerEnqueue(
139 | controller: TransformStreamDefaultController,
140 | chunk
141 | ) {
142 | const stream = controller.controlledTransformStream;
143 | const readableController = stream.readable.readableStreamController;
144 | if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController)) {
145 | throw new TypeError("readable stream controller cannot close on enqueue");
146 | }
147 | try {
148 | ReadableStreamDefaultControllerEnqueue(readableController, chunk);
149 | } catch (e) {
150 | TransformStreamErrorWritableAndUnblockWrite(stream, e);
151 | throw stream.readable.storedError;
152 | }
153 | const backpressure = ReadableStreamDefaultControllerHasBackpressure(
154 | readableController
155 | );
156 | if (backpressure !== stream.backpressure) {
157 | Assert(backpressure);
158 | TransformStreamSetBackpressure(stream, true);
159 | }
160 | }
161 |
162 | export function TransformStreamDefaultControllerError(
163 | controller: TransformStreamDefaultController,
164 | e
165 | ) {
166 | TransformStreamError(controller.controlledTransformStream, e);
167 | }
168 |
169 | export function TransformStreamDefaultControllerPerformTransform(
170 | controller: TransformStreamDefaultController,
171 | chunk
172 | ) {
173 | controller.transformAlgorithm(chunk).catch(r => {
174 | TransformStreamError(controller.controlledTransformStream, r);
175 | throw r;
176 | });
177 | }
178 |
179 | export function TransformStreamDefaultControllerTerminate(
180 | controller: TransformStreamDefaultController
181 | ) {
182 | const stream = controller.controlledTransformStream;
183 | const readableController = stream.readable.readableStreamController;
184 | if (ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController)) {
185 | ReadableStreamDefaultControllerClose(readableController);
186 | }
187 | const error = new TypeError("stream ended");
188 | TransformStreamErrorWritableAndUnblockWrite(stream, error);
189 | }
190 |
191 | export function TransformStreamDefaultSinkWriteAlgorithm(
192 | stream: TransformStream,
193 | chunk
194 | ) {
195 | Assert(stream.writable.state === "writable");
196 | const controller = stream.transformStreamController;
197 | if (stream.backpressure) {
198 | const p = stream.backpressureChangePromise;
199 | Assert(p !== void 0);
200 | return p.then(() => {
201 | const writable = stream.writable;
202 | const { state } = writable;
203 | if (state === "erroring") {
204 | throw writable.storedError;
205 | }
206 | Assert(state === "writable");
207 | return TransformStreamDefaultControllerPerformTransform(
208 | controller,
209 | chunk
210 | );
211 | });
212 | }
213 | return TransformStreamDefaultControllerPerformTransform(controller, chunk);
214 | }
215 |
216 | export async function TransformStreamDefaultSinkAbortAlgorithm(
217 | stream: TransformStream,
218 | reason
219 | ) {
220 | TransformStreamError(stream, reason);
221 | }
222 |
223 | export function TransformStreamDefaultSinkCloseAlgorithm(
224 | stream: TransformStream
225 | ) {
226 | const { readable } = stream;
227 | const controller = stream.transformStreamController;
228 | const flushPromise = controller.flushAlgorithm();
229 | TransformStreamDefaultControllerClearAlgorithms(controller);
230 | return flushPromise
231 | .then(() => {
232 | if (readable.state === "errored") {
233 | throw readable.storedError;
234 | }
235 | const readableController = readable.readableStreamController;
236 | if (
237 | ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController)
238 | ) {
239 | ReadableStreamDefaultControllerClose(readableController);
240 | }
241 | })
242 | .catch(r => {
243 | TransformStreamError(stream, r);
244 | throw readable.storedError;
245 | });
246 | }
247 |
248 | export function TransformStreamDefaultSourcePullAlgorithm(
249 | stream: TransformStream
250 | ) {
251 | Assert(stream.backpressure);
252 | Assert(stream.backpressureChangePromise !== void 0);
253 | TransformStreamSetBackpressure(stream, false);
254 | return stream.backpressureChangePromise;
255 | }
256 |
--------------------------------------------------------------------------------
/writable_stream_writer.ts:
--------------------------------------------------------------------------------
1 | import {
2 | IsWritableStream,
3 | IsWritableStreamLocked,
4 | WritableStream,
5 | WritableStreamAbort,
6 | WritableStreamAddWriteRequest,
7 | WritableStreamCloseQueuedOrInFlight
8 | } from "./writable_stream.ts";
9 | import {
10 | defer,
11 | Defer,
12 | PromiseState,
13 | rejectDefer,
14 | resolveDefer
15 | } from "./defer.ts";
16 | import { Assert } from "./util.ts";
17 | import {
18 | WritableStreamDefaultControllerClose,
19 | WritableStreamDefaultControllerGetChunkSize,
20 | WritableStreamDefaultControllerGetDesiredSize,
21 | WritableStreamDefaultControllerWrite
22 | } from "./writable_stream_controller.ts";
23 |
24 | export interface WritableStreamWriter {
25 | readonly closed;
26 | readonly desiredSize;
27 | readonly ready;
28 |
29 | abort(reason);
30 |
31 | close();
32 |
33 | releaseLock();
34 |
35 | write(chunk: T);
36 | }
37 |
38 | export class WritableStreamDefaultWriter implements WritableStreamWriter {
39 | constructor(stream: WritableStream) {
40 | if (!IsWritableStream(stream)) {
41 | throw new TypeError("stream is not writable stream");
42 | }
43 | if (IsWritableStreamLocked(stream)) {
44 | throw new TypeError("stream is locked");
45 | }
46 | this.ownerWritableStream = stream;
47 | stream.writer = this;
48 | const { state } = stream;
49 | if (state === "writable") {
50 | if (!WritableStreamCloseQueuedOrInFlight(stream) && stream.backpressure) {
51 | this.readyPromise = defer();
52 | } else {
53 | this.readyPromise = resolveDefer(void 0);
54 | }
55 | this.closedPromise = defer();
56 | } else if (state === "erroring") {
57 | this.readyPromise = rejectDefer(stream.storedError);
58 | this.closedPromise = defer();
59 | } else if (state === "closed") {
60 | this.readyPromise = resolveDefer(void 0);
61 | this.closedPromise = resolveDefer(void 0);
62 | } else {
63 | Assert(state === "errored");
64 | const { storedError } = stream;
65 | this.readyPromise = rejectDefer(storedError);
66 | this.closedPromise = rejectDefer(storedError);
67 | }
68 | }
69 |
70 | get closed(): Promise {
71 | if (!IsWritableStreamDefaultWriter(this)) {
72 | return Promise.reject(
73 | new TypeError("this is not WritableStreamDefaultWriter")
74 | );
75 | }
76 | return this.closedPromise;
77 | }
78 |
79 | get desiredSize() {
80 | if (!IsWritableStreamDefaultWriter(this)) {
81 | throw new TypeError("this is not WritableStreamDefaultWriter");
82 | }
83 | if (this.ownerWritableStream === void 0) {
84 | throw new TypeError("stream is undefined");
85 | }
86 | return WritableStreamDefaultWriterGetDesiredSize(this);
87 | }
88 |
89 | get ready(): Promise {
90 | if (!IsWritableStreamDefaultWriter(this)) {
91 | return Promise.reject(
92 | new TypeError("this is not WritableStreamDefaultWriter")
93 | );
94 | }
95 | return this.readyPromise;
96 | }
97 |
98 | async abort(reason) {
99 | if (!IsWritableStreamDefaultWriter(this)) {
100 | throw new TypeError("this is not WritableStreamDefaultWriter");
101 | }
102 | if (this.ownerWritableStream === void 0) {
103 | throw new TypeError("stream is undefined");
104 | }
105 | return WritableStreamDefaultWriterAbort(this, reason);
106 | }
107 |
108 | async close() {
109 | if (!IsWritableStreamDefaultWriter(this)) {
110 | throw new TypeError();
111 | }
112 | const stream = this.ownerWritableStream;
113 | if (stream === void 0) {
114 | throw new TypeError();
115 | }
116 | if (WritableStreamCloseQueuedOrInFlight(stream)) {
117 | throw new TypeError();
118 | }
119 | return WritableStreamDefaultWriterClose(this);
120 | }
121 |
122 | releaseLock() {
123 | if (!IsWritableStreamDefaultWriter(this)) {
124 | throw new TypeError();
125 | }
126 | const stream = this.ownerWritableStream;
127 | if (stream === void 0) {
128 | throw new TypeError();
129 | }
130 | Assert(stream.writer !== void 0);
131 | WritableStreamDefaultWriterRelease(this);
132 | }
133 |
134 | write(chunk) {
135 | if (!IsWritableStreamDefaultWriter(this)) {
136 | throw new TypeError();
137 | }
138 | const stream = this.ownerWritableStream;
139 | if (stream === void 0) {
140 | throw new TypeError();
141 | }
142 | return WritableStreamDefaultWriterWrite(this, chunk);
143 | }
144 |
145 | closedPromise: Defer;
146 | ownerWritableStream: WritableStream;
147 | readyPromise: Defer;
148 | }
149 |
150 | export function IsWritableStreamDefaultWriter(
151 | x
152 | ): x is WritableStreamDefaultWriter {
153 | return typeof x === "object" && x.hasOwnProperty("ownerWritableStream");
154 | }
155 |
156 | export function WritableStreamDefaultWriterAbort(
157 | writer: WritableStreamDefaultWriter,
158 | reason
159 | ) {
160 | Assert(writer.ownerWritableStream !== void 0);
161 | return WritableStreamAbort(writer.ownerWritableStream, reason);
162 | }
163 |
164 | export async function WritableStreamDefaultWriterClose(
165 | writer: WritableStreamDefaultWriter
166 | ): Promise {
167 | const stream = writer.ownerWritableStream;
168 | Assert(stream !== void 0);
169 | const { state } = stream;
170 | if (state === "closed" || state === "errored") {
171 | throw new TypeError(`stream is ${state}`);
172 | }
173 | Assert(state === "writable" || state === "erroring");
174 | Assert(!WritableStreamCloseQueuedOrInFlight(stream));
175 | const promise = defer();
176 | stream.closeRequest = promise;
177 | if (stream.backpressure && state == "writable") {
178 | writer.readyPromise.resolve();
179 | }
180 | WritableStreamDefaultControllerClose(stream.writableStreamController);
181 | return promise;
182 | }
183 |
184 | export async function WritableStreamDefaultWriterCloseWithErrorPropagation(
185 | writer: WritableStreamDefaultWriter
186 | ) {
187 | const stream = writer.ownerWritableStream;
188 | Assert(stream !== void 0);
189 | const { state } = stream;
190 | if (WritableStreamCloseQueuedOrInFlight(stream) || state === "closed") {
191 | return void 0;
192 | }
193 | if (state === "errored") {
194 | throw stream.storedError;
195 | }
196 | Assert(state === "writable" || state === "erroring");
197 | return WritableStreamDefaultWriterClose(writer);
198 | }
199 |
200 | export function WritableStreamDefaultWriterEnsureClosedPromiseRejected(
201 | writer: WritableStreamDefaultWriter,
202 | error
203 | ) {
204 | if (writer.closedPromise[PromiseState] === "pending") {
205 | writer.closedPromise.reject(error);
206 | } else {
207 | writer.closedPromise = rejectDefer(error);
208 | }
209 | }
210 |
211 | export function WritableStreamDefaultWriterEnsureReadyPromiseRejected(
212 | writer: WritableStreamDefaultWriter,
213 | error
214 | ) {
215 | if (writer.readyPromise[PromiseState] === "pending") {
216 | writer.readyPromise.reject(error);
217 | } else {
218 | writer.readyPromise = rejectDefer(error);
219 | }
220 | }
221 |
222 | export function WritableStreamDefaultWriterGetDesiredSize(
223 | writer: WritableStreamDefaultWriter
224 | ) {
225 | const stream = writer.ownerWritableStream;
226 | const { state } = stream;
227 | if (state === "errored" || state === "erroring") {
228 | return null;
229 | }
230 | if (state === "closed") {
231 | return 0;
232 | }
233 | return WritableStreamDefaultControllerGetDesiredSize(
234 | stream.writableStreamController
235 | );
236 | }
237 |
238 | export function WritableStreamDefaultWriterRelease(
239 | writer: WritableStreamDefaultWriter
240 | ) {
241 | const stream = writer.ownerWritableStream;
242 | Assert(stream !== void 0, "stream is undefined");
243 | Assert(stream.writer === writer, "writer is not identical");
244 | const releasedError = new TypeError();
245 | WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError);
246 | WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError);
247 | stream.writer = void 0;
248 | writer.ownerWritableStream = void 0;
249 | }
250 |
251 | export async function WritableStreamDefaultWriterWrite(
252 | writer: WritableStreamDefaultWriter,
253 | chunk
254 | ) {
255 | const stream = writer.ownerWritableStream;
256 | Assert(stream !== void 0);
257 | const controller = stream.writableStreamController;
258 | const chunkSize = WritableStreamDefaultControllerGetChunkSize(
259 | controller,
260 | chunk
261 | );
262 | if (stream !== writer.ownerWritableStream) {
263 | throw new TypeError("different stream");
264 | }
265 | const { state } = stream;
266 | if (state === "errored") {
267 | throw stream.storedError;
268 | }
269 | if (WritableStreamCloseQueuedOrInFlight(stream) || state === "closed") {
270 | throw new TypeError(
271 | `stream is ${state === "closed" ? "closed" : "closing"}`
272 | );
273 | }
274 | if (state === "erroring") {
275 | throw stream.storedError;
276 | }
277 | Assert(state === "writable");
278 | const promise = WritableStreamAddWriteRequest(stream);
279 | WritableStreamDefaultControllerWrite(controller, chunk, chunkSize);
280 | return promise;
281 | }
282 |
--------------------------------------------------------------------------------
/writable_stream_controller.ts:
--------------------------------------------------------------------------------
1 | import { SizeAlgorithm, StartAlgorithm } from "./readable_stream.ts";
2 | import {
3 | WritableStream,
4 | AbortAlgorithm,
5 | CloseAlgorithm,
6 | IsWritableStream,
7 | WriteAlgorithm,
8 | WritableStreamUpdateBackpressure,
9 | WritableStreamDealWithRejection,
10 | WritableStreamCloseQueuedOrInFlight,
11 | WritableStreamFinishErroring,
12 | WritableStreamMarkCloseRequestInFlight,
13 | WritableStreamFinishInFlightClose,
14 | WritableStreamFinishInFlightCloseWithError,
15 | WritableStreamMarkFirstWriteRequestInFlight,
16 | WritableStreamFinishInFlightWrite,
17 | WritableStreamStartErroring
18 | } from "./writable_stream.ts";
19 | import { Assert } from "./util.ts";
20 | import {
21 | CreateAlgorithmFromUnderlyingMethod,
22 | DequeueValue,
23 | EnqueueValueWithSize,
24 | InvokeOrNoop,
25 | PeekQueueValue,
26 | ResetQueue
27 | } from "./misc.ts";
28 |
29 | export interface WritableStreamController {
30 | error(e);
31 | }
32 |
33 | export const ErrorSteps = Symbol("ErrorSteps");
34 | export const AbortSteps = Symbol("AbortSteps");
35 |
36 | export function createWritableStreamDefaultController<
37 | T
38 | >(): WritableStreamDefaultController {
39 | const ret = Object.create(WritableStreamDefaultController.prototype);
40 | ret[ErrorSteps] = () => ResetQueue(ret);
41 | ret[AbortSteps] = reason => {
42 | const result = ret.abortAlgorithm(reason);
43 | WritableStreamDefaultControllerClearAlgorithms(ret);
44 | return result;
45 | };
46 | return ret;
47 | }
48 |
49 | export class WritableStreamDefaultController
50 | implements WritableStreamController {
51 | abortAlgorithm: AbortAlgorithm;
52 | closeAlgorithm: CloseAlgorithm;
53 | controlledWritableStream: WritableStream;
54 | queue: ("close" | { chunk: T })[];
55 | queueTotalSize: number;
56 | started: boolean;
57 | strategyHWM: number;
58 | strategySizeAlgorithm: SizeAlgorithm;
59 | writeAlgorithm: WriteAlgorithm;
60 |
61 | constructor() {
62 | throw new TypeError();
63 | }
64 |
65 | error(e) {
66 | if (!IsWritableStreamDefaultController(this)) {
67 | throw new TypeError("this is not WritableStreamDefaultController");
68 | }
69 | const { state } = this.controlledWritableStream;
70 | if (state !== "writable") {
71 | return;
72 | }
73 | WritableStreamDefaultControllerError(this, e);
74 | }
75 | }
76 |
77 | export function IsWritableStreamDefaultController(
78 | x
79 | ): x is WritableStreamDefaultController {
80 | return typeof x === "object" && x.hasOwnProperty("controlledWritableStream");
81 | }
82 |
83 | export function SetUpWritableStreamDefaultController(params: {
84 | stream: WritableStream;
85 | controller: WritableStreamDefaultController;
86 | startAlgorithm: StartAlgorithm;
87 | writeAlgorithm: WriteAlgorithm;
88 | closeAlgorithm: CloseAlgorithm;
89 | abortAlgorithm: AbortAlgorithm;
90 | highWaterMark: number;
91 | sizeAlgorithm: SizeAlgorithm;
92 | }) {
93 | const {
94 | stream,
95 | controller,
96 | startAlgorithm,
97 | writeAlgorithm,
98 | closeAlgorithm,
99 | abortAlgorithm,
100 | highWaterMark,
101 | sizeAlgorithm
102 | } = params;
103 | Assert(IsWritableStream(stream));
104 | Assert(stream.writableStreamController === void 0);
105 | controller.controlledWritableStream = stream;
106 | stream.writableStreamController = controller;
107 | ResetQueue(controller);
108 | controller.started = false;
109 | controller.strategySizeAlgorithm = sizeAlgorithm;
110 | controller.strategyHWM = highWaterMark;
111 | controller.writeAlgorithm = writeAlgorithm;
112 | controller.closeAlgorithm = closeAlgorithm;
113 | controller.abortAlgorithm = abortAlgorithm;
114 | const backpressure = WritableStreamDefaultControllerGetBackpressure(
115 | controller
116 | );
117 | WritableStreamUpdateBackpressure(stream, backpressure);
118 | Promise.resolve(startAlgorithm())
119 | .then(() => {
120 | Assert(stream.state === "writable" || stream.state === "erroring");
121 | controller.started = true;
122 | WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
123 | })
124 | .catch(r => {
125 | Assert(stream.state === "writable" || stream.state === "erroring");
126 | controller.started = true;
127 | WritableStreamDealWithRejection(stream, r);
128 | });
129 | }
130 |
131 | export function SetUpWritableStreamDefaultControllerFromUnderlyingSink(
132 | stream: WritableStream,
133 | underlyingSink,
134 | highWaterMark: number,
135 | sizeAlgorithm: SizeAlgorithm
136 | ) {
137 | Assert(underlyingSink !== void 0);
138 | const controller = createWritableStreamDefaultController();
139 | const startAlgorithm = () =>
140 | InvokeOrNoop(underlyingSink, "start", controller);
141 | const writeAlgorithm = CreateAlgorithmFromUnderlyingMethod(
142 | underlyingSink,
143 | "write",
144 | 1,
145 | controller
146 | );
147 | const closeAlgorithm = CreateAlgorithmFromUnderlyingMethod(
148 | underlyingSink,
149 | "close",
150 | 0
151 | );
152 | const abortAlgorithm = CreateAlgorithmFromUnderlyingMethod(
153 | underlyingSink,
154 | "abort",
155 | 1
156 | );
157 | SetUpWritableStreamDefaultController({
158 | stream,
159 | controller,
160 | startAlgorithm,
161 | writeAlgorithm,
162 | closeAlgorithm,
163 | abortAlgorithm,
164 | highWaterMark,
165 | sizeAlgorithm
166 | });
167 | }
168 |
169 | export function WritableStreamDefaultControllerClearAlgorithms(
170 | controller: WritableStreamDefaultController
171 | ) {
172 | controller.writeAlgorithm = void 0;
173 | controller.closeAlgorithm = void 0;
174 | controller.abortAlgorithm = void 0;
175 | controller.strategySizeAlgorithm = void 0;
176 | }
177 |
178 | export function WritableStreamDefaultControllerClose(
179 | controller: WritableStreamDefaultController
180 | ) {
181 | EnqueueValueWithSize(controller, "close", 0);
182 | WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
183 | }
184 |
185 | export function WritableStreamDefaultControllerGetChunkSize(
186 | controller: WritableStreamDefaultController,
187 | chunk
188 | ): number {
189 | try {
190 | return controller.strategySizeAlgorithm(chunk);
191 | } catch (e) {
192 | WritableStreamDefaultControllerErrorIfNeeded(controller, e);
193 | return 1;
194 | }
195 | }
196 |
197 | export function WritableStreamDefaultControllerGetDesiredSize(
198 | controller: WritableStreamDefaultController
199 | ): number {
200 | return controller.strategyHWM - controller.queueTotalSize;
201 | }
202 |
203 | export function WritableStreamDefaultControllerWrite(
204 | controller: WritableStreamDefaultController,
205 | chunk,
206 | chunkSize: number
207 | ) {
208 | const writeRecord = { chunk };
209 | try {
210 | EnqueueValueWithSize(controller, writeRecord, chunkSize);
211 | } catch (e) {
212 | WritableStreamDefaultControllerErrorIfNeeded(controller, e);
213 | return;
214 | }
215 | const stream = controller.controlledWritableStream;
216 | if (
217 | !WritableStreamCloseQueuedOrInFlight(stream) &&
218 | stream.state === "writable"
219 | ) {
220 | const backpressure = WritableStreamDefaultControllerGetBackpressure(
221 | controller
222 | );
223 | WritableStreamUpdateBackpressure(stream, backpressure);
224 | }
225 | WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
226 | }
227 |
228 | export function WritableStreamDefaultControllerAdvanceQueueIfNeeded(
229 | controller: WritableStreamDefaultController
230 | ) {
231 | const stream = controller.controlledWritableStream;
232 | if (!controller.started) {
233 | return;
234 | }
235 | if (stream.inFlightWriteRequest !== void 0) {
236 | return;
237 | }
238 | const { state } = stream;
239 | if (state === "closed" || state === "errored") {
240 | return;
241 | }
242 | if (state === "erroring") {
243 | WritableStreamFinishErroring(stream);
244 | return;
245 | }
246 | if (controller.queue.length === 0) {
247 | return;
248 | }
249 | const writeRecord = PeekQueueValue(controller);
250 | if (writeRecord === "close") {
251 | WritableStreamDefaultControllerProcessClose(controller);
252 | } else {
253 | WritableStreamDefaultControllerProcessWrite(controller, writeRecord.chunk);
254 | }
255 | }
256 |
257 | export function WritableStreamDefaultControllerErrorIfNeeded(
258 | controller: WritableStreamDefaultController,
259 | error
260 | ) {
261 | if (controller.controlledWritableStream.state === "writable") {
262 | WritableStreamDefaultControllerError(controller, error);
263 | }
264 | }
265 |
266 | export function WritableStreamDefaultControllerProcessClose(
267 | controller: WritableStreamDefaultController
268 | ) {
269 | const stream = controller.controlledWritableStream;
270 | WritableStreamMarkCloseRequestInFlight(stream);
271 | DequeueValue(controller);
272 | Assert(controller.queue.length === 0);
273 | const sinkClosePromise = controller.closeAlgorithm();
274 | WritableStreamDefaultControllerClearAlgorithms(controller);
275 | sinkClosePromise
276 | .then(() => {
277 | WritableStreamFinishInFlightClose(stream);
278 | })
279 | .catch(r => {
280 | WritableStreamFinishInFlightCloseWithError(stream, r);
281 | });
282 | }
283 |
284 | export function WritableStreamDefaultControllerProcessWrite(
285 | controller: WritableStreamDefaultController,
286 | chunk
287 | ) {
288 | const stream = controller.controlledWritableStream;
289 | WritableStreamMarkFirstWriteRequestInFlight(stream);
290 | const sinkWritePromise = controller.writeAlgorithm(chunk);
291 | sinkWritePromise.then(() => {
292 | WritableStreamFinishInFlightWrite(stream);
293 | const { state } = stream;
294 | Assert(state === "writable" || state === "erroring");
295 | DequeueValue(controller);
296 | if (!WritableStreamCloseQueuedOrInFlight(stream) && state === "writable") {
297 | const bp = WritableStreamDefaultControllerGetBackpressure(controller);
298 | WritableStreamUpdateBackpressure(stream, bp);
299 | }
300 | WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller);
301 | });
302 | }
303 |
304 | export function WritableStreamDefaultControllerGetBackpressure(
305 | controller: WritableStreamDefaultController
306 | ) {
307 | return WritableStreamDefaultControllerGetDesiredSize(controller) <= 0;
308 | }
309 |
310 | export function WritableStreamDefaultControllerError(
311 | controller: WritableStreamDefaultController,
312 | error
313 | ) {
314 | const stream = controller.controlledWritableStream;
315 | Assert(stream.state === "writable");
316 | WritableStreamDefaultControllerClearAlgorithms(controller);
317 | WritableStreamStartErroring(stream, error);
318 | }
319 |
--------------------------------------------------------------------------------
/readable_stream_controller.ts:
--------------------------------------------------------------------------------
1 | import { Assert } from "./util.ts";
2 |
3 | import { ReadableStreamBYOBRequest } from "./readable_stream_request.ts";
4 | import {
5 | CancelAlgorithm,
6 | IsReadableStreamLocked,
7 | PullAlgorithm,
8 | ReadableStream,
9 | ReadableStreamAddReadRequest,
10 | ReadableStreamClose,
11 | ReadableStreamCreateReadResult,
12 | ReadableStreamError,
13 | ReadableStreamFulfillReadRequest,
14 | ReadableStreamGetNumReadRequests,
15 | SizeAlgorithm,
16 | StartAlgorithm,
17 | UnderlyingSource
18 | } from "./readable_stream.ts";
19 |
20 | import {
21 | CreateAlgorithmFromUnderlyingMethod,
22 | DequeueValue,
23 | EnqueueValueWithSize,
24 | InvokeOrNoop,
25 | ResetQueue
26 | } from "./misc.ts";
27 |
28 | export type PullIntoDescriptor = {
29 | buffer: ArrayBuffer;
30 | byteOffset: number;
31 | bytesFilled: number;
32 | byteLength: number;
33 | elementSize: number;
34 | ctor: any;
35 | readerType: string;
36 | };
37 |
38 | export interface ReadableStreamController {
39 | readonly byobRequest?: ReadableStreamBYOBRequest;
40 |
41 | readonly desiredSize: number;
42 |
43 | close(): void;
44 |
45 | enqueue(chunk: T): void;
46 |
47 | error(e): void;
48 | }
49 |
50 | export abstract class ReadableStreamControllerBase {
51 | autoAllocateChunkSize: number;
52 |
53 | cancelAlgorithm: CancelAlgorithm;
54 |
55 | closeRequested: boolean;
56 | pullAgain: boolean;
57 |
58 | pullAlgorithm: PullAlgorithm;
59 |
60 | pulling: boolean;
61 | pendingPullIntos: PullIntoDescriptor[];
62 | queue: {
63 | buffer: ArrayBuffer;
64 | byteLength: number;
65 | byteOffset: number;
66 | }[];
67 | queueTotalSize;
68 | started: boolean;
69 | strategyHWM: number;
70 |
71 | //
72 | }
73 |
74 | export class ReadableStreamDefaultController
75 | extends ReadableStreamControllerBase
76 | implements ReadableStreamController {
77 | constructor() {
78 | super();
79 | throw new TypeError();
80 | }
81 |
82 | controlledReadableStream: ReadableStream;
83 | strategySizeAlgorithm: (chunk) => number;
84 |
85 | get desiredSize(): number {
86 | if (!IsReadableStreamDefaultController(this)) {
87 | throw new TypeError();
88 | }
89 | return ReadableStreamDefaultControllerGetDesiredSize(this);
90 | }
91 |
92 | close(): void {
93 | if (!IsReadableStreamDefaultController(this)) {
94 | throw new TypeError();
95 | }
96 | if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(this)) {
97 | throw new TypeError();
98 | }
99 | ReadableStreamDefaultControllerClose(this);
100 | }
101 |
102 | enqueue(chunk: T): void {
103 | if (!IsReadableStreamDefaultController(this)) {
104 | throw new TypeError();
105 | }
106 | if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(this)) {
107 | throw new TypeError();
108 | }
109 | return ReadableStreamDefaultControllerEnqueue(this, chunk);
110 | }
111 |
112 | error(e): void {
113 | if (!IsReadableStreamDefaultController(this)) {
114 | throw new TypeError();
115 | }
116 | ReadableStreamDefaultControllerError(this, e);
117 | }
118 |
119 | CancelSteps(reason): Promise {
120 | ResetQueue(this);
121 | const result = this.cancelAlgorithm(reason);
122 | ReadableStreamDefaultControllerClearAlgorithms(this);
123 | return result;
124 | }
125 |
126 | PullSteps(forAuthorCode?: boolean): Promise {
127 | const stream = this.controlledReadableStream;
128 | if (this.queue.length > 0) {
129 | const chunk = DequeueValue(this);
130 | if (this.closeRequested && this.queue.length === 0) {
131 | ReadableStreamDefaultControllerClearAlgorithms(this);
132 | ReadableStreamClose(stream);
133 | } else {
134 | ReadableStreamDefaultControllerCallPullIfNeeded(this);
135 | }
136 | return Promise.resolve(
137 | ReadableStreamCreateReadResult(chunk, false, forAuthorCode)
138 | );
139 | }
140 | const pendingPromise = ReadableStreamAddReadRequest(stream, forAuthorCode);
141 | ReadableStreamDefaultControllerCallPullIfNeeded(this);
142 | return pendingPromise;
143 | }
144 | }
145 |
146 | export function IsReadableStreamDefaultController(
147 | x
148 | ): x is ReadableStreamDefaultController {
149 | return typeof x === "object" && x.hasOwnProperty("controlledReadableStream");
150 | }
151 |
152 | export function ReadableStreamDefaultControllerCallPullIfNeeded(
153 | controller: ReadableStreamDefaultController
154 | ) {
155 | const shouldPull = ReadableStreamDefaultControllerShouldCallPull(controller);
156 | if (!shouldPull) {
157 | return;
158 | }
159 | if (controller.pulling) {
160 | controller.pullAgain = true;
161 | return;
162 | }
163 | Assert(!controller.pullAgain);
164 | controller.pulling = true;
165 | controller
166 | .pullAlgorithm()
167 | .then(() => {
168 | controller.pulling = false;
169 | if (controller.pullAgain) {
170 | controller.pullAgain = false;
171 | ReadableStreamDefaultControllerCallPullIfNeeded(controller);
172 | }
173 | })
174 | .catch(r => {
175 | ReadableStreamDefaultControllerError(controller, r);
176 | });
177 | }
178 |
179 | export function ReadableStreamDefaultControllerShouldCallPull(
180 | controller: ReadableStreamDefaultController
181 | ) {
182 | const stream = controller.controlledReadableStream;
183 | if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(controller)) {
184 | return false;
185 | }
186 | if (!controller.started) {
187 | return false;
188 | }
189 | if (
190 | IsReadableStreamLocked(stream) &&
191 | ReadableStreamGetNumReadRequests(stream) > 0
192 | ) {
193 | return true;
194 | }
195 | const desiredSize = ReadableStreamDefaultControllerGetDesiredSize(controller);
196 | Assert(desiredSize !== null);
197 | return desiredSize > 0;
198 | }
199 |
200 | export function ReadableStreamDefaultControllerClearAlgorithms(
201 | controller: ReadableStreamDefaultController
202 | ) {
203 | controller.pullAlgorithm = void 0;
204 | controller.cancelAlgorithm = void 0;
205 | controller.strategySizeAlgorithm = void 0;
206 | }
207 |
208 | export function ReadableStreamDefaultControllerClose(controller) {
209 | const stream = controller.controlledReadableStream;
210 | Assert(ReadableStreamDefaultControllerCanCloseOrEnqueue(controller));
211 | controller.closeRequested = true;
212 | if (controller.queue.length === 0) {
213 | ReadableStreamDefaultControllerClearAlgorithms(controller);
214 | ReadableStreamClose(stream);
215 | }
216 | }
217 |
218 | export function ReadableStreamDefaultControllerEnqueue(controller, chunk) {
219 | if (IsReadableStreamDefaultController(controller)) {
220 | const stream = controller.controlledReadableStream;
221 | Assert(ReadableStreamDefaultControllerCanCloseOrEnqueue(controller));
222 | if (
223 | IsReadableStreamLocked(stream) &&
224 | ReadableStreamGetNumReadRequests(stream) > 0
225 | ) {
226 | ReadableStreamFulfillReadRequest(stream, chunk, false);
227 | } else {
228 | let result: number;
229 | try {
230 | result = controller.strategySizeAlgorithm(chunk);
231 | } catch (e) {
232 | ReadableStreamDefaultControllerError(controller, e);
233 | return e;
234 | }
235 | const chunkSize = result;
236 | try {
237 | EnqueueValueWithSize(controller, chunk, chunkSize);
238 | } catch (e) {
239 | ReadableStreamDefaultControllerError(controller, e);
240 | return e;
241 | }
242 | ReadableStreamDefaultControllerCallPullIfNeeded(controller);
243 | }
244 | }
245 | }
246 |
247 | export function ReadableStreamDefaultControllerError(controller, e) {
248 | if (IsReadableStreamDefaultController(controller)) {
249 | const stream = controller.controlledReadableStream;
250 | if (stream.state !== "readable") {
251 | return;
252 | }
253 | ResetQueue(controller);
254 | ReadableStreamDefaultControllerClearAlgorithms(controller);
255 | ReadableStreamError(stream, e);
256 | }
257 | }
258 |
259 | export function ReadableStreamDefaultControllerGetDesiredSize(
260 | controller: ReadableStreamDefaultController
261 | ): number | null {
262 | const stream = controller.controlledReadableStream;
263 | const state = stream.state;
264 | if (state === "errored") {
265 | return null;
266 | }
267 | if (state === "closed") {
268 | return 0;
269 | }
270 | return controller.strategyHWM - controller.queueTotalSize;
271 | }
272 |
273 | export function ReadableStreamDefaultControllerHasBackpressure(
274 | controller: ReadableStreamDefaultController
275 | ): boolean {
276 | return !ReadableStreamDefaultControllerShouldCallPull(controller);
277 | }
278 |
279 | export function ReadableStreamDefaultControllerCanCloseOrEnqueue(
280 | controller: ReadableStreamDefaultController
281 | ): boolean {
282 | const state = controller.controlledReadableStream.state;
283 | return !controller.closeRequested && state === "readable";
284 | }
285 |
286 | export function SetUpReadableStreamDefaultController(params: {
287 | stream: ReadableStream;
288 | controller: ReadableStreamDefaultController;
289 | startAlgorithm: StartAlgorithm;
290 | pullAlgorithm: PullAlgorithm;
291 | cancelAlgorithm: CancelAlgorithm;
292 | highWaterMark: number;
293 | sizeAlgorithm: SizeAlgorithm;
294 | }) {
295 | const {
296 | stream,
297 | controller,
298 | startAlgorithm,
299 | pullAlgorithm,
300 | cancelAlgorithm
301 | } = params;
302 | let { highWaterMark, sizeAlgorithm } = params;
303 | Assert(stream.readableStreamController === void 0);
304 | controller.controlledReadableStream = stream;
305 | controller.queue = void 0;
306 | controller.queueTotalSize = void 0;
307 | ResetQueue(controller);
308 | controller.started = false;
309 | controller.closeRequested = false;
310 | controller.pullAgain = false;
311 | controller.pulling = false;
312 | controller.strategySizeAlgorithm = sizeAlgorithm;
313 | controller.strategyHWM = highWaterMark;
314 | controller.pullAlgorithm = pullAlgorithm;
315 | controller.cancelAlgorithm = cancelAlgorithm;
316 | stream.readableStreamController = controller;
317 | Promise.resolve(startAlgorithm())
318 | .then(() => {
319 | controller.started = true;
320 | Assert(controller.pulling == false);
321 | Assert(controller.pullAgain == false);
322 | ReadableStreamDefaultControllerCallPullIfNeeded(controller);
323 | })
324 | .catch(r => {
325 | ReadableStreamDefaultControllerError(controller, r);
326 | });
327 | }
328 |
329 | export function SetUpReadableStreamDefaultControllerFromUnderlyingSource(params: {
330 | stream: ReadableStream;
331 | underlyingSource: UnderlyingSource;
332 | highWaterMark: number;
333 | sizeAlgorithm: SizeAlgorithm;
334 | }) {
335 | const { stream, underlyingSource, highWaterMark, sizeAlgorithm } = params;
336 | Assert(underlyingSource !== void 0);
337 | const controller = Object.create(ReadableStreamDefaultController.prototype);
338 | const startAlgorithm = () =>
339 | InvokeOrNoop(underlyingSource, "start", controller);
340 | const pullAlgorithm = CreateAlgorithmFromUnderlyingMethod(
341 | underlyingSource,
342 | "pull",
343 | 0,
344 | controller
345 | );
346 | const cancelAlgorithm = CreateAlgorithmFromUnderlyingMethod(
347 | underlyingSource,
348 | "cancel",
349 | 1
350 | );
351 | SetUpReadableStreamDefaultController({
352 | stream,
353 | controller,
354 | startAlgorithm,
355 | pullAlgorithm,
356 | cancelAlgorithm,
357 | highWaterMark,
358 | sizeAlgorithm
359 | });
360 | }
361 |
--------------------------------------------------------------------------------
/writable_stream.ts:
--------------------------------------------------------------------------------
1 | import {
2 | WritableStreamDefaultWriter,
3 | WritableStreamDefaultWriterEnsureReadyPromiseRejected,
4 | WritableStreamWriter
5 | } from "./writable_stream_writer.ts";
6 | import { defer, Defer } from "./defer.ts";
7 | import { SizeAlgorithm, StartAlgorithm } from "./readable_stream.ts";
8 | import {
9 | IsNonNegativeNumber,
10 | MakeSizeAlgorithmFromSizeFunction,
11 | ValidateAndNormalizeHighWaterMark
12 | } from "./misc.ts";
13 | import { Assert } from "./util.ts";
14 | import {
15 | AbortSteps,
16 | createWritableStreamDefaultController,
17 | ErrorSteps,
18 | SetUpWritableStreamDefaultController,
19 | SetUpWritableStreamDefaultControllerFromUnderlyingSink,
20 | WritableStreamDefaultController
21 | } from "./writable_stream_controller.ts";
22 | import { QueuingStrategy } from "./strategy.ts";
23 |
24 | export type WriteAlgorithm = (chunk: T) => any;
25 | export type CloseAlgorithm = () => any;
26 | export type AbortAlgorithm = (reason) => any;
27 |
28 | export class WritableStream {
29 | constructor(
30 | underlyingSink: {
31 | start?: StartAlgorithm;
32 | write?: WriteAlgorithm;
33 | close?: CloseAlgorithm;
34 | abort?: AbortAlgorithm;
35 | type?: string;
36 | },
37 | strategy: QueuingStrategy = {}
38 | ) {
39 | InitializeWritableStream(this);
40 | let { size, highWaterMark } = strategy;
41 | const { type } = underlyingSink;
42 | if (type !== void 0) {
43 | throw new RangeError("type should not be specified yet");
44 | }
45 | const sizeAlgorithm = MakeSizeAlgorithmFromSizeFunction(size);
46 | if (highWaterMark === void 0) {
47 | highWaterMark = 1;
48 | }
49 | highWaterMark = ValidateAndNormalizeHighWaterMark(highWaterMark);
50 | SetUpWritableStreamDefaultControllerFromUnderlyingSink(
51 | this,
52 | underlyingSink,
53 | highWaterMark,
54 | sizeAlgorithm
55 | );
56 | }
57 |
58 | get locked() {
59 | if (!IsWritableStream(this)) {
60 | throw new TypeError("this is not writable stream");
61 | }
62 | return IsWritableStreamLocked(this);
63 | }
64 |
65 | async abort(reason) {
66 | if (!IsWritableStream(this)) {
67 | throw new TypeError("this is not writable stream");
68 | }
69 | if (IsWritableStreamLocked(this)) {
70 | throw new TypeError("stream locked");
71 | }
72 | return WritableStreamAbort(this, reason);
73 | }
74 |
75 | getWriter(): WritableStreamWriter {
76 | if (!IsWritableStream(this)) {
77 | throw new TypeError("this is not writable stream");
78 | }
79 | return AcquireWritableStreamDefaultWriter(this);
80 | }
81 |
82 | backpressure;
83 | closeRequest: Defer;
84 | inFlightWriteRequest: Defer;
85 | inFlightCloseRequest: Defer;
86 | pendingAbortRequest: {
87 | promise: Defer;
88 | reason;
89 | wasAlreadyErroring: boolean;
90 | };
91 | state: "writable" | "closed" | "erroring" | "errored";
92 | storedError: Error;
93 | writableStreamController: WritableStreamDefaultController;
94 | writer: WritableStreamDefaultWriter;
95 | writeRequests: Defer[];
96 | }
97 |
98 | export function AcquireWritableStreamDefaultWriter(
99 | stream: WritableStream
100 | ): WritableStreamDefaultWriter {
101 | return new WritableStreamDefaultWriter(stream);
102 | }
103 |
104 | export function CreateWritableStream(
105 | startAlgorithm: StartAlgorithm,
106 | writeAlgorithm: WriteAlgorithm,
107 | closeAlgorithm: CloseAlgorithm,
108 | abortAlgorithm: AbortAlgorithm,
109 | highWaterMark: number = 1,
110 | sizeAlgorithm: SizeAlgorithm = () => 1
111 | ) {
112 | Assert(IsNonNegativeNumber(highWaterMark));
113 | const stream = Object.create(WritableStream.prototype);
114 | InitializeWritableStream(stream);
115 | const controller = createWritableStreamDefaultController();
116 | SetUpWritableStreamDefaultController({
117 | stream,
118 | controller,
119 | startAlgorithm,
120 | writeAlgorithm,
121 | closeAlgorithm,
122 | abortAlgorithm,
123 | highWaterMark,
124 | sizeAlgorithm
125 | });
126 | }
127 |
128 | export function InitializeWritableStream(stream: WritableStream) {
129 | stream.state = "writable";
130 | stream.storedError = void 0;
131 | stream.writer = void 0;
132 | stream.writableStreamController = void 0;
133 | stream.inFlightCloseRequest = void 0;
134 | stream.closeRequest = void 0;
135 | stream.pendingAbortRequest = void 0;
136 | stream.writeRequests = [];
137 | stream.backpressure = false;
138 | }
139 |
140 | export function IsWritableStream(x): x is WritableStream {
141 | return typeof x === "object" && x.hasOwnProperty("writableStreamController");
142 | }
143 |
144 | export function IsWritableStreamLocked(stream: WritableStream) {
145 | Assert(IsWritableStream(stream));
146 | return stream.writer !== void 0;
147 | }
148 |
149 | export async function WritableStreamAbort(
150 | stream: WritableStream,
151 | reason
152 | ): Promise {
153 | const { state } = stream;
154 | if (state === "closed" || state === "errored") {
155 | return void 0;
156 | }
157 | if (stream.pendingAbortRequest !== void 0) {
158 | return stream.pendingAbortRequest.promise;
159 | }
160 | Assert(stream.state === "writable" || stream.state === "erroring");
161 | let wasAlreadyErroring = false;
162 | if (state === "erroring") {
163 | wasAlreadyErroring = true;
164 | reason = void 0;
165 | }
166 | const promise = defer();
167 | stream.pendingAbortRequest = {
168 | promise,
169 | reason,
170 | wasAlreadyErroring
171 | };
172 | if (!wasAlreadyErroring) {
173 | WritableStreamStartErroring(stream, reason);
174 | }
175 | return promise;
176 | }
177 |
178 | export function WritableStreamAddWriteRequest(stream: WritableStream) {
179 | Assert(IsWritableStreamLocked(stream));
180 | Assert(stream.state === "writable");
181 | const promise = defer();
182 | stream.writeRequests.push(promise);
183 | return promise;
184 | }
185 |
186 | export function WritableStreamDealWithRejection(stream: WritableStream, error) {
187 | const { state } = stream;
188 | if (state === "writable") {
189 | WritableStreamStartErroring(stream, error);
190 | return;
191 | }
192 | Assert(state === "erroring");
193 | WritableStreamFinishErroring(stream);
194 | }
195 |
196 | export function WritableStreamStartErroring(stream: WritableStream, reason) {
197 | Assert(stream.storedError === void 0);
198 | Assert(stream.state === "writable");
199 | const controller = stream.writableStreamController;
200 | Assert(controller !== void 0);
201 | stream.state = "erroring";
202 | stream.storedError = reason;
203 | const { writer } = stream;
204 | if (writer !== void 0) {
205 | WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason);
206 | }
207 | if (!WritableStreamHasOperationMarkedInFlight(stream) && controller.started) {
208 | WritableStreamFinishErroring(stream);
209 | }
210 | }
211 |
212 | export function WritableStreamFinishErroring(stream: WritableStream) {
213 | Assert(stream.state === "erroring");
214 | Assert(!WritableStreamHasOperationMarkedInFlight(stream));
215 | stream.state = "errored";
216 | stream.writableStreamController[ErrorSteps]();
217 | const { storedError } = stream;
218 | stream.writeRequests.forEach(p => p.reject(storedError));
219 | stream.writeRequests = [];
220 | if (stream.pendingAbortRequest === void 0) {
221 | WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
222 | return;
223 | }
224 | const abortRequest = stream.pendingAbortRequest;
225 | stream.pendingAbortRequest = void 0;
226 | if (abortRequest.wasAlreadyErroring) {
227 | abortRequest.promise.reject(storedError);
228 | WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
229 | return;
230 | }
231 | const promise = stream.writableStreamController[AbortSteps](
232 | abortRequest.reason
233 | );
234 | promise
235 | .then(() => {
236 | abortRequest.promise.resolve(void 0);
237 | WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
238 | })
239 | .catch(r => {
240 | abortRequest.promise.reject(r);
241 | WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream);
242 | });
243 | }
244 |
245 | export function WritableStreamFinishInFlightWrite(stream: WritableStream) {
246 | Assert(stream.inFlightWriteRequest !== void 0);
247 | stream.inFlightWriteRequest.resolve(void 0);
248 | stream.inFlightWriteRequest = void 0;
249 | }
250 |
251 | export function WritableStreamFinishInFlightWriteWithError(
252 | stream: WritableStream,
253 | error
254 | ) {
255 | Assert(stream.inFlightWriteRequest !== void 0);
256 | stream.inFlightWriteRequest.resolve(void 0);
257 | stream.inFlightWriteRequest = void 0;
258 | Assert(stream.state === "writable" || stream.state === "erroring");
259 | WritableStreamDealWithRejection(stream, error);
260 | }
261 |
262 | export function WritableStreamFinishInFlightClose(stream: WritableStream) {
263 | Assert(stream.inFlightCloseRequest !== void 0);
264 | stream.inFlightCloseRequest.resolve(void 0);
265 | stream.inFlightCloseRequest = void 0;
266 | const { state } = stream;
267 | Assert(stream.state === "writable" || stream.state === "erroring");
268 | if (state === "erroring") {
269 | stream.storedError = void 0;
270 | if (stream.pendingAbortRequest !== void 0) {
271 | stream.pendingAbortRequest.promise.resolve(void 0);
272 | stream.pendingAbortRequest = void 0;
273 | }
274 | }
275 | stream.state = "closed";
276 | const { writer } = stream;
277 | if (writer !== void 0) {
278 | writer.closedPromise.resolve(void 0);
279 | }
280 | Assert(stream.pendingAbortRequest === void 0);
281 | Assert(stream.storedError === void 0);
282 | }
283 |
284 | export function WritableStreamFinishInFlightCloseWithError(
285 | stream: WritableStream,
286 | error
287 | ) {
288 | Assert(stream.inFlightCloseRequest !== void 0);
289 | stream.inFlightCloseRequest.resolve(void 0);
290 | stream.inFlightCloseRequest = void 0;
291 | Assert(stream.state === "writable" || stream.state === "erroring");
292 | if (stream.pendingAbortRequest !== void 0) {
293 | stream.pendingAbortRequest.promise.reject(error);
294 | stream.pendingAbortRequest = void 0;
295 | }
296 | WritableStreamDealWithRejection(stream, error);
297 | }
298 |
299 | export function WritableStreamCloseQueuedOrInFlight(stream: WritableStream) {
300 | return !(
301 | stream.closeRequest === void 0 || stream.inFlightCloseRequest === void 0
302 | );
303 | }
304 |
305 | export function WritableStreamHasOperationMarkedInFlight(
306 | stream: WritableStream
307 | ) {
308 | return !(
309 | stream.inFlightWriteRequest === void 0 &&
310 | stream.inFlightCloseRequest === void 0
311 | );
312 | }
313 |
314 | export function WritableStreamMarkCloseRequestInFlight(stream: WritableStream) {
315 | Assert(stream.inFlightCloseRequest === void 0);
316 | Assert(stream.closeRequest !== void 0);
317 | stream.inFlightCloseRequest = stream.closeRequest;
318 | stream.closeRequest = void 0;
319 | }
320 |
321 | export function WritableStreamMarkFirstWriteRequestInFlight(
322 | stream: WritableStream
323 | ) {
324 | Assert(stream.inFlightWriteRequest === void 0);
325 | Assert(stream.writeRequests.length > 0);
326 | const writerRequest = stream.writeRequests.shift();
327 | stream.inFlightWriteRequest = writerRequest;
328 | }
329 |
330 | export function WritableStreamRejectCloseAndClosedPromiseIfNeeded(
331 | stream: WritableStream
332 | ) {
333 | Assert(stream.state === "errored");
334 | if (stream.pendingAbortRequest !== void 0) {
335 | Assert(stream.inFlightCloseRequest !== void 0);
336 | stream.closeRequest.reject(stream.storedError);
337 | stream.closeRequest = void 0;
338 | }
339 | const { writer } = stream;
340 | if (writer !== void 0) {
341 | writer.closedPromise.reject(stream.storedError);
342 | }
343 | }
344 |
345 | export function WritableStreamUpdateBackpressure(
346 | stream: WritableStream,
347 | backpressure: boolean
348 | ) {
349 | Assert(stream.state === "writable");
350 | Assert(!WritableStreamCloseQueuedOrInFlight(stream));
351 | const { writer } = stream;
352 | if (writer !== void 0 && backpressure !== stream.backpressure) {
353 | if (backpressure) {
354 | writer.readyPromise = defer();
355 | } else {
356 | Assert(!backpressure);
357 | writer.readyPromise.resolve(void 0);
358 | }
359 | }
360 | stream.backpressure = backpressure;
361 | }
362 |
--------------------------------------------------------------------------------
/readable_stream.ts:
--------------------------------------------------------------------------------
1 | import {
2 | IsReadableStreamDefaultReader,
3 | ReadableStreamDefaultReader,
4 | ReadableStreamDefaultReaderRead,
5 | ReadableStreamReader,
6 | ReadableStreamReaderGenericRelease
7 | } from "./readable_stream_reader.ts";
8 | import { Assert, isAbortSignal } from "./util.ts";
9 | import {
10 | ReadableStreamController,
11 | ReadableStreamDefaultController,
12 | ReadableStreamDefaultControllerClose,
13 | ReadableStreamDefaultControllerEnqueue,
14 | ReadableStreamDefaultControllerError,
15 | SetUpReadableStreamDefaultController,
16 | SetUpReadableStreamDefaultControllerFromUnderlyingSource
17 | } from "./readable_stream_controller.ts";
18 | import {
19 | IsNonNegativeNumber,
20 | MakeSizeAlgorithmFromSizeFunction,
21 | ValidateAndNormalizeHighWaterMark
22 | } from "./misc.ts";
23 | import { defer } from "./defer.ts";
24 | import {
25 | AcquireWritableStreamDefaultWriter,
26 | IsWritableStream,
27 | IsWritableStreamLocked,
28 | WritableStream,
29 | WritableStreamAbort,
30 | WritableStreamCloseQueuedOrInFlight
31 | } from "./writable_stream.ts";
32 | import {
33 | WritableStreamDefaultWriterCloseWithErrorPropagation,
34 | WritableStreamDefaultWriterGetDesiredSize,
35 | WritableStreamDefaultWriterRelease
36 | } from "./writable_stream_writer.ts";
37 | import { QueuingStrategy } from "./strategy.ts";
38 | import {
39 | IsReadableByteStreamController,
40 | SetUpReadableByteStreamController,
41 | SetUpReadableByteStreamControllerFromUnderlyingSource,
42 | ReadableByteStreamController
43 | } from "./readable_byte_stream_controller.ts";
44 | import {
45 | IsReadableStreamBYOBReader,
46 | ReadableStreamBYOBReader
47 | } from "./readable_stream_byob_reader.ts";
48 |
49 | export type UnderlyingSource = {
50 | type?: "bytes";
51 | autoAllocateChunkSize?: number;
52 | start?: (controller: ReadableStreamController) => any;
53 | pull?: (controller: ReadableStreamController) => any;
54 | cancel?: CancelAlgorithm;
55 | };
56 |
57 | export type StartAlgorithm = () => any;
58 | export type PullAlgorithm = () => Promise;
59 | export type CancelAlgorithm = (reason) => Promise;
60 | export type SizeAlgorithm = (chunk) => number;
61 |
62 | export type ReadableStreamReadResult = { value: T; done: boolean };
63 |
64 | export class ReadableStream {
65 | disturbed: boolean;
66 | readableStreamController:
67 | | ReadableByteStreamController
68 | | ReadableStreamDefaultController;
69 | reader: ReadableStreamDefaultReader | ReadableStreamBYOBReader;
70 | state: "readable" | "closed" | "errored";
71 | storedError: Error;
72 |
73 | constructor(
74 | underlyingSource: UnderlyingSource = {},
75 | strategy: QueuingStrategy = {}
76 | ) {
77 | InitializeReadableStream(this);
78 | let { highWaterMark, size } = strategy;
79 | const { type } = underlyingSource;
80 | if (type === "bytes") {
81 | if (size !== void 0) {
82 | throw new RangeError();
83 | }
84 | if (highWaterMark === void 0) {
85 | highWaterMark = 0;
86 | }
87 | highWaterMark = ValidateAndNormalizeHighWaterMark(highWaterMark);
88 | SetUpReadableByteStreamControllerFromUnderlyingSource(
89 | this,
90 | underlyingSource,
91 | highWaterMark
92 | );
93 | } else if (type === void 0) {
94 | const sizeAlgorithm = MakeSizeAlgorithmFromSizeFunction(size);
95 | if (highWaterMark === void 0) {
96 | highWaterMark = 0;
97 | }
98 | highWaterMark = ValidateAndNormalizeHighWaterMark(highWaterMark);
99 | SetUpReadableStreamDefaultControllerFromUnderlyingSource({
100 | stream: this,
101 | underlyingSource,
102 | highWaterMark,
103 | sizeAlgorithm
104 | });
105 | } else {
106 | throw new RangeError();
107 | }
108 | }
109 |
110 | get locked(): boolean {
111 | if (!IsReadableStream(this)) {
112 | throw new TypeError();
113 | }
114 | return IsReadableStreamLocked(this);
115 | }
116 |
117 | cancel(reason?): Promise {
118 | if (IsReadableStream(this)) {
119 | return Promise.reject(new TypeError());
120 | }
121 | if (IsReadableStreamLocked(this)) {
122 | return Promise.reject(new TypeError());
123 | }
124 | return ReadableStreamCancel(this, reason);
125 | }
126 |
127 | getReader(
128 | params: { mode?: "byob" } = {}
129 | ): ReadableStreamBYOBReader | ReadableStreamReader {
130 | if (!IsReadableStream(this)) {
131 | throw new TypeError();
132 | }
133 | if (params.mode === void 0) {
134 | return AcquireReadableStreamDefaultReader(this);
135 | }
136 | if (params.mode === "byob") {
137 | return AcquireReadableStreamBYOBReader(this);
138 | }
139 | throw new RangeError();
140 | }
141 |
142 | pipeThrough(
143 | {
144 | writable,
145 | readable
146 | }: {
147 | writable: WritableStream;
148 | readable: ReadableStream;
149 | },
150 | {
151 | preventClose,
152 | preventAbort,
153 | preventCancel,
154 | signal
155 | }: {
156 | preventClose?: boolean;
157 | preventAbort?: boolean;
158 | preventCancel?: boolean;
159 | signal?: domTypes.AbortSignal;
160 | } = {}
161 | ) {
162 | if (!IsReadableStream(this)) {
163 | throw new TypeError("this is not ReadableStream");
164 | }
165 | if (!IsWritableStream(writable)) {
166 | throw new TypeError("writable is not WritableStream");
167 | }
168 | if (!IsReadableStream(readable)) {
169 | throw new TypeError("readable is not ReadableStream");
170 | }
171 | preventClose = !!preventClose;
172 | preventAbort = !!preventAbort;
173 | preventCancel = !!preventCancel;
174 | if (signal !== void 0 && !isAbortSignal(signal)) {
175 | throw new TypeError("signal is not instance of AbortSignal");
176 | }
177 | if (IsReadableStreamLocked(this)) {
178 | throw new TypeError("this stream is locked");
179 | }
180 | if (IsWritableStreamLocked(writable)) {
181 | throw new TypeError("writable is locked");
182 | }
183 | ReadableStreamPipeTo(
184 | this,
185 | writable,
186 | preventClose,
187 | preventAbort,
188 | preventCancel,
189 | signal
190 | );
191 | return readable;
192 | }
193 |
194 | async pipeTo(
195 | dest: WritableStream,
196 | {
197 | preventClose,
198 | preventAbort,
199 | preventCancel,
200 | signal
201 | }: {
202 | preventClose?: boolean;
203 | preventAbort?: boolean;
204 | preventCancel?: boolean;
205 | signal?;
206 | } = {}
207 | ): Promise {
208 | if (!IsReadableStream(this)) {
209 | throw new TypeError("this is not ReadableStream");
210 | }
211 | if (!IsWritableStream(dest)) {
212 | throw new TypeError("dest is not WritableStream");
213 | }
214 | preventClose = !!preventClose;
215 | preventAbort = !!preventAbort;
216 | preventCancel = !!preventCancel;
217 | if (signal !== void 0 && !isAbortSignal(signal)) {
218 | throw new TypeError("signal is not instance of AbortSignal");
219 | }
220 | if (IsReadableStreamLocked(this)) {
221 | throw new TypeError("this stream is locked");
222 | }
223 | if (IsWritableStreamLocked(dest)) {
224 | throw new TypeError("writable is locked");
225 | }
226 | return ReadableStreamPipeTo(
227 | this,
228 | dest,
229 | preventClose,
230 | preventCancel,
231 | preventAbort,
232 | signal
233 | );
234 | }
235 |
236 | tee(): [ReadableStream, ReadableStream] {
237 | if (!IsReadableStream(this)) {
238 | throw new TypeError();
239 | }
240 | return ReadableStreamTee(this, false);
241 | }
242 | }
243 |
244 | function AcquireReadableStreamBYOBReader(
245 | stream: ReadableStream
246 | ): ReadableStreamBYOBReader {
247 | return new ReadableStreamBYOBReader(stream);
248 | }
249 |
250 | function AcquireReadableStreamDefaultReader(
251 | stream: ReadableStream
252 | ): ReadableStreamDefaultReader {
253 | return new ReadableStreamDefaultReader(stream);
254 | }
255 |
256 | export function CreateReadableStream(
257 | startAlgorithm: StartAlgorithm,
258 | pullAlgorithm: PullAlgorithm,
259 | cancelAlgorithm: CancelAlgorithm,
260 | highWaterMark: number = 1,
261 | sizeAlgorithm: SizeAlgorithm = () => 1
262 | ): ReadableStream {
263 | Assert(IsNonNegativeNumber(highWaterMark));
264 | const stream = Object.create(ReadableStream.prototype);
265 | InitializeReadableStream(stream);
266 | const controller = Object.create(ReadableStreamDefaultController.prototype);
267 | SetUpReadableStreamDefaultController({
268 | stream,
269 | controller,
270 | startAlgorithm,
271 | pullAlgorithm,
272 | cancelAlgorithm,
273 | highWaterMark,
274 | sizeAlgorithm
275 | });
276 | return stream;
277 | }
278 |
279 | export function CreateReadableByteStream(
280 | startAlgorithm: StartAlgorithm,
281 | pullAlgorithm: PullAlgorithm,
282 | cancelAlgorithm: CancelAlgorithm,
283 | highWaterMark: number = 1,
284 | autoAllocateChunkSize?: number
285 | ) {
286 | Assert(IsNonNegativeNumber(highWaterMark));
287 | if (autoAllocateChunkSize !== void 0) {
288 | Assert(Number.isInteger(autoAllocateChunkSize));
289 | Assert(autoAllocateChunkSize > 0);
290 | }
291 | const stream = Object.create(ReadableStream.prototype);
292 | InitializeReadableStream(stream);
293 | const controller = Object.create(ReadableByteStreamController.prototype);
294 | SetUpReadableByteStreamController(
295 | stream,
296 | controller,
297 | startAlgorithm,
298 | pullAlgorithm,
299 | cancelAlgorithm,
300 | highWaterMark,
301 | autoAllocateChunkSize
302 | );
303 | return stream;
304 | }
305 |
306 | export function InitializeReadableStream(stream: ReadableStream) {
307 | stream.state = "readable";
308 | stream.reader = void 0;
309 | stream.storedError = void 0;
310 | stream.disturbed = false;
311 | }
312 |
313 | export function IsReadableStream(x): x is ReadableStream {
314 | return typeof x === "object" && x.hasOwnProperty("readableStreamController");
315 | }
316 |
317 | export function IsReadableStreamDisturbed(stream: ReadableStream): boolean {
318 | Assert(IsReadableStream(stream));
319 | return stream.disturbed;
320 | }
321 |
322 | export function IsReadableStreamLocked(stream: ReadableStream): boolean {
323 | Assert(IsReadableStream(stream));
324 | return stream.reader !== void 0;
325 | }
326 |
327 | export function ReadableStreamTee(
328 | stream: ReadableStream,
329 | cloneForBranch2: boolean
330 | ): [ReadableStream, ReadableStream] {
331 | Assert(IsReadableStream(stream));
332 | Assert(typeof cloneForBranch2 === "boolean");
333 | const reader = AcquireReadableStreamDefaultReader(stream);
334 | let closedOrErrored = false;
335 | let canceled1 = false;
336 | let canceled2 = false;
337 | let reason1 = void 0;
338 | let reason2 = void 0;
339 | let branch1: ReadableStream = void 0;
340 | let branch2: ReadableStream = void 0;
341 | let cancelPromise = defer();
342 | const pullAlgorithm: PullAlgorithm = () => {
343 | return ReadableStreamDefaultReaderRead(reader).then(
344 | (result: { value; done: boolean }) => {
345 | Assert(typeof result === "object");
346 | const { value, done } = result;
347 | Assert(typeof done === "boolean");
348 | if (done && !closedOrErrored) {
349 | if (!canceled1) {
350 | ReadableStreamDefaultControllerClose(
351 | branch1.readableStreamController
352 | );
353 | }
354 | if (!canceled2) {
355 | ReadableStreamDefaultControllerClose(
356 | branch2.readableStreamController
357 | );
358 | }
359 | }
360 | if (closedOrErrored) {
361 | return;
362 | }
363 | let [value1, value2] = [value, value];
364 | if (!canceled2 && cloneForBranch2) {
365 | //value2 <- ?StructuredDeserialize( ? StructuredSerialize( value2 ), 現在の Realm Record )
366 | }
367 | if (!canceled1) {
368 | ReadableStreamDefaultControllerEnqueue(
369 | branch1.readableStreamController,
370 | value1
371 | );
372 | }
373 | if (!canceled2) {
374 | ReadableStreamDefaultControllerEnqueue(
375 | branch1.readableStreamController,
376 | value2
377 | );
378 | }
379 | }
380 | );
381 | };
382 | const cancel1Algorithm: CancelAlgorithm = reason => {
383 | canceled1 = true;
384 | reason1 = reason;
385 | if (canceled2) {
386 | const compositeReason = [reason1, reason2];
387 | const cancelResult = ReadableStreamCancel(stream, compositeReason);
388 | cancelPromise.resolve(cancelResult);
389 | }
390 | return cancelPromise;
391 | };
392 | const cancel2Algorithm: CancelAlgorithm = reason => {
393 | canceled2 = true;
394 | reason2 = reason;
395 | if (canceled1) {
396 | const compositeReason = [reason1, reason2];
397 | const cancelResult = ReadableStreamCancel(stream, compositeReason);
398 | cancelPromise.resolve(cancelResult);
399 | }
400 | return cancelPromise;
401 | };
402 | const startAlgorithm: StartAlgorithm = () => void 0;
403 | branch1 = CreateReadableStream(
404 | startAlgorithm,
405 | pullAlgorithm,
406 | cancel1Algorithm
407 | );
408 | branch2 = CreateReadableStream(
409 | startAlgorithm,
410 | pullAlgorithm,
411 | cancel2Algorithm
412 | );
413 | reader.closedPromise.catch(r => {
414 | if (!closedOrErrored) {
415 | ReadableStreamDefaultControllerError(branch1.readableStreamController, r);
416 | ReadableStreamDefaultControllerError(branch2.readableStreamController, r);
417 | closedOrErrored = true;
418 | }
419 | });
420 | return [branch1, branch2];
421 | }
422 |
423 | export async function ReadableStreamPipeTo(
424 | source: ReadableStream,
425 | dest: WritableStream,
426 | preventClose: boolean,
427 | preventAbort: boolean,
428 | preventCancel: boolean,
429 | signal?
430 | ) {
431 | Assert(IsReadableStream(source));
432 | Assert(IsWritableStream(dest));
433 | Assert(typeof preventCancel === "boolean");
434 | Assert(typeof preventAbort === "boolean");
435 | Assert(typeof preventClose === "boolean");
436 | Assert(signal === void 0 || isAbortSignal(signal));
437 | Assert(!IsReadableStreamLocked(source));
438 | Assert(!IsWritableStreamLocked(dest));
439 | let reader: ReadableStreamBYOBReader | ReadableStreamDefaultReader;
440 | if (IsReadableByteStreamController(source.readableStreamController)) {
441 | reader = AcquireReadableStreamBYOBReader(source);
442 | } else {
443 | reader = AcquireReadableStreamDefaultReader(source);
444 | }
445 | const writer = AcquireWritableStreamDefaultWriter(dest);
446 | let shutingDown = false;
447 | const promsie = defer();
448 | let abortAlgorithm;
449 | if (!signal) {
450 | abortAlgorithm = () => {
451 | let error = new Error("aborted");
452 | const actions = [];
453 | if (!preventAbort) {
454 | actions.push(async () => {
455 | if (dest.state === "writable") {
456 | return WritableStreamAbort(dest, error);
457 | }
458 | });
459 | }
460 | if (!preventCancel) {
461 | actions.push(async () => {
462 | if (source.state === "readable") {
463 | return ReadableStreamCancel(source, error);
464 | }
465 | });
466 | }
467 | shutdown(error, () => Promise.all(actions.map(p => p())));
468 | if (signal.aborted) {
469 | abortAlgorithm();
470 | return promsie;
471 | }
472 | signal.addEventListener("onabort", abortAlgorithm);
473 | };
474 | }
475 | const finalize = (error?) => {
476 | WritableStreamDefaultWriterRelease(writer);
477 | ReadableStreamReaderGenericRelease(reader);
478 | if (signal) {
479 | signal.removeEventListener("onabort", abortAlgorithm);
480 | }
481 | if (error) {
482 | promsie.reject(error);
483 | } else {
484 | promsie.resolve();
485 | }
486 | };
487 | const shutdown = (err?, action?: () => Promise) => {
488 | if (shutingDown) {
489 | return;
490 | }
491 | shutingDown = true;
492 | if (
493 | dest.state === "writable" ||
494 | !WritableStreamCloseQueuedOrInFlight(dest)
495 | ) {
496 | }
497 | if (!action) {
498 | finalize(err);
499 | return;
500 | }
501 | action()
502 | .then(() => finalize(err))
503 | .catch(finalize);
504 | };
505 | (async () => {
506 | while (true) {
507 | const desiredSize = WritableStreamDefaultWriterGetDesiredSize(writer);
508 | if (desiredSize === null || desiredSize <= 0) {
509 | return;
510 | }
511 | if (source.state === "errored") {
512 | if (!preventAbort) {
513 | shutdown(source.storedError, () => {
514 | return WritableStreamAbort(dest, source.storedError);
515 | });
516 | } else {
517 | shutdown(source.storedError);
518 | }
519 | } else if (dest.state === "errored") {
520 | if (!preventCancel) {
521 | shutdown(dest.storedError, () => {
522 | return ReadableStreamCancel(source, dest.storedError);
523 | });
524 | } else {
525 | shutdown(dest.storedError);
526 | }
527 | } else if (source.state === "closed") {
528 | if (!preventClose) {
529 | shutdown(void 0, () => {
530 | return WritableStreamDefaultWriterCloseWithErrorPropagation(writer);
531 | });
532 | } else {
533 | shutdown();
534 | }
535 | } else if (
536 | WritableStreamCloseQueuedOrInFlight(dest) ||
537 | dest.state === "closed"
538 | ) {
539 | const destClosed = new TypeError();
540 | if (!preventCancel) {
541 | shutdown(destClosed, () => {
542 | return ReadableStreamCancel(source, destClosed);
543 | });
544 | } else {
545 | shutdown(destClosed);
546 | }
547 | }
548 | if (IsReadableStreamBYOBReader(reader)) {
549 | let view = new Uint8Array(desiredSize);
550 | const { done } = await reader.read(view);
551 | if (done) break;
552 | await writer.write(view);
553 | } else {
554 | const { value, done } = await reader.read();
555 | if (done) break;
556 | await writer.write(value);
557 | }
558 | }
559 | })();
560 | return promsie;
561 | }
562 |
563 | export function ReadableStreamAddReadIntoRequest(
564 | stream: ReadableStream,
565 | forAuthorCode
566 | ) {
567 | Assert(IsReadableStreamBYOBReader(stream.reader));
568 | const reader = stream.reader as ReadableStreamBYOBReader;
569 | Assert(stream.state === "readable" || stream.state === "closed");
570 | const promise = defer();
571 | const readIntoRequest = { promise, forAuthorCode };
572 | reader.readIntoRequests.push(readIntoRequest);
573 | return promise;
574 | }
575 |
576 | export function ReadableStreamAddReadRequest(
577 | stream: ReadableStream,
578 | forAuthorCode
579 | ): Promise<{ value; done: boolean }> {
580 | Assert(IsReadableStreamDefaultReader(stream.reader));
581 | const reader = stream.reader as ReadableStreamDefaultReader;
582 | Assert(stream.state === "readable" || stream.state === "closed");
583 | const promise = defer<{ value; done: boolean }>();
584 | const readIntoRequest = { promise, forAuthorCode };
585 | reader.readRequests.push(readIntoRequest);
586 | return promise;
587 | }
588 |
589 | export function ReadableStreamCancel(
590 | stream: ReadableStream,
591 | reason
592 | ): Promise {
593 | stream.disturbed = true;
594 | if (stream.state === "closed") {
595 | return Promise.reject(void 0);
596 | }
597 | if (stream.state === "errored") {
598 | return Promise.reject(stream.storedError);
599 | }
600 | ReadableStreamClose(stream);
601 | const sourceCancelPromise = stream.readableStreamController.cancelAlgorithm(
602 | reason
603 | );
604 | return sourceCancelPromise.then(() => void 0);
605 | }
606 |
607 | export function ReadableStreamClose(stream: ReadableStream) {
608 | Assert(stream.state === "readable");
609 | stream.state = "closed";
610 | const reader = stream.reader;
611 | if (reader === void 0) {
612 | return;
613 | }
614 | if (IsReadableStreamDefaultReader(reader)) {
615 | for (let req of reader.readRequests) {
616 | const resolved = ReadableStreamCreateReadResult(
617 | void 0,
618 | true,
619 | req.forAuthorCode
620 | );
621 | req.promise.resolve(resolved);
622 | }
623 | reader.readRequests = [];
624 | }
625 | reader.closedPromise.resolve(void 0);
626 | }
627 |
628 | export function ReadableStreamCreateReadResult(
629 | value,
630 | done: boolean,
631 | forAuthorCode: boolean
632 | ): ReadableStreamReadResult {
633 | const ret = forAuthorCode ? Object.create({}) : Object.create(null);
634 | ret["value"] = value as T;
635 | ret["done"] = done;
636 | return { value, done };
637 | }
638 |
639 | export function ReadableStreamError(stream: ReadableStream, e) {
640 | Assert(IsReadableStream(stream));
641 | Assert(stream.state === "readable");
642 | stream.state = "errored";
643 | stream.storedError = e;
644 | const reader = stream.reader;
645 | if (stream.reader === void 0) {
646 | return;
647 | }
648 | if (IsReadableStreamDefaultReader(reader)) {
649 | for (const req of reader.readRequests) {
650 | req.promise.reject(e);
651 | }
652 | reader.readRequests = [];
653 | } else if (IsReadableStreamBYOBReader(reader)) {
654 | for (const req of reader.readIntoRequests) {
655 | req.promise.reject(e);
656 | }
657 | reader.readIntoRequests = [];
658 | }
659 | reader.closedPromise.reject(e);
660 | //TODO: Set reader.[[closedPromise]].[[PromiseIsHandled]] to true.
661 | }
662 |
663 | export function ReadableStreamFulfillReadIntoRequest(
664 | stream: ReadableStream,
665 | chunk,
666 | done
667 | ) {
668 | const reader = stream.reader;
669 | const req = (reader).readIntoRequests.shift();
670 | req.promise.resolve(
671 | ReadableStreamCreateReadResult(chunk, done, req.forAuthorCode)
672 | );
673 | }
674 |
675 | export function ReadableStreamFulfillReadRequest(
676 | stream: ReadableStream,
677 | chunk,
678 | done
679 | ) {
680 | const reader = stream.reader;
681 | const req = (>reader).readRequests.shift();
682 | req.promise.resolve(
683 | ReadableStreamCreateReadResult(chunk, done, req.forAuthorCode)
684 | );
685 | }
686 |
687 | export function ReadableStreamGetNumReadIntoRequests(stream: ReadableStream) {
688 | return (stream.reader).readIntoRequests.length;
689 | }
690 |
691 | export function ReadableStreamGetNumReadRequests(stream) {
692 | return (>stream.reader).readRequests.length;
693 | }
694 |
695 | export function ReadableStreamHasBYOBReader(stream: ReadableStream): boolean {
696 | const reader = stream.reader;
697 | if (reader === void 0) {
698 | return false;
699 | }
700 | return IsReadableStreamBYOBReader(reader);
701 | }
702 |
703 | export function ReadableStreamHasDefaultReader(stream): boolean {
704 | const reader = stream.reader;
705 | if (reader === void 0) {
706 | return false;
707 | }
708 | return IsReadableStreamDefaultReader(reader);
709 | }
710 |
--------------------------------------------------------------------------------
/readable_byte_stream_controller.ts:
--------------------------------------------------------------------------------
1 | import {
2 | CancelAlgorithm,
3 | IsReadableStreamLocked,
4 | PullAlgorithm,
5 | ReadableStream,
6 | ReadableStreamAddReadIntoRequest,
7 | ReadableStreamAddReadRequest,
8 | ReadableStreamClose,
9 | ReadableStreamCreateReadResult,
10 | ReadableStreamError,
11 | ReadableStreamFulfillReadIntoRequest,
12 | ReadableStreamFulfillReadRequest,
13 | ReadableStreamGetNumReadIntoRequests,
14 | ReadableStreamGetNumReadRequests,
15 | ReadableStreamHasBYOBReader,
16 | ReadableStreamHasDefaultReader,
17 | ReadableStreamReadResult,
18 | StartAlgorithm,
19 | UnderlyingSource
20 | } from "./readable_stream.ts";
21 | import {
22 | ReadableStreamBYOBRequest,
23 | ReadableStreamBYOBRequestImpl,
24 | SetUpReadableStreamBYOBRequest
25 | } from "./readable_stream_request.ts";
26 | import {
27 | CreateAlgorithmFromUnderlyingMethod,
28 | InvokeOrNoop,
29 | IsFiniteNonNegativeNumber,
30 | ResetQueue,
31 | TransferArrayBuffer,
32 | ValidateAndNormalizeHighWaterMark
33 | } from "./misc.ts";
34 | import { Assert, isArrayBufferView } from "./util.ts";
35 | import {
36 | PullIntoDescriptor,
37 | ReadableStreamController,
38 | ReadableStreamControllerBase
39 | } from "./readable_stream_controller.ts";
40 |
41 | export class ReadableByteStreamController extends ReadableStreamControllerBase
42 | implements ReadableStreamController {
43 | constructor() {
44 | super();
45 | throw new TypeError();
46 | }
47 |
48 | controlledReadableByteStream: ReadableStream;
49 | _byobRequest: ReadableStreamBYOBRequestImpl;
50 | get byobRequest(): ReadableStreamBYOBRequest {
51 | if (!IsReadableByteStreamController(this)) {
52 | throw new TypeError();
53 | }
54 | if (this._byobRequest === void 0 && this.pendingPullIntos.length > 0) {
55 | const firstDescriptor = this.pendingPullIntos[0];
56 | const { buffer, byteOffset, bytesFilled, byteLength } = firstDescriptor;
57 | const view = new Uint8Array(
58 | buffer,
59 | byteOffset + bytesFilled,
60 | byteLength - bytesFilled
61 | );
62 | const byobRequest = Object.create(
63 | ReadableStreamBYOBRequestImpl.prototype
64 | );
65 | SetUpReadableStreamBYOBRequest(byobRequest, this, view);
66 | this._byobRequest = byobRequest;
67 | }
68 | return this._byobRequest;
69 | }
70 |
71 | get desiredSize(): number {
72 | if (!IsReadableByteStreamController(this)) {
73 | throw new TypeError();
74 | }
75 | return ReadableByteStreamControllerGetDesiredSize(this);
76 | }
77 |
78 | close(): void {
79 | if (!IsReadableByteStreamController(this)) {
80 | throw new TypeError();
81 | }
82 | if (this.closeRequested) {
83 | throw new TypeError();
84 | }
85 | if (this.controlledReadableByteStream.state !== "readable") {
86 | throw new TypeError();
87 | }
88 | ReadableByteStreamControllerClose(this);
89 | }
90 |
91 | enqueue(chunk: ArrayBufferView): void {
92 | if (!IsReadableByteStreamController(this)) {
93 | throw new TypeError();
94 | }
95 | if (this.closeRequested) {
96 | throw new TypeError();
97 | }
98 | if (this.controlledReadableByteStream.state !== "readable") {
99 | throw new TypeError();
100 | }
101 | if (typeof chunk !== "object") {
102 | throw new TypeError();
103 | }
104 | if (!isArrayBufferView(chunk)) {
105 | throw new TypeError("chunk is not ArrayBufferView: " + chunk);
106 | }
107 | ReadableByteStreamControllerEnqueue(this, chunk);
108 | }
109 |
110 | error(e): void {
111 | if (!IsReadableByteStreamController(this)) {
112 | throw new TypeError();
113 | }
114 | ReadableByteStreamControllerError(this, e);
115 | }
116 |
117 | CancelSteps(reason): Promise {
118 | ResetQueue(this);
119 | const result = this.cancelAlgorithm(reason);
120 | ReadableByteStreamControllerClearAlgorithms(this);
121 | return result;
122 | }
123 |
124 | PullSteps(
125 | forAuthorCode?: boolean
126 | ): Promise> {
127 | const stream = this.controlledReadableByteStream;
128 | Assert(ReadableStreamHasDefaultReader(stream));
129 | if (this.queueTotalSize > 0) {
130 | Assert(ReadableStreamGetNumReadRequests(stream) === 0);
131 | const entry = this.queue.shift();
132 | this.queueTotalSize -= entry.byteLength;
133 | ReadableByteStreamControllerHandleQueueDrain(this);
134 | const view = new Uint8Array(
135 | entry.buffer,
136 | entry.byteOffset,
137 | entry.byteLength
138 | );
139 | return Promise.resolve(
140 | ReadableStreamCreateReadResult(view, false, forAuthorCode)
141 | );
142 | }
143 | const { autoAllocateChunkSize } = this;
144 | if (autoAllocateChunkSize !== void 0) {
145 | let buffer: ArrayBuffer;
146 | try {
147 | buffer = new ArrayBuffer(autoAllocateChunkSize);
148 | } catch (e) {
149 | return Promise.reject(e);
150 | }
151 | const pullIntoDescriptor: PullIntoDescriptor = {
152 | buffer,
153 | byteOffset: 0,
154 | byteLength: autoAllocateChunkSize,
155 | bytesFilled: 0,
156 | elementSize: 1,
157 | ctor: Uint8Array,
158 | readerType: "default"
159 | };
160 | this.pendingPullIntos.push(pullIntoDescriptor);
161 | }
162 | const promise = ReadableStreamAddReadRequest(stream, forAuthorCode);
163 | ReadableByteStreamControllerCallPullIfNeeded(this);
164 | return promise;
165 | }
166 | }
167 |
168 | export function IsReadableByteStreamController(
169 | x
170 | ): x is ReadableByteStreamController {
171 | return (
172 | typeof x === "object" && x.hasOwnProperty("controlledReadableByteStream")
173 | );
174 | }
175 |
176 | export function ReadableByteStreamControllerCallPullIfNeeded(
177 | controller: ReadableByteStreamController
178 | ) {
179 | const shouldPull = ReadableByteStreamControllerShouldCallPull(controller);
180 | if (!shouldPull) {
181 | return;
182 | }
183 | if (controller.pulling) {
184 | controller.pullAgain = true;
185 | return;
186 | }
187 | Assert(!controller.pullAgain);
188 | controller.pulling = true;
189 | controller
190 | .pullAlgorithm()
191 | .then(() => {
192 | controller.pulling = false;
193 | if (controller.pullAgain) {
194 | controller.pullAgain = false;
195 | ReadableByteStreamControllerCallPullIfNeeded(controller);
196 | }
197 | })
198 | .catch(r => {
199 | ReadableByteStreamControllerError(controller, r);
200 | });
201 | }
202 |
203 | export function ReadableByteStreamControllerClearAlgorithms(
204 | controller: ReadableByteStreamController
205 | ) {
206 | controller.pullAlgorithm = void 0;
207 | controller.cancelAlgorithm = void 0;
208 | }
209 |
210 | export function ReadableByteStreamControllerClearPendingPullIntos(
211 | controller: ReadableByteStreamController
212 | ) {
213 | ReadableByteStreamControllerInvalidateBYOBRequest(controller);
214 | controller.pendingPullIntos = [];
215 | }
216 |
217 | export function ReadableByteStreamControllerClose(
218 | controller: ReadableByteStreamController
219 | ) {
220 | const stream = controller.controlledReadableByteStream;
221 | Assert(controller.closeRequested === false);
222 | Assert(stream.state === "readable");
223 | if (controller.queueTotalSize > 0) {
224 | controller.closeRequested = true;
225 | return;
226 | }
227 | if (controller.pendingPullIntos.length > 0) {
228 | const firstPengingPullInfo = controller.pendingPullIntos[0];
229 | if (firstPengingPullInfo.bytesFilled > 0) {
230 | const e = new TypeError();
231 | ReadableByteStreamControllerError(controller, e);
232 | throw e;
233 | }
234 | }
235 | ReadableByteStreamControllerClearAlgorithms(controller);
236 | ReadableStreamClose(stream);
237 | }
238 |
239 | export function ReadableByteStreamControllerCommitPullIntoDescriptor(
240 | stream: ReadableStream,
241 | pullIntoDescriptor: PullIntoDescriptor
242 | ) {
243 | Assert(stream.state !== "errored");
244 | let done = false;
245 | if (stream.state === "closed") {
246 | Assert(pullIntoDescriptor.bytesFilled === 0);
247 | done = true;
248 | }
249 | const filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(
250 | pullIntoDescriptor
251 | );
252 | if (pullIntoDescriptor.readerType === "default") {
253 | ReadableStreamFulfillReadRequest(stream, filledView, done);
254 | } else {
255 | Assert(pullIntoDescriptor.readerType === "byob");
256 | ReadableStreamFulfillReadIntoRequest(stream, filledView, done);
257 | }
258 | }
259 |
260 | export function ReadableByteStreamControllerConvertPullIntoDescriptor(
261 | pullIntoDescriptor: PullIntoDescriptor
262 | ) {
263 | const { bytesFilled, elementSize } = pullIntoDescriptor;
264 | Assert(bytesFilled <= pullIntoDescriptor.byteLength);
265 | Assert(bytesFilled % pullIntoDescriptor.elementSize === 0);
266 | return new pullIntoDescriptor.ctor(
267 | pullIntoDescriptor.buffer,
268 | pullIntoDescriptor.byteOffset,
269 | bytesFilled / elementSize
270 | );
271 | }
272 |
273 | export function ReadableByteStreamControllerEnqueue(
274 | controller: ReadableByteStreamController,
275 | chunk: ArrayBufferView
276 | ) {
277 | const stream = controller.controlledReadableByteStream;
278 | Assert(controller.closeRequested === false);
279 | Assert(stream.state === "readable");
280 | const { buffer } = chunk;
281 | const { byteOffset, byteLength } = chunk;
282 | const transferredBuffer = TransferArrayBuffer(buffer);
283 | if (ReadableStreamHasDefaultReader(stream)) {
284 | if (ReadableStreamGetNumReadRequests(stream) === 0) {
285 | ReadableByteStreamControllerEnqueueChunkToQueue(
286 | controller,
287 | transferredBuffer,
288 | byteOffset,
289 | byteLength
290 | );
291 | } else {
292 | Assert(controller.queue.length === 0, "l=0");
293 | const transferredView = new Uint8Array(
294 | transferredBuffer,
295 | byteOffset,
296 | byteLength
297 | );
298 | ReadableStreamFulfillReadRequest(stream, transferredView, false);
299 | }
300 | } else if (ReadableStreamHasBYOBReader(stream)) {
301 | ReadableByteStreamControllerEnqueueChunkToQueue(
302 | controller,
303 | transferredBuffer,
304 | byteOffset,
305 | byteLength
306 | );
307 | ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
308 | controller
309 | );
310 | } else {
311 | Assert(
312 | IsReadableStreamLocked(stream) === false,
313 | "stream should not be locked"
314 | );
315 | ReadableByteStreamControllerEnqueueChunkToQueue(
316 | controller,
317 | transferredBuffer,
318 | byteOffset,
319 | byteLength
320 | );
321 | }
322 | ReadableByteStreamControllerCallPullIfNeeded(controller);
323 | }
324 |
325 | export function ReadableByteStreamControllerEnqueueChunkToQueue(
326 | controller: ReadableByteStreamController,
327 | buffer: ArrayBuffer,
328 | byteOffset: number,
329 | byteLength: number
330 | ) {
331 | controller.queue.push({
332 | buffer,
333 | byteOffset,
334 | byteLength
335 | });
336 | controller.queueTotalSize += byteLength;
337 | }
338 |
339 | export function ReadableByteStreamControllerError(
340 | controller: ReadableByteStreamController,
341 | e
342 | ) {
343 | const stream = controller.controlledReadableByteStream;
344 | if (stream.state !== "readable") {
345 | return;
346 | }
347 | ReadableByteStreamControllerClearPendingPullIntos(controller);
348 | ResetQueue(controller);
349 | ReadableByteStreamControllerClearAlgorithms(controller);
350 | ReadableStreamError(controller.controlledReadableByteStream, e);
351 | }
352 |
353 | export function ReadableByteStreamControllerFillHeadPullIntoDescriptor(
354 | controller: ReadableByteStreamController,
355 | size: number,
356 | pullIntoDescriptor: PullIntoDescriptor
357 | ) {
358 | Assert(
359 | controller.pendingPullIntos.length === 0 ||
360 | controller.pendingPullIntos[0] === pullIntoDescriptor
361 | );
362 | ReadableByteStreamControllerInvalidateBYOBRequest(controller);
363 | pullIntoDescriptor.bytesFilled += size;
364 | }
365 |
366 | export function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
367 | controller: ReadableByteStreamController,
368 | pullIntoDescriptor: PullIntoDescriptor
369 | ): boolean {
370 | const { elementSize } = pullIntoDescriptor;
371 | const currentAlignedBytes =
372 | pullIntoDescriptor.bytesFilled -
373 | (pullIntoDescriptor.bytesFilled % elementSize);
374 | const maxBytesToCopy = Math.min(
375 | controller.queueTotalSize,
376 | pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled
377 | );
378 | const maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy;
379 | const maxAlignedBytes = maxBytesFilled - (maxBytesFilled % elementSize);
380 | let totalBytesToCopyRemaining = maxBytesToCopy;
381 | let ready = false;
382 | if (maxAlignedBytes > currentAlignedBytes) {
383 | totalBytesToCopyRemaining =
384 | maxAlignedBytes - pullIntoDescriptor.bytesFilled;
385 | ready = true;
386 | }
387 | const { queue } = controller;
388 | while (totalBytesToCopyRemaining > 0) {
389 | const headOfQueue = queue[0];
390 | const bytesToCopy = Math.min(
391 | totalBytesToCopyRemaining,
392 | headOfQueue.byteLength
393 | );
394 | const destStart =
395 | pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled;
396 | const srcView = new Uint8Array(
397 | headOfQueue.buffer,
398 | headOfQueue.byteOffset,
399 | headOfQueue.byteLength
400 | );
401 | const destView = new Uint8Array(
402 | pullIntoDescriptor.buffer,
403 | destStart,
404 | bytesToCopy
405 | );
406 | for (let i = 0; i < bytesToCopy; i++) {
407 | destView[i] = srcView[i];
408 | }
409 | if (headOfQueue.byteLength === bytesToCopy) {
410 | queue.shift();
411 | } else {
412 | headOfQueue.byteOffset += bytesToCopy;
413 | headOfQueue.byteLength -= bytesToCopy;
414 | }
415 | controller.queueTotalSize -= bytesToCopy;
416 | ReadableByteStreamControllerFillHeadPullIntoDescriptor(
417 | controller,
418 | bytesToCopy,
419 | pullIntoDescriptor
420 | );
421 | totalBytesToCopyRemaining -= bytesToCopy;
422 | }
423 | if (ready === false) {
424 | Assert(controller.queueTotalSize === 0);
425 | Assert(pullIntoDescriptor.bytesFilled > 0);
426 | Assert(pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize);
427 | }
428 | return ready;
429 | }
430 |
431 | export function ReadableByteStreamControllerGetDesiredSize(
432 | controller: ReadableByteStreamController
433 | ): number | null {
434 | const stream = controller.controlledReadableByteStream;
435 | const { state } = stream;
436 | if (state === "errored") {
437 | return null;
438 | }
439 | if (state === "closed") {
440 | return 0;
441 | }
442 | return controller.strategyHWM - controller.queueTotalSize;
443 | }
444 |
445 | export function ReadableByteStreamControllerHandleQueueDrain(
446 | controller: ReadableByteStreamController
447 | ) {
448 | Assert(controller.controlledReadableByteStream.state === "readable");
449 | if (controller.queueTotalSize === 0 && controller.closeRequested) {
450 | ReadableByteStreamControllerClearAlgorithms(controller);
451 | ReadableStreamClose(controller.controlledReadableByteStream);
452 | } else {
453 | ReadableByteStreamControllerCallPullIfNeeded(controller);
454 | }
455 | }
456 |
457 | export function ReadableByteStreamControllerInvalidateBYOBRequest(
458 | controller: ReadableByteStreamController
459 | ) {
460 | if (controller._byobRequest === void 0) {
461 | return;
462 | }
463 | controller._byobRequest.associatedReadableByteStreamController = void 0;
464 | controller._byobRequest._view = void 0;
465 | controller._byobRequest = void 0;
466 | }
467 |
468 | export function ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
469 | controller: ReadableByteStreamController
470 | ) {
471 | Assert(controller.closeRequested === false);
472 | while (controller.pendingPullIntos.length > 0) {
473 | if (controller.queueTotalSize === 0) {
474 | return;
475 | }
476 | const pullIntoDescriptor = controller.pendingPullIntos[0];
477 | if (
478 | ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
479 | controller,
480 | pullIntoDescriptor
481 | ) === true
482 | ) {
483 | ReadableByteStreamControllerShiftPendingPullInto(controller);
484 | ReadableByteStreamControllerCommitPullIntoDescriptor(
485 | controller.controlledReadableByteStream,
486 | pullIntoDescriptor
487 | );
488 | }
489 | }
490 | }
491 |
492 | const TypedArraySizeMap = {
493 | Int8Array: [1, Int8Array],
494 | Uint8Array: [1, Uint8Array],
495 | Uint8ClampedArray: [1, Uint8ClampedArray],
496 | Int16Array: [2, Int16Array],
497 | Uint16Array: [2, Uint16Array],
498 | Int32Array: [4, Int32Array],
499 | Uint32Array: [4, Uint32Array],
500 | Float32Array: [4, Float32Array],
501 | Float64Array: [8, Float64Array]
502 | };
503 |
504 | export function ReadableByteStreamControllerPullInto(
505 | controller: ReadableByteStreamController,
506 | view: ArrayBufferView,
507 | forAuthorCode?: boolean
508 | ): Promise {
509 | const stream = controller.controlledReadableByteStream;
510 | let elementSize = 1;
511 | let ctor = DataView;
512 | const ctorName = view.constructor.name;
513 | if (TypedArraySizeMap[ctorName]) {
514 | [elementSize, ctor] = TypedArraySizeMap[ctorName];
515 | }
516 | const { byteOffset, byteLength } = view;
517 | const buffer = TransferArrayBuffer(view.buffer);
518 | const pullIntoDescriptor: PullIntoDescriptor = {
519 | buffer,
520 | byteOffset,
521 | byteLength,
522 | bytesFilled: 0,
523 | elementSize,
524 | ctor,
525 | readerType: "byob"
526 | };
527 | if (controller.pendingPullIntos.length > 0) {
528 | controller.pendingPullIntos.push(pullIntoDescriptor);
529 | return ReadableStreamAddReadIntoRequest(stream, forAuthorCode);
530 | }
531 | if (stream.state === "closed") {
532 | const emptyView = new ctor(
533 | pullIntoDescriptor.buffer,
534 | pullIntoDescriptor.byteOffset,
535 | 0
536 | );
537 | return Promise.resolve(
538 | ReadableStreamCreateReadResult(emptyView, true, forAuthorCode)
539 | );
540 | }
541 | if (controller.queueTotalSize > 0) {
542 | if (
543 | ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
544 | controller,
545 | pullIntoDescriptor
546 | )
547 | ) {
548 | const filedView = ReadableByteStreamControllerConvertPullIntoDescriptor(
549 | pullIntoDescriptor
550 | );
551 | ReadableByteStreamControllerHandleQueueDrain(controller);
552 | return Promise.resolve(
553 | ReadableStreamCreateReadResult(filedView, false, forAuthorCode)
554 | );
555 | }
556 | if (controller.closeRequested) {
557 | const e = new TypeError();
558 | ReadableByteStreamControllerError(controller, e);
559 | return Promise.reject(e);
560 | }
561 | }
562 | controller.pendingPullIntos.push(pullIntoDescriptor);
563 | const promise = ReadableStreamAddReadIntoRequest(stream, forAuthorCode);
564 | ReadableByteStreamControllerCallPullIfNeeded(controller);
565 | return promise;
566 | }
567 |
568 | export function ReadableByteStreamControllerRespond(
569 | controller: ReadableByteStreamController,
570 | bytesWritten: number
571 | ): void {
572 | if (IsFiniteNonNegativeNumber(bytesWritten) === false) {
573 | throw new RangeError();
574 | }
575 | Assert(controller.pendingPullIntos.length > 0);
576 | ReadableByteStreamControllerRespondInternal(controller, bytesWritten);
577 | }
578 |
579 | export function ReadableByteStreamControllerRespondInClosedState(
580 | controller: ReadableByteStreamController,
581 | firstDescriptor: PullIntoDescriptor
582 | ) {
583 | firstDescriptor.buffer = TransferArrayBuffer(firstDescriptor.buffer);
584 | Assert(firstDescriptor.bytesFilled === 0);
585 | const stream = controller.controlledReadableByteStream;
586 | if (ReadableStreamHasBYOBReader(stream)) {
587 | while (ReadableStreamGetNumReadIntoRequests(stream) > 0) {
588 | const pullIntoDescriptor = ReadableByteStreamControllerShiftPendingPullInto(
589 | controller
590 | );
591 | ReadableByteStreamControllerCommitPullIntoDescriptor(
592 | stream,
593 | pullIntoDescriptor
594 | );
595 | }
596 | }
597 | }
598 |
599 | export function ReadableByteStreamControllerRespondInReadableState(
600 | controller: ReadableByteStreamController,
601 | bytesWritten: number,
602 | pullIntoDescriptor: PullIntoDescriptor
603 | ) {
604 | if (
605 | pullIntoDescriptor.bytesFilled + bytesWritten >
606 | pullIntoDescriptor.byteLength
607 | ) {
608 | throw new RangeError();
609 | }
610 | ReadableByteStreamControllerFillHeadPullIntoDescriptor(
611 | controller,
612 | bytesWritten,
613 | pullIntoDescriptor
614 | );
615 | if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) {
616 | return;
617 | }
618 | ReadableByteStreamControllerShiftPendingPullInto(controller);
619 | const remainderSize =
620 | pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize;
621 | if (remainderSize > 0) {
622 | const end = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled;
623 | const remainder = CloneArrayBuffer(
624 | pullIntoDescriptor.buffer,
625 | end - remainderSize,
626 | remainderSize
627 | );
628 | ReadableByteStreamControllerEnqueueChunkToQueue(
629 | controller,
630 | remainder,
631 | 0,
632 | remainder.byteLength
633 | );
634 | }
635 | pullIntoDescriptor.buffer = TransferArrayBuffer(pullIntoDescriptor.buffer);
636 | pullIntoDescriptor.bytesFilled =
637 | pullIntoDescriptor.bytesFilled - remainderSize;
638 | ReadableByteStreamControllerCommitPullIntoDescriptor(
639 | controller.controlledReadableByteStream,
640 | pullIntoDescriptor
641 | );
642 | ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller);
643 | }
644 |
645 | function CloneArrayBuffer(
646 | srcBuffer: ArrayBuffer,
647 | srcByteOffset: number,
648 | srcLength: number
649 | ): ArrayBuffer {
650 | const ret = new ArrayBuffer(srcLength);
651 | const retView = new DataView(ret);
652 | const srcView = new DataView(srcBuffer, srcByteOffset, srcLength);
653 | for (let i = 0; i < srcLength; i++) {
654 | retView[i] = srcView[i];
655 | }
656 | return ret;
657 | }
658 |
659 | export function ReadableByteStreamControllerRespondInternal(
660 | controller: ReadableByteStreamController,
661 | bytesWritten: number
662 | ) {
663 | const firstDescriptor = controller.pendingPullIntos[0];
664 | const stream = controller.controlledReadableByteStream;
665 | if (stream.state === "closed") {
666 | if (bytesWritten !== 0) {
667 | throw new TypeError();
668 | }
669 | ReadableByteStreamControllerRespondInClosedState(
670 | controller,
671 | firstDescriptor
672 | );
673 | } else {
674 | Assert(stream.state === "readable");
675 | ReadableByteStreamControllerRespondInReadableState(
676 | controller,
677 | bytesWritten,
678 | firstDescriptor
679 | );
680 | }
681 | ReadableByteStreamControllerCallPullIfNeeded(controller);
682 | }
683 |
684 | export function ReadableByteStreamControllerRespondWithNewView(
685 | controller: ReadableByteStreamController,
686 | view
687 | ) {
688 | Assert(controller.pendingPullIntos.length > 0);
689 | const firstDescriptor = controller.pendingPullIntos[0];
690 | if (
691 | firstDescriptor.byteOffset + firstDescriptor.bytesFilled !==
692 | view.ByteOffset
693 | ) {
694 | throw new RangeError();
695 | }
696 | if (firstDescriptor.byteLength !== view.ByteLength) {
697 | throw new RangeError();
698 | }
699 | firstDescriptor.buffer = view.ViewedArrayBuffer;
700 | ReadableByteStreamControllerRespondInternal(controller, view.ByteLength);
701 | }
702 |
703 | export function ReadableByteStreamControllerShiftPendingPullInto(
704 | controller: ReadableByteStreamController
705 | ): PullIntoDescriptor {
706 | const descriptor = controller.pendingPullIntos.shift();
707 | ReadableByteStreamControllerInvalidateBYOBRequest(controller);
708 | return descriptor;
709 | }
710 |
711 | export function ReadableByteStreamControllerShouldCallPull(
712 | controller: ReadableByteStreamController
713 | ) {
714 | const stream = controller.controlledReadableByteStream;
715 | if (stream.state !== "readable") {
716 | return false;
717 | }
718 | if (controller.closeRequested === true) {
719 | return false;
720 | }
721 | if (controller.started === false) {
722 | return false;
723 | }
724 | if (
725 | ReadableStreamHasDefaultReader(stream) &&
726 | ReadableStreamGetNumReadRequests(stream) > 0
727 | ) {
728 | return true;
729 | }
730 | if (
731 | ReadableStreamHasBYOBReader(stream) &&
732 | ReadableStreamGetNumReadIntoRequests(stream) > 0
733 | ) {
734 | return true;
735 | }
736 | const desiredSize = ReadableByteStreamControllerGetDesiredSize(controller);
737 | Assert(desiredSize !== null);
738 | if (desiredSize > 0) {
739 | return true;
740 | }
741 | return false;
742 | }
743 |
744 | export function SetUpReadableByteStreamController(
745 | stream: ReadableStream,
746 | controller: ReadableByteStreamController,
747 | startAlgorithm: StartAlgorithm,
748 | pullAlgorithm: PullAlgorithm,
749 | cancelAlgorithm: CancelAlgorithm,
750 | highWaterMark: number,
751 | autoAllocateChunkSize: number
752 | ) {
753 | Assert(stream.readableStreamController === void 0);
754 | if (autoAllocateChunkSize !== void 0) {
755 | Assert(Number.isInteger(autoAllocateChunkSize));
756 | Assert(autoAllocateChunkSize > 0);
757 | }
758 | controller.controlledReadableByteStream = stream;
759 | controller.pullAgain = false;
760 | controller.pulling = false;
761 | ReadableByteStreamControllerClearPendingPullIntos(controller);
762 | ResetQueue(controller);
763 | controller.closeRequested = false;
764 | controller.started = false;
765 | controller.strategyHWM = ValidateAndNormalizeHighWaterMark(highWaterMark);
766 | controller.pullAlgorithm = pullAlgorithm;
767 | controller.cancelAlgorithm = cancelAlgorithm;
768 | controller.autoAllocateChunkSize = autoAllocateChunkSize;
769 | controller.pendingPullIntos = [];
770 | stream.readableStreamController = controller;
771 | Promise.resolve(startAlgorithm())
772 | .then(() => {
773 | controller.started = true;
774 | Assert(!controller.pulling);
775 | Assert(!controller.pullAgain);
776 | ReadableByteStreamControllerCallPullIfNeeded(controller);
777 | })
778 | .catch(r => {
779 | ReadableByteStreamControllerError(controller, r);
780 | });
781 | }
782 |
783 | export function SetUpReadableByteStreamControllerFromUnderlyingSource(
784 | stream: ReadableStream,
785 | underlyingByteSource: UnderlyingSource,
786 | highWaterMark: number
787 | ) {
788 | Assert(underlyingByteSource !== void 0);
789 | const controller = Object.create(ReadableByteStreamController.prototype);
790 | const startAlgorithm = () =>
791 | InvokeOrNoop(underlyingByteSource, "start", controller);
792 | const pullAlgorithm = CreateAlgorithmFromUnderlyingMethod(
793 | underlyingByteSource,
794 | "pull",
795 | 0,
796 | controller
797 | );
798 | const cancelAlgorithm = CreateAlgorithmFromUnderlyingMethod(
799 | underlyingByteSource,
800 | "cancel",
801 | 1
802 | );
803 | const { autoAllocateChunkSize } = underlyingByteSource;
804 | if (autoAllocateChunkSize !== void 0) {
805 | if (!Number.isInteger(autoAllocateChunkSize) || autoAllocateChunkSize < 0) {
806 | throw new RangeError();
807 | }
808 | }
809 | SetUpReadableByteStreamController(
810 | stream,
811 | controller,
812 | startAlgorithm,
813 | pullAlgorithm,
814 | cancelAlgorithm,
815 | highWaterMark,
816 | autoAllocateChunkSize
817 | );
818 | }
819 |
--------------------------------------------------------------------------------