@yume-chan/stream-extra 0.0.18 → 0.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.json +33 -21
- package/CHANGELOG.md +8 -2
- package/README.md +1 -1
- package/esm/buffered-transform.d.ts +11 -10
- package/esm/buffered-transform.d.ts.map +1 -1
- package/esm/buffered-transform.js +55 -55
- package/esm/buffered-transform.js.map +1 -1
- package/esm/buffered.d.ts +29 -27
- package/esm/buffered.d.ts.map +1 -1
- package/esm/buffered.js +128 -123
- package/esm/buffered.js.map +1 -1
- package/esm/chunk.d.ts +7 -4
- package/esm/chunk.d.ts.map +1 -1
- package/esm/chunk.js +48 -7
- package/esm/chunk.js.map +1 -1
- package/esm/consumable.d.ts +53 -0
- package/esm/consumable.d.ts.map +1 -0
- package/esm/consumable.js +178 -0
- package/esm/consumable.js.map +1 -0
- package/esm/decode-utf8.d.ts +4 -4
- package/esm/decode-utf8.js +11 -11
- package/esm/distribution.d.ts +24 -0
- package/esm/distribution.d.ts.map +1 -0
- package/esm/distribution.js +99 -0
- package/esm/distribution.js.map +1 -0
- package/esm/duplex.d.ts +48 -47
- package/esm/duplex.d.ts.map +1 -1
- package/esm/duplex.js +90 -92
- package/esm/duplex.js.map +1 -1
- package/esm/gather-string.d.ts +6 -6
- package/esm/gather-string.d.ts.map +1 -1
- package/esm/gather-string.js +15 -13
- package/esm/gather-string.js.map +1 -1
- package/esm/index.d.ts +16 -15
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +16 -15
- package/esm/index.js.map +1 -1
- package/esm/inspect.d.ts +4 -4
- package/esm/inspect.js +11 -11
- package/esm/pipe-from.d.ts +12 -11
- package/esm/pipe-from.d.ts.map +1 -1
- package/esm/pipe-from.js +23 -25
- package/esm/pipe-from.js.map +1 -1
- package/esm/push-readable.d.ts +19 -18
- package/esm/push-readable.d.ts.map +1 -1
- package/esm/push-readable.js +61 -61
- package/esm/push-readable.js.map +1 -1
- package/esm/split-string.d.ts +4 -4
- package/esm/split-string.d.ts.map +1 -1
- package/esm/split-string.js +24 -24
- package/esm/split-string.js.map +1 -1
- package/esm/stream.d.ts +25 -24
- package/esm/stream.d.ts.map +1 -1
- package/esm/stream.js +26 -26
- package/esm/stream.js.map +1 -1
- package/esm/struct-deserialize.d.ts +6 -6
- package/esm/struct-deserialize.d.ts.map +1 -1
- package/esm/struct-deserialize.js +8 -8
- package/esm/struct-serialize.d.ts +5 -5
- package/esm/struct-serialize.js +10 -10
- package/esm/trace.d.ts +3 -3
- package/esm/wrap-readable.d.ts +21 -20
- package/esm/wrap-readable.d.ts.map +1 -1
- package/esm/wrap-readable.js +56 -56
- package/esm/wrap-readable.js.map +1 -1
- package/esm/wrap-writable.d.ts +14 -12
- package/esm/wrap-writable.d.ts.map +1 -1
- package/esm/wrap-writable.js +62 -52
- package/esm/wrap-writable.js.map +1 -1
- package/package.json +7 -6
- package/src/buffered-transform.ts +5 -10
- package/src/buffered.ts +7 -5
- package/src/consumable.ts +281 -0
- package/src/distribution.ts +113 -0
- package/src/duplex.ts +15 -16
- package/src/gather-string.ts +5 -3
- package/src/index.ts +16 -15
- package/src/inspect.ts +1 -1
- package/src/pipe-from.ts +8 -6
- package/src/push-readable.ts +3 -7
- package/src/split-string.ts +5 -2
- package/src/stream.ts +1 -1
- package/src/struct-deserialize.ts +1 -1
- package/src/wrap-readable.ts +5 -5
- package/src/wrap-writable.ts +16 -4
- package/tsconfig.build.tsbuildinfo +1 -1
- package/src/chunk.ts +0 -15
package/esm/wrap-writable.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
2
|
+
import type { TransformStream } from "./stream.js";
|
|
3
|
+
import { WritableStream } from "./stream.js";
|
|
4
|
+
export type WrapWritableStreamStart<T> = () => ValueOrPromise<WritableStream<T>>;
|
|
5
|
+
export interface WritableStreamWrapper<T> {
|
|
6
|
+
start: WrapWritableStreamStart<T>;
|
|
7
|
+
close?(): void | Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare class WrapWritableStream<T> extends WritableStream<T> {
|
|
10
|
+
writable: WritableStream<T>;
|
|
11
|
+
private writer;
|
|
12
|
+
constructor(wrapper: WritableStream<T> | WrapWritableStreamStart<T> | WritableStreamWrapper<T>);
|
|
13
|
+
bePipedThroughFrom<U>(transformer: TransformStream<U, T>): WrapWritableStream<U>;
|
|
14
|
+
}
|
|
13
15
|
//# sourceMappingURL=wrap-writable.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrap-writable.d.ts","sourceRoot":"","sources":["../src/wrap-writable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"wrap-writable.d.ts","sourceRoot":"","sources":["../src/wrap-writable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,OAAO,KAAK,EAAE,eAAe,EAA+B,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,uBAAuB,CAAC,CAAC,IAAI,MAAM,cAAc,CACzD,cAAc,CAAC,CAAC,CAAC,CACpB,CAAC;AAEF,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACpC,KAAK,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC;IAClC,KAAK,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAmBD,qBAAa,kBAAkB,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IACjD,QAAQ,EAAG,cAAc,CAAC,CAAC,CAAC,CAAC;IAEpC,OAAO,CAAC,MAAM,CAAkC;gBAG5C,OAAO,EACD,cAAc,CAAC,CAAC,CAAC,GACjB,uBAAuB,CAAC,CAAC,CAAC,GAC1B,qBAAqB,CAAC,CAAC,CAAC;IAmC3B,kBAAkB,CAAC,CAAC,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC;CAYlE"}
|
package/esm/wrap-writable.js
CHANGED
|
@@ -1,53 +1,63 @@
|
|
|
1
|
-
import { WritableStream } from "./stream.js";
|
|
2
|
-
async function getWrappedWritableStream(wrapper) {
|
|
3
|
-
if ("start" in wrapper) {
|
|
4
|
-
return await wrapper.start();
|
|
5
|
-
}
|
|
6
|
-
else if (typeof wrapper === "function") {
|
|
7
|
-
return await wrapper();
|
|
8
|
-
}
|
|
9
|
-
else {
|
|
10
|
-
// Can't use `wrapper instanceof WritableStream`
|
|
11
|
-
// Because we want to be compatible with any WritableStream-like objects
|
|
12
|
-
return wrapper;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
export class WrapWritableStream extends WritableStream {
|
|
16
|
-
writable;
|
|
17
|
-
writer;
|
|
18
|
-
constructor(wrapper) {
|
|
19
|
-
super({
|
|
20
|
-
start: async () => {
|
|
21
|
-
// `start` is invoked before `ReadableStream`'s constructor finish,
|
|
22
|
-
// so using `this` synchronously causes
|
|
23
|
-
// "Must call super constructor in derived class before accessing 'this' or returning from derived constructor".
|
|
24
|
-
// Queue a microtask to avoid this.
|
|
25
|
-
await Promise.resolve();
|
|
26
|
-
this.writable = await getWrappedWritableStream(wrapper);
|
|
27
|
-
this.writer = this.writable.getWriter();
|
|
28
|
-
},
|
|
29
|
-
write: async (chunk) => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
1
|
+
import { WritableStream } from "./stream.js";
|
|
2
|
+
async function getWrappedWritableStream(wrapper) {
|
|
3
|
+
if ("start" in wrapper) {
|
|
4
|
+
return await wrapper.start();
|
|
5
|
+
}
|
|
6
|
+
else if (typeof wrapper === "function") {
|
|
7
|
+
return await wrapper();
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
// Can't use `wrapper instanceof WritableStream`
|
|
11
|
+
// Because we want to be compatible with any WritableStream-like objects
|
|
12
|
+
return wrapper;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class WrapWritableStream extends WritableStream {
|
|
16
|
+
writable;
|
|
17
|
+
writer;
|
|
18
|
+
constructor(wrapper) {
|
|
19
|
+
super({
|
|
20
|
+
start: async () => {
|
|
21
|
+
// `start` is invoked before `ReadableStream`'s constructor finish,
|
|
22
|
+
// so using `this` synchronously causes
|
|
23
|
+
// "Must call super constructor in derived class before accessing 'this' or returning from derived constructor".
|
|
24
|
+
// Queue a microtask to avoid this.
|
|
25
|
+
await Promise.resolve();
|
|
26
|
+
this.writable = await getWrappedWritableStream(wrapper);
|
|
27
|
+
this.writer = this.writable.getWriter();
|
|
28
|
+
},
|
|
29
|
+
write: async (chunk) => {
|
|
30
|
+
await this.writer.write(chunk);
|
|
31
|
+
},
|
|
32
|
+
abort: async (reason) => {
|
|
33
|
+
await this.writer.abort(reason);
|
|
34
|
+
if ("close" in wrapper) {
|
|
35
|
+
await wrapper.close?.();
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
close: async () => {
|
|
39
|
+
// Close the inner stream first.
|
|
40
|
+
// Usually the inner stream is a logical sub-stream over the outer stream,
|
|
41
|
+
// closing the outer stream first will make the inner stream incapable of
|
|
42
|
+
// sending data in its `close` handler.
|
|
43
|
+
await this.writer.close();
|
|
44
|
+
if ("close" in wrapper) {
|
|
45
|
+
await wrapper.close?.();
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
bePipedThroughFrom(transformer) {
|
|
51
|
+
let promise;
|
|
52
|
+
return new WrapWritableStream({
|
|
53
|
+
start: () => {
|
|
54
|
+
promise = transformer.readable.pipeTo(this);
|
|
55
|
+
return transformer.writable;
|
|
56
|
+
},
|
|
57
|
+
async close() {
|
|
58
|
+
await promise;
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
53
63
|
//# sourceMappingURL=wrap-writable.js.map
|
package/esm/wrap-writable.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrap-writable.js","sourceRoot":"","sources":["../src/wrap-writable.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wrap-writable.js","sourceRoot":"","sources":["../src/wrap-writable.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAW7C,KAAK,UAAU,wBAAwB,CACnC,OAG8B;IAE9B,IAAI,OAAO,IAAI,OAAO,EAAE;QACpB,OAAO,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;KAChC;SAAM,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE;QACtC,OAAO,MAAM,OAAO,EAAE,CAAC;KAC1B;SAAM;QACH,gDAAgD;QAChD,wEAAwE;QACxE,OAAO,OAAO,CAAC;KAClB;AACL,CAAC;AAED,MAAM,OAAO,kBAAsB,SAAQ,cAAiB;IACjD,QAAQ,CAAqB;IAE5B,MAAM,CAAkC;IAEhD,YACI,OAG8B;QAE9B,KAAK,CAAC;YACF,KAAK,EAAE,KAAK,IAAI,EAAE;gBACd,mEAAmE;gBACnE,uCAAuC;gBACvC,gHAAgH;gBAChH,mCAAmC;gBACnC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;gBAExB,IAAI,CAAC,QAAQ,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,CAAC;gBACxD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC5C,CAAC;YACD,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;gBACnB,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACnC,CAAC;YACD,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;gBACpB,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAChC,IAAI,OAAO,IAAI,OAAO,EAAE;oBACpB,MAAM,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;iBAC3B;YACL,CAAC;YACD,KAAK,EAAE,KAAK,IAAI,EAAE;gBACd,gCAAgC;gBAChC,0EAA0E;gBAC1E,yEAAyE;gBACzE,uCAAuC;gBACvC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBAC1B,IAAI,OAAO,IAAI,OAAO,EAAE;oBACpB,MAAM,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;iBAC3B;YACL,CAAC;SACJ,CAAC,CAAC;IACP,CAAC;IAEM,kBAAkB,CAAI,WAAkC;QAC3D,IAAI,OAAsB,CAAC;QAC3B,OAAO,IAAI,kBAAkB,CAAI;YAC7B,KAAK,EAAE,GAAG,EAAE;gBACR,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC5C,OAAO,WAAW,CAAC,QAAQ,CAAC;YAChC,CAAC;YACD,KAAK,CAAC,KAAK;gBACP,MAAM,OAAO,CAAC;YAClB,CAAC;SACJ,CAAC,CAAC;IACP,CAAC;CACJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yume-chan/stream-extra",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.19",
|
|
4
4
|
"description": "Extensions to Web Streams API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"stream",
|
|
@@ -26,17 +26,18 @@
|
|
|
26
26
|
"types": "esm/index.d.ts",
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@yume-chan/async": "^2.2.0",
|
|
29
|
-
"@yume-chan/struct": "^0.0.
|
|
29
|
+
"@yume-chan/struct": "^0.0.19",
|
|
30
30
|
"tslib": "^2.4.1",
|
|
31
31
|
"web-streams-polyfill": "^4.0.0-beta.3"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@jest/globals": "^29.
|
|
34
|
+
"@jest/globals": "^29.5.0",
|
|
35
35
|
"@yume-chan/eslint-config": "^1.0.0",
|
|
36
36
|
"@yume-chan/tsconfig": "^1.0.0",
|
|
37
37
|
"cross-env": "^7.0.3",
|
|
38
|
-
"eslint": "^8.
|
|
39
|
-
"jest": "^29.
|
|
38
|
+
"eslint": "^8.36.0",
|
|
39
|
+
"jest": "^29.5.0",
|
|
40
|
+
"prettier": "^2.8.4",
|
|
40
41
|
"ts-jest": "^29.0.4",
|
|
41
42
|
"typescript": "^4.9.4"
|
|
42
43
|
},
|
|
@@ -44,6 +45,6 @@
|
|
|
44
45
|
"build": "tsc -b tsconfig.build.json",
|
|
45
46
|
"build:watch": "tsc -b tsconfig.build.json",
|
|
46
47
|
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage",
|
|
47
|
-
"lint": "eslint src/**/*.ts --fix"
|
|
48
|
+
"lint": "eslint src/**/*.ts --fix && prettier src/**/*.ts --write --tab-width 4"
|
|
48
49
|
}
|
|
49
50
|
}
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
BufferedReadableStream,
|
|
5
5
|
BufferedReadableStreamEndedError,
|
|
6
6
|
} from "./buffered.js";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from "./
|
|
11
|
-
import {
|
|
12
|
-
ReadableStream,
|
|
13
|
-
WritableStream,
|
|
14
|
-
type ReadableWritablePair,
|
|
15
|
-
} from "./stream.js";
|
|
7
|
+
import type { PushReadableStreamController } from "./push-readable.js";
|
|
8
|
+
import { PushReadableStream } from "./push-readable.js";
|
|
9
|
+
import type { ReadableWritablePair } from "./stream.js";
|
|
10
|
+
import { ReadableStream, WritableStream } from "./stream.js";
|
|
16
11
|
|
|
17
12
|
// TODO: BufferedTransformStream: find better implementation
|
|
18
13
|
export class BufferedTransformStream<T>
|
package/src/buffered.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { PushReadableStream } from "./push-readable.js";
|
|
2
|
-
import {
|
|
3
|
-
type ReadableStream,
|
|
4
|
-
type ReadableStreamDefaultReader,
|
|
5
|
-
} from "./stream.js";
|
|
2
|
+
import type { ReadableStream, ReadableStreamDefaultReader } from "./stream.js";
|
|
6
3
|
|
|
7
4
|
export class BufferedReadableStreamEndedError extends Error {
|
|
8
5
|
public constructor() {
|
|
@@ -18,8 +15,12 @@ export class BufferedReadableStream {
|
|
|
18
15
|
private bufferedOffset = 0;
|
|
19
16
|
private bufferedLength = 0;
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
private _position = 0;
|
|
19
|
+
public get position() {
|
|
20
|
+
return this._position;
|
|
21
|
+
}
|
|
22
22
|
|
|
23
|
+
protected readonly stream: ReadableStream<Uint8Array>;
|
|
23
24
|
protected readonly reader: ReadableStreamDefaultReader<Uint8Array>;
|
|
24
25
|
|
|
25
26
|
public constructor(stream: ReadableStream<Uint8Array>) {
|
|
@@ -32,6 +33,7 @@ export class BufferedReadableStream {
|
|
|
32
33
|
if (done) {
|
|
33
34
|
throw new BufferedReadableStreamEndedError();
|
|
34
35
|
}
|
|
36
|
+
this._position += value.byteLength;
|
|
35
37
|
return value;
|
|
36
38
|
}
|
|
37
39
|
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { PromiseResolver } from "@yume-chan/async";
|
|
2
|
+
|
|
3
|
+
import type { QueuingStrategy, WritableStreamDefaultWriter } from "./stream.js";
|
|
4
|
+
import { ReadableStream, TransformStream, WritableStream } from "./stream.js";
|
|
5
|
+
|
|
6
|
+
interface Task {
|
|
7
|
+
run<T>(callback: () => T): T;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface Console {
|
|
11
|
+
createTask(name: string): Task;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface GlobalEx {
|
|
15
|
+
console: Console;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// `createTask` allows browser DevTools to track the call stack across async boundaries.
|
|
19
|
+
const { console } = globalThis as unknown as GlobalEx;
|
|
20
|
+
const createTask: Console["createTask"] =
|
|
21
|
+
console.createTask?.bind(console) ??
|
|
22
|
+
(() => ({
|
|
23
|
+
run(callback) {
|
|
24
|
+
return callback();
|
|
25
|
+
},
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
export class Consumable<T> {
|
|
29
|
+
private readonly task: Task;
|
|
30
|
+
private readonly resolver: PromiseResolver<void>;
|
|
31
|
+
|
|
32
|
+
public readonly value: T;
|
|
33
|
+
public readonly consumed: Promise<void>;
|
|
34
|
+
|
|
35
|
+
public constructor(value: T) {
|
|
36
|
+
this.task = createTask("Consumable");
|
|
37
|
+
this.value = value;
|
|
38
|
+
this.resolver = new PromiseResolver<void>();
|
|
39
|
+
this.consumed = this.resolver.promise;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public consume() {
|
|
43
|
+
this.resolver.resolve();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public error(error: any) {
|
|
47
|
+
this.resolver.reject(error);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public async tryConsume<U>(callback: (value: T) => U) {
|
|
51
|
+
try {
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
53
|
+
const result = await this.task.run(() => callback(this.value));
|
|
54
|
+
this.consume();
|
|
55
|
+
return result;
|
|
56
|
+
} catch (e) {
|
|
57
|
+
this.resolver.reject(e);
|
|
58
|
+
throw e;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function enqueue<T>(
|
|
64
|
+
controller: { enqueue: (chunk: Consumable<T>) => void },
|
|
65
|
+
chunk: T
|
|
66
|
+
) {
|
|
67
|
+
const output = new Consumable(chunk);
|
|
68
|
+
controller.enqueue(output);
|
|
69
|
+
await output.consumed;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export class WrapConsumableStream<T> extends TransformStream<T, Consumable<T>> {
|
|
73
|
+
public constructor() {
|
|
74
|
+
super({
|
|
75
|
+
async transform(chunk, controller) {
|
|
76
|
+
await enqueue(controller, chunk);
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export class UnwrapConsumableStream<T> extends TransformStream<
|
|
83
|
+
Consumable<T>,
|
|
84
|
+
T
|
|
85
|
+
> {
|
|
86
|
+
public constructor() {
|
|
87
|
+
super({
|
|
88
|
+
transform(chunk, controller) {
|
|
89
|
+
controller.enqueue(chunk.value);
|
|
90
|
+
chunk.consume();
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface ConsumableReadableStreamController<T> {
|
|
97
|
+
enqueue(chunk: T): Promise<void>;
|
|
98
|
+
close(): void;
|
|
99
|
+
error(reason: any): void;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface ConsumableReadableStreamSource<T> {
|
|
103
|
+
start?(
|
|
104
|
+
controller: ConsumableReadableStreamController<T>
|
|
105
|
+
): void | PromiseLike<void>;
|
|
106
|
+
pull?(
|
|
107
|
+
controller: ConsumableReadableStreamController<T>
|
|
108
|
+
): void | PromiseLike<void>;
|
|
109
|
+
cancel?(reason: any): void | PromiseLike<void>;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export class ConsumableReadableStream<T> extends ReadableStream<Consumable<T>> {
|
|
113
|
+
public constructor(
|
|
114
|
+
source: ConsumableReadableStreamSource<T>,
|
|
115
|
+
strategy?: QueuingStrategy<T>
|
|
116
|
+
) {
|
|
117
|
+
let wrappedController:
|
|
118
|
+
| ConsumableReadableStreamController<T>
|
|
119
|
+
| undefined;
|
|
120
|
+
|
|
121
|
+
let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
|
|
122
|
+
if (strategy) {
|
|
123
|
+
wrappedStrategy = {};
|
|
124
|
+
if ("highWaterMark" in strategy) {
|
|
125
|
+
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
|
126
|
+
}
|
|
127
|
+
if ("size" in strategy) {
|
|
128
|
+
wrappedStrategy.size = (chunk) => {
|
|
129
|
+
return strategy.size!(chunk.value);
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
super(
|
|
135
|
+
{
|
|
136
|
+
async start(controller) {
|
|
137
|
+
wrappedController = {
|
|
138
|
+
async enqueue(chunk) {
|
|
139
|
+
await enqueue(controller, chunk);
|
|
140
|
+
},
|
|
141
|
+
close() {
|
|
142
|
+
controller.close();
|
|
143
|
+
},
|
|
144
|
+
error(reason) {
|
|
145
|
+
controller.error(reason);
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
await source.start?.(wrappedController);
|
|
150
|
+
},
|
|
151
|
+
async pull() {
|
|
152
|
+
await source.pull?.(wrappedController!);
|
|
153
|
+
},
|
|
154
|
+
async cancel(reason) {
|
|
155
|
+
await source.cancel?.(reason);
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
wrappedStrategy
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface ConsumableWritableStreamSink<T> {
|
|
164
|
+
start?(): void | PromiseLike<void>;
|
|
165
|
+
write?(chunk: T): void | PromiseLike<void>;
|
|
166
|
+
abort?(reason: any): void | PromiseLike<void>;
|
|
167
|
+
close?(): void | PromiseLike<void>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export class ConsumableWritableStream<T> extends WritableStream<Consumable<T>> {
|
|
171
|
+
public static async write<T>(
|
|
172
|
+
writer: WritableStreamDefaultWriter<Consumable<T>>,
|
|
173
|
+
value: T
|
|
174
|
+
) {
|
|
175
|
+
const consumable = new Consumable(value);
|
|
176
|
+
await writer.write(consumable);
|
|
177
|
+
await consumable.consumed;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public constructor(
|
|
181
|
+
sink: ConsumableWritableStreamSink<T>,
|
|
182
|
+
strategy?: QueuingStrategy<T>
|
|
183
|
+
) {
|
|
184
|
+
let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
|
|
185
|
+
if (strategy) {
|
|
186
|
+
wrappedStrategy = {};
|
|
187
|
+
if ("highWaterMark" in strategy) {
|
|
188
|
+
wrappedStrategy.highWaterMark = strategy.highWaterMark;
|
|
189
|
+
}
|
|
190
|
+
if ("size" in strategy) {
|
|
191
|
+
wrappedStrategy.size = (chunk) => {
|
|
192
|
+
return strategy.size!(chunk.value);
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
super(
|
|
198
|
+
{
|
|
199
|
+
start() {
|
|
200
|
+
return sink.start?.();
|
|
201
|
+
},
|
|
202
|
+
async write(chunk) {
|
|
203
|
+
await chunk.tryConsume((value) => sink.write?.(value));
|
|
204
|
+
chunk.consume();
|
|
205
|
+
},
|
|
206
|
+
abort(reason) {
|
|
207
|
+
return sink.abort?.(reason);
|
|
208
|
+
},
|
|
209
|
+
close() {
|
|
210
|
+
return sink.close?.();
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
wrappedStrategy
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export interface ConsumableTransformer<I, O> {
|
|
219
|
+
start?(
|
|
220
|
+
controller: ConsumableReadableStreamController<O>
|
|
221
|
+
): void | PromiseLike<void>;
|
|
222
|
+
transform?(
|
|
223
|
+
chunk: I,
|
|
224
|
+
controller: ConsumableReadableStreamController<O>
|
|
225
|
+
): void | PromiseLike<void>;
|
|
226
|
+
flush?(
|
|
227
|
+
controller: ConsumableReadableStreamController<O>
|
|
228
|
+
): void | PromiseLike<void>;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export class ConsumableTransformStream<I, O> extends TransformStream<
|
|
232
|
+
Consumable<I>,
|
|
233
|
+
Consumable<O>
|
|
234
|
+
> {
|
|
235
|
+
public constructor(transformer: ConsumableTransformer<I, O>) {
|
|
236
|
+
let wrappedController:
|
|
237
|
+
| ConsumableReadableStreamController<O>
|
|
238
|
+
| undefined;
|
|
239
|
+
|
|
240
|
+
super({
|
|
241
|
+
async start(controller) {
|
|
242
|
+
wrappedController = {
|
|
243
|
+
async enqueue(chunk) {
|
|
244
|
+
await enqueue(controller, chunk);
|
|
245
|
+
},
|
|
246
|
+
close() {
|
|
247
|
+
controller.terminate();
|
|
248
|
+
},
|
|
249
|
+
error(reason) {
|
|
250
|
+
controller.error(reason);
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
await transformer.start?.(wrappedController);
|
|
255
|
+
},
|
|
256
|
+
async transform(chunk) {
|
|
257
|
+
await chunk.tryConsume((value) =>
|
|
258
|
+
transformer.transform?.(value, wrappedController!)
|
|
259
|
+
);
|
|
260
|
+
chunk.consume();
|
|
261
|
+
},
|
|
262
|
+
async flush() {
|
|
263
|
+
await transformer.flush?.(wrappedController!);
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export class ConsumableInspectStream<T> extends TransformStream<
|
|
270
|
+
Consumable<T>,
|
|
271
|
+
Consumable<T>
|
|
272
|
+
> {
|
|
273
|
+
public constructor(callback: (value: T) => void) {
|
|
274
|
+
super({
|
|
275
|
+
transform(chunk, controller) {
|
|
276
|
+
callback(chunk.value);
|
|
277
|
+
controller.enqueue(chunk);
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { ConsumableTransformStream } from "./consumable.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Splits or combines buffers to specified size.
|
|
5
|
+
*/
|
|
6
|
+
export class BufferCombiner {
|
|
7
|
+
private _capacity: number;
|
|
8
|
+
private readonly _buffer: Uint8Array;
|
|
9
|
+
private _offset: number;
|
|
10
|
+
private _available: number;
|
|
11
|
+
|
|
12
|
+
public constructor(size: number) {
|
|
13
|
+
this._capacity = size;
|
|
14
|
+
this._buffer = new Uint8Array(size);
|
|
15
|
+
this._offset = 0;
|
|
16
|
+
this._available = size;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Pushes data to the combiner.
|
|
21
|
+
* @param data The input data to be split or combined.
|
|
22
|
+
* @returns
|
|
23
|
+
* A generator that yields buffers of specified size.
|
|
24
|
+
* It may yield the same buffer multiple times, consume the data before calling `next`.
|
|
25
|
+
*/
|
|
26
|
+
public *push(data: Uint8Array): Generator<Uint8Array, void, void> {
|
|
27
|
+
let offset = 0;
|
|
28
|
+
let available = data.byteLength;
|
|
29
|
+
|
|
30
|
+
if (this._offset !== 0) {
|
|
31
|
+
if (available >= this._available) {
|
|
32
|
+
this._buffer.set(
|
|
33
|
+
data.subarray(0, this._available),
|
|
34
|
+
this._offset
|
|
35
|
+
);
|
|
36
|
+
offset += this._available;
|
|
37
|
+
available -= this._available;
|
|
38
|
+
|
|
39
|
+
yield this._buffer;
|
|
40
|
+
this._offset = 0;
|
|
41
|
+
this._available = this._capacity;
|
|
42
|
+
|
|
43
|
+
if (available === 0) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
this._buffer.set(data, this._offset);
|
|
48
|
+
this._offset += available;
|
|
49
|
+
this._available -= available;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
while (available >= this._capacity) {
|
|
55
|
+
const end = offset + this._capacity;
|
|
56
|
+
yield data.subarray(offset, end);
|
|
57
|
+
offset = end;
|
|
58
|
+
available -= this._capacity;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (available > 0) {
|
|
62
|
+
this._buffer.set(data.subarray(offset), this._offset);
|
|
63
|
+
this._offset += available;
|
|
64
|
+
this._available -= available;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public flush(): Uint8Array | undefined {
|
|
69
|
+
if (this._offset === 0) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const output = this._buffer.subarray(0, this._offset);
|
|
74
|
+
this._offset = 0;
|
|
75
|
+
this._available = this._capacity;
|
|
76
|
+
return output;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export class DistributionStream extends ConsumableTransformStream<
|
|
81
|
+
Uint8Array,
|
|
82
|
+
Uint8Array
|
|
83
|
+
> {
|
|
84
|
+
public constructor(size: number, combine = false) {
|
|
85
|
+
const combiner = combine ? new BufferCombiner(size) : undefined;
|
|
86
|
+
super({
|
|
87
|
+
async transform(chunk, controller) {
|
|
88
|
+
if (combiner) {
|
|
89
|
+
for (const buffer of combiner.push(chunk)) {
|
|
90
|
+
await controller.enqueue(buffer);
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
let offset = 0;
|
|
94
|
+
let available = chunk.byteLength;
|
|
95
|
+
while (available > 0) {
|
|
96
|
+
const end = offset + size;
|
|
97
|
+
await controller.enqueue(chunk.subarray(offset, end));
|
|
98
|
+
offset = end;
|
|
99
|
+
available -= size;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
async flush(controller) {
|
|
104
|
+
if (combiner) {
|
|
105
|
+
const data = combiner.flush();
|
|
106
|
+
if (data) {
|
|
107
|
+
await controller.enqueue(data);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|