@yume-chan/stream-extra 0.0.19 → 0.0.21
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 +60 -33
- package/CHANGELOG.md +17 -1
- package/esm/buffered-transform.d.ts +1 -2
- package/esm/buffered-transform.d.ts.map +1 -1
- package/esm/buffered-transform.js +10 -9
- package/esm/buffered-transform.js.map +1 -1
- package/esm/buffered.d.ts +4 -11
- package/esm/buffered.d.ts.map +1 -1
- package/esm/buffered.js +40 -36
- package/esm/buffered.js.map +1 -1
- package/esm/concat.d.ts +35 -0
- package/esm/concat.d.ts.map +1 -0
- package/esm/concat.js +128 -0
- package/esm/concat.js.map +1 -0
- package/esm/consumable.d.ts +1 -2
- package/esm/consumable.d.ts.map +1 -1
- package/esm/consumable.js +9 -9
- package/esm/consumable.js.map +1 -1
- package/esm/distribution.d.ts +1 -4
- package/esm/distribution.d.ts.map +1 -1
- package/esm/distribution.js +29 -29
- package/esm/distribution.js.map +1 -1
- package/esm/duplex.d.ts +1 -5
- package/esm/duplex.d.ts.map +1 -1
- package/esm/duplex.js +21 -19
- package/esm/duplex.js.map +1 -1
- package/esm/index.d.ts +1 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -1
- package/esm/index.js.map +1 -1
- package/esm/push-readable.d.ts.map +1 -1
- package/esm/push-readable.js +11 -6
- package/esm/push-readable.js.map +1 -1
- package/esm/split-string.d.ts.map +1 -1
- package/esm/split-string.js.map +1 -1
- package/esm/stream.js +0 -14
- package/esm/stream.js.map +1 -1
- package/esm/struct-deserialize.d.ts.map +1 -1
- package/esm/struct-deserialize.js.map +1 -1
- package/esm/wrap-readable.d.ts +1 -1
- package/esm/wrap-readable.d.ts.map +1 -1
- package/esm/wrap-readable.js +4 -4
- package/esm/wrap-readable.js.map +1 -1
- package/esm/wrap-writable.d.ts +1 -1
- package/esm/wrap-writable.d.ts.map +1 -1
- package/esm/wrap-writable.js +5 -5
- package/esm/wrap-writable.js.map +1 -1
- package/package.json +8 -8
- package/src/buffered-transform.ts +14 -16
- package/src/buffered.ts +48 -42
- package/src/concat.ts +160 -0
- package/src/consumable.ts +38 -37
- package/src/decode-utf8.ts +1 -1
- package/src/distribution.ts +35 -35
- package/src/duplex.ts +28 -26
- package/src/index.ts +1 -1
- package/src/pipe-from.ts +1 -1
- package/src/push-readable.ts +15 -11
- package/src/split-string.ts +2 -2
- package/src/stream.ts +0 -13
- package/src/struct-deserialize.ts +2 -2
- package/src/struct-serialize.ts +1 -1
- package/src/wrap-readable.ts +10 -10
- package/src/wrap-writable.ts +10 -10
- package/tsconfig.build.json +6 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/chunk.d.ts +0 -8
- package/esm/chunk.d.ts.map +0 -1
- package/esm/chunk.js +0 -56
- package/esm/chunk.js.map +0 -1
- package/esm/gather-string.d.ts +0 -7
- package/esm/gather-string.d.ts.map +0 -1
- package/esm/gather-string.js +0 -16
- package/esm/gather-string.js.map +0 -1
- package/esm/trace.d.ts +0 -16
- package/esm/trace.d.ts.map +0 -1
- package/esm/trace.js +0 -131
- package/esm/trace.js.map +0 -1
- package/src/gather-string.ts +0 -17
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
2
|
+
import { StructEmptyError } from "@yume-chan/struct";
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
-
BufferedReadableStream,
|
|
5
|
-
BufferedReadableStreamEndedError,
|
|
6
|
-
} from "./buffered.js";
|
|
4
|
+
import { BufferedReadableStream } from "./buffered.js";
|
|
7
5
|
import type { PushReadableStreamController } from "./push-readable.js";
|
|
8
6
|
import { PushReadableStream } from "./push-readable.js";
|
|
9
7
|
import type { ReadableWritablePair } from "./stream.js";
|
|
@@ -13,18 +11,18 @@ import { ReadableStream, WritableStream } from "./stream.js";
|
|
|
13
11
|
export class BufferedTransformStream<T>
|
|
14
12
|
implements ReadableWritablePair<T, Uint8Array>
|
|
15
13
|
{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return this
|
|
14
|
+
#readable: ReadableStream<T>;
|
|
15
|
+
get readable() {
|
|
16
|
+
return this.#readable;
|
|
19
17
|
}
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return this
|
|
19
|
+
#writable: WritableStream<Uint8Array>;
|
|
20
|
+
get writable() {
|
|
21
|
+
return this.#writable;
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
constructor(
|
|
27
|
-
transform: (stream: BufferedReadableStream) => ValueOrPromise<T
|
|
25
|
+
transform: (stream: BufferedReadableStream) => ValueOrPromise<T>,
|
|
28
26
|
) {
|
|
29
27
|
// Convert incoming chunks to a `BufferedReadableStream`
|
|
30
28
|
let sourceStreamController!: PushReadableStreamController<Uint8Array>;
|
|
@@ -32,19 +30,19 @@ export class BufferedTransformStream<T>
|
|
|
32
30
|
const buffered = new BufferedReadableStream(
|
|
33
31
|
new PushReadableStream<Uint8Array>((controller) => {
|
|
34
32
|
sourceStreamController = controller;
|
|
35
|
-
})
|
|
33
|
+
}),
|
|
36
34
|
);
|
|
37
35
|
|
|
38
|
-
this
|
|
36
|
+
this.#readable = new ReadableStream<T>({
|
|
39
37
|
async pull(controller) {
|
|
40
38
|
try {
|
|
41
39
|
const value = await transform(buffered);
|
|
42
40
|
controller.enqueue(value);
|
|
43
41
|
} catch (e) {
|
|
44
|
-
// Treat `
|
|
42
|
+
// Treat `StructEmptyError` as a normal end.
|
|
45
43
|
// If the `transform` method doesn't have enough data to return a value,
|
|
46
44
|
// it should throw another error to indicate that.
|
|
47
|
-
if (e instanceof
|
|
45
|
+
if (e instanceof StructEmptyError) {
|
|
48
46
|
controller.close();
|
|
49
47
|
return;
|
|
50
48
|
}
|
|
@@ -58,7 +56,7 @@ export class BufferedTransformStream<T>
|
|
|
58
56
|
},
|
|
59
57
|
});
|
|
60
58
|
|
|
61
|
-
this
|
|
59
|
+
this.#writable = new WritableStream({
|
|
62
60
|
async write(chunk) {
|
|
63
61
|
await sourceStreamController.enqueue(chunk);
|
|
64
62
|
},
|
package/src/buffered.ts
CHANGED
|
@@ -1,43 +1,41 @@
|
|
|
1
|
+
import type { AsyncExactReadable } from "@yume-chan/struct";
|
|
2
|
+
import { ExactReadableEndedError } from "@yume-chan/struct";
|
|
3
|
+
|
|
1
4
|
import { PushReadableStream } from "./push-readable.js";
|
|
2
5
|
import type { ReadableStream, ReadableStreamDefaultReader } from "./stream.js";
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
const NOOP = () => {
|
|
8
|
+
// no-op
|
|
9
|
+
};
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
export class BufferedReadableStream implements AsyncExactReadable {
|
|
12
|
+
#buffered: Uint8Array | undefined;
|
|
13
|
+
#bufferedOffset = 0;
|
|
14
|
+
#bufferedLength = 0;
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
private bufferedLength = 0;
|
|
17
|
-
|
|
18
|
-
private _position = 0;
|
|
19
|
-
public get position() {
|
|
20
|
-
return this._position;
|
|
16
|
+
#position = 0;
|
|
17
|
+
get position() {
|
|
18
|
+
return this.#position;
|
|
21
19
|
}
|
|
22
20
|
|
|
23
21
|
protected readonly stream: ReadableStream<Uint8Array>;
|
|
24
22
|
protected readonly reader: ReadableStreamDefaultReader<Uint8Array>;
|
|
25
23
|
|
|
26
|
-
|
|
24
|
+
constructor(stream: ReadableStream<Uint8Array>) {
|
|
27
25
|
this.stream = stream;
|
|
28
26
|
this.reader = stream.getReader();
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
async #readSource() {
|
|
32
30
|
const { done, value } = await this.reader.read();
|
|
33
31
|
if (done) {
|
|
34
|
-
throw new
|
|
32
|
+
throw new ExactReadableEndedError();
|
|
35
33
|
}
|
|
36
|
-
this
|
|
34
|
+
this.#position += value.byteLength;
|
|
37
35
|
return value;
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
|
|
38
|
+
async #readAsync(length: number, initial?: Uint8Array) {
|
|
41
39
|
let result: Uint8Array;
|
|
42
40
|
let index: number;
|
|
43
41
|
|
|
@@ -47,15 +45,15 @@ export class BufferedReadableStream {
|
|
|
47
45
|
index = initial.byteLength;
|
|
48
46
|
length -= initial.byteLength;
|
|
49
47
|
} else {
|
|
50
|
-
const array = await this
|
|
48
|
+
const array = await this.#readSource();
|
|
51
49
|
if (array.byteLength === length) {
|
|
52
50
|
return array;
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
if (array.byteLength > length) {
|
|
56
|
-
this
|
|
57
|
-
this
|
|
58
|
-
this
|
|
54
|
+
this.#buffered = array;
|
|
55
|
+
this.#bufferedOffset = length;
|
|
56
|
+
this.#bufferedLength = array.byteLength - length;
|
|
59
57
|
return array.subarray(0, length);
|
|
60
58
|
}
|
|
61
59
|
|
|
@@ -66,16 +64,16 @@ export class BufferedReadableStream {
|
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
while (length > 0) {
|
|
69
|
-
const array = await this
|
|
67
|
+
const array = await this.#readSource();
|
|
70
68
|
if (array.byteLength === length) {
|
|
71
69
|
result.set(array, index);
|
|
72
70
|
return result;
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
if (array.byteLength > length) {
|
|
76
|
-
this
|
|
77
|
-
this
|
|
78
|
-
this
|
|
74
|
+
this.#buffered = array;
|
|
75
|
+
this.#bufferedOffset = length;
|
|
76
|
+
this.#bufferedLength = array.byteLength - length;
|
|
79
77
|
result.set(array.subarray(0, length), index);
|
|
80
78
|
return result;
|
|
81
79
|
}
|
|
@@ -93,24 +91,26 @@ export class BufferedReadableStream {
|
|
|
93
91
|
* @param length
|
|
94
92
|
* @returns
|
|
95
93
|
*/
|
|
96
|
-
|
|
94
|
+
readExactly(length: number): Uint8Array | Promise<Uint8Array> {
|
|
97
95
|
// PERF: Add a synchronous path for reading from internal buffer
|
|
98
|
-
if (this
|
|
99
|
-
const array = this
|
|
100
|
-
const offset = this
|
|
101
|
-
if (this
|
|
96
|
+
if (this.#buffered) {
|
|
97
|
+
const array = this.#buffered;
|
|
98
|
+
const offset = this.#bufferedOffset;
|
|
99
|
+
if (this.#bufferedLength > length) {
|
|
102
100
|
// PERF: `subarray` is slow
|
|
103
101
|
// don't use it until absolutely necessary
|
|
104
|
-
this
|
|
105
|
-
this
|
|
102
|
+
this.#bufferedOffset += length;
|
|
103
|
+
this.#bufferedLength -= length;
|
|
106
104
|
return array.subarray(offset, offset + length);
|
|
107
105
|
}
|
|
108
106
|
|
|
109
|
-
this
|
|
110
|
-
|
|
107
|
+
this.#buffered = undefined;
|
|
108
|
+
this.#bufferedLength = 0;
|
|
109
|
+
this.#bufferedOffset = 0;
|
|
110
|
+
return this.#readAsync(length, array.subarray(offset));
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
return this
|
|
113
|
+
return this.#readAsync(length);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
/**
|
|
@@ -118,11 +118,17 @@ export class BufferedReadableStream {
|
|
|
118
118
|
* all data from the wrapped stream.
|
|
119
119
|
* @returns A `ReadableStream`
|
|
120
120
|
*/
|
|
121
|
-
|
|
122
|
-
if (this
|
|
121
|
+
release(): ReadableStream<Uint8Array> {
|
|
122
|
+
if (this.#bufferedLength > 0) {
|
|
123
123
|
return new PushReadableStream<Uint8Array>(async (controller) => {
|
|
124
124
|
// Put the remaining data back to the stream
|
|
125
|
-
|
|
125
|
+
const buffered = this.#buffered!.subarray(this.#bufferedOffset);
|
|
126
|
+
await controller.enqueue(buffered);
|
|
127
|
+
|
|
128
|
+
controller.abortSignal.addEventListener("abort", () => {
|
|
129
|
+
// NOOP: the reader might already be released
|
|
130
|
+
this.reader.cancel().catch(NOOP);
|
|
131
|
+
});
|
|
126
132
|
|
|
127
133
|
// Manually pipe the stream
|
|
128
134
|
while (true) {
|
|
@@ -141,7 +147,7 @@ export class BufferedReadableStream {
|
|
|
141
147
|
}
|
|
142
148
|
}
|
|
143
149
|
|
|
144
|
-
|
|
150
|
+
cancel(reason?: unknown) {
|
|
145
151
|
return this.reader.cancel(reason);
|
|
146
152
|
}
|
|
147
153
|
}
|
package/src/concat.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { PromiseResolver } from "@yume-chan/async";
|
|
2
|
+
|
|
3
|
+
import type { ReadableStreamDefaultController } from "./stream.js";
|
|
4
|
+
import { ReadableStream, WritableStream } from "./stream.js";
|
|
5
|
+
|
|
6
|
+
export interface ConcatStringReadableStream
|
|
7
|
+
extends ReadableStream<string>,
|
|
8
|
+
Promise<string> {}
|
|
9
|
+
|
|
10
|
+
// `TransformStream` only calls its `source.flush` method when its `readable` is being read.
|
|
11
|
+
// If the user want to use the `Promise` interface, the `flush` method will never be called,
|
|
12
|
+
// so the `PromiseResolver` will never be resolved.
|
|
13
|
+
// Thus we need to implement our own `TransformStream` using a `WritableStream` and a `ReadableStream`.
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A `TransformStream` that concatenates strings.
|
|
17
|
+
*
|
|
18
|
+
* Its `readable` is also a `Promise<string>`, so it's possible to `await` it to get the result.
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* const result: string = await readable.pipeThrough(new ConcatStringStream());
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export class ConcatStringStream {
|
|
25
|
+
// PERF: rope (concat strings) is faster than `[].join('')`
|
|
26
|
+
#result = "";
|
|
27
|
+
|
|
28
|
+
#resolver = new PromiseResolver<string>();
|
|
29
|
+
|
|
30
|
+
#writable = new WritableStream<string>({
|
|
31
|
+
write: (chunk) => {
|
|
32
|
+
this.#result += chunk;
|
|
33
|
+
},
|
|
34
|
+
close: () => {
|
|
35
|
+
this.#resolver.resolve(this.#result);
|
|
36
|
+
this.#readableController.enqueue(this.#result);
|
|
37
|
+
this.#readableController.close();
|
|
38
|
+
},
|
|
39
|
+
abort: (reason) => {
|
|
40
|
+
this.#resolver.reject(reason);
|
|
41
|
+
this.#readableController.error(reason);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
get writable(): WritableStream<string> {
|
|
45
|
+
return this.#writable;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#readableController!: ReadableStreamDefaultController<string>;
|
|
49
|
+
#readable = new ReadableStream<string>({
|
|
50
|
+
start: (controller) => {
|
|
51
|
+
this.#readableController = controller;
|
|
52
|
+
},
|
|
53
|
+
}) as ConcatStringReadableStream;
|
|
54
|
+
get readable(): ConcatStringReadableStream {
|
|
55
|
+
return this.#readable;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
constructor() {
|
|
59
|
+
void Object.defineProperties(this.#readable, {
|
|
60
|
+
then: {
|
|
61
|
+
get: () =>
|
|
62
|
+
this.#resolver.promise.then.bind(this.#resolver.promise),
|
|
63
|
+
},
|
|
64
|
+
catch: {
|
|
65
|
+
get: () =>
|
|
66
|
+
this.#resolver.promise.catch.bind(this.#resolver.promise),
|
|
67
|
+
},
|
|
68
|
+
finally: {
|
|
69
|
+
get: () =>
|
|
70
|
+
this.#resolver.promise.finally.bind(this.#resolver.promise),
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface ConcatBufferReadableStream
|
|
77
|
+
extends ReadableStream<Uint8Array>,
|
|
78
|
+
Promise<Uint8Array> {}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* A `TransformStream` that concatenates `Uint8Array`s.
|
|
82
|
+
*
|
|
83
|
+
* If you want to decode the result as string,
|
|
84
|
+
* prefer `.pipeThrough(new DecodeUtf8Stream()).pipeThrough(new ConcatStringStream())`,
|
|
85
|
+
* than `.pipeThough(new ConcatBufferStream()).pipeThrough(new DecodeUtf8Stream())`,
|
|
86
|
+
* because concatenating strings is faster than concatenating `Uint8Array`s.
|
|
87
|
+
*/
|
|
88
|
+
export class ConcatBufferStream {
|
|
89
|
+
#segments: Uint8Array[] = [];
|
|
90
|
+
|
|
91
|
+
#resolver = new PromiseResolver<Uint8Array>();
|
|
92
|
+
|
|
93
|
+
#writable = new WritableStream<Uint8Array>({
|
|
94
|
+
write: (chunk) => {
|
|
95
|
+
this.#segments.push(chunk);
|
|
96
|
+
},
|
|
97
|
+
close: () => {
|
|
98
|
+
let result: Uint8Array;
|
|
99
|
+
let offset = 0;
|
|
100
|
+
switch (this.#segments.length) {
|
|
101
|
+
case 0:
|
|
102
|
+
result = new Uint8Array(0);
|
|
103
|
+
break;
|
|
104
|
+
case 1:
|
|
105
|
+
result = this.#segments[0]!;
|
|
106
|
+
break;
|
|
107
|
+
default:
|
|
108
|
+
result = new Uint8Array(
|
|
109
|
+
this.#segments.reduce(
|
|
110
|
+
(prev, item) => prev + item.length,
|
|
111
|
+
0,
|
|
112
|
+
),
|
|
113
|
+
);
|
|
114
|
+
for (const segment of this.#segments) {
|
|
115
|
+
result.set(segment, offset);
|
|
116
|
+
offset += segment.length;
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
this.#resolver.resolve(result);
|
|
122
|
+
this.#readableController.enqueue(result);
|
|
123
|
+
this.#readableController.close();
|
|
124
|
+
},
|
|
125
|
+
abort: (reason) => {
|
|
126
|
+
this.#resolver.reject(reason);
|
|
127
|
+
this.#readableController.error(reason);
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
get writable(): WritableStream<Uint8Array> {
|
|
131
|
+
return this.#writable;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
#readableController!: ReadableStreamDefaultController<Uint8Array>;
|
|
135
|
+
#readable = new ReadableStream<Uint8Array>({
|
|
136
|
+
start: (controller) => {
|
|
137
|
+
this.#readableController = controller;
|
|
138
|
+
},
|
|
139
|
+
}) as ConcatBufferReadableStream;
|
|
140
|
+
get readable(): ConcatBufferReadableStream {
|
|
141
|
+
return this.#readable;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
constructor() {
|
|
145
|
+
void Object.defineProperties(this.#readable, {
|
|
146
|
+
then: {
|
|
147
|
+
get: () =>
|
|
148
|
+
this.#resolver.promise.then.bind(this.#resolver.promise),
|
|
149
|
+
},
|
|
150
|
+
catch: {
|
|
151
|
+
get: () =>
|
|
152
|
+
this.#resolver.promise.catch.bind(this.#resolver.promise),
|
|
153
|
+
},
|
|
154
|
+
finally: {
|
|
155
|
+
get: () =>
|
|
156
|
+
this.#resolver.promise.finally.bind(this.#resolver.promise),
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
package/src/consumable.ts
CHANGED
|
@@ -11,12 +11,12 @@ interface Console {
|
|
|
11
11
|
createTask(name: string): Task;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
interface
|
|
14
|
+
interface GlobalExtension {
|
|
15
15
|
console: Console;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
// `createTask` allows browser DevTools to track the call stack across async boundaries.
|
|
19
|
-
const { console } = globalThis as unknown as
|
|
19
|
+
const { console } = globalThis as unknown as GlobalExtension;
|
|
20
20
|
const createTask: Console["createTask"] =
|
|
21
21
|
console.createTask?.bind(console) ??
|
|
22
22
|
(() => ({
|
|
@@ -26,35 +26,35 @@ const createTask: Console["createTask"] =
|
|
|
26
26
|
}));
|
|
27
27
|
|
|
28
28
|
export class Consumable<T> {
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
readonly #task: Task;
|
|
30
|
+
readonly #resolver: PromiseResolver<void>;
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
readonly value: T;
|
|
33
|
+
readonly consumed: Promise<void>;
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
this
|
|
35
|
+
constructor(value: T) {
|
|
36
|
+
this.#task = createTask("Consumable");
|
|
37
37
|
this.value = value;
|
|
38
|
-
this
|
|
39
|
-
this.consumed = this
|
|
38
|
+
this.#resolver = new PromiseResolver<void>();
|
|
39
|
+
this.consumed = this.#resolver.promise;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
this
|
|
42
|
+
consume() {
|
|
43
|
+
this.#resolver.resolve();
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
this
|
|
46
|
+
error(error: any) {
|
|
47
|
+
this.#resolver.reject(error);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
async tryConsume<U>(callback: (value: T) => U) {
|
|
51
51
|
try {
|
|
52
52
|
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
53
|
-
const result = await this
|
|
53
|
+
const result = await this.#task.run(() => callback(this.value));
|
|
54
54
|
this.consume();
|
|
55
55
|
return result;
|
|
56
56
|
} catch (e) {
|
|
57
|
-
this
|
|
57
|
+
this.#resolver.reject(e);
|
|
58
58
|
throw e;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -62,7 +62,7 @@ export class Consumable<T> {
|
|
|
62
62
|
|
|
63
63
|
async function enqueue<T>(
|
|
64
64
|
controller: { enqueue: (chunk: Consumable<T>) => void },
|
|
65
|
-
chunk: T
|
|
65
|
+
chunk: T,
|
|
66
66
|
) {
|
|
67
67
|
const output = new Consumable(chunk);
|
|
68
68
|
controller.enqueue(output);
|
|
@@ -70,7 +70,7 @@ async function enqueue<T>(
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
export class WrapConsumableStream<T> extends TransformStream<T, Consumable<T>> {
|
|
73
|
-
|
|
73
|
+
constructor() {
|
|
74
74
|
super({
|
|
75
75
|
async transform(chunk, controller) {
|
|
76
76
|
await enqueue(controller, chunk);
|
|
@@ -83,7 +83,7 @@ export class UnwrapConsumableStream<T> extends TransformStream<
|
|
|
83
83
|
Consumable<T>,
|
|
84
84
|
T
|
|
85
85
|
> {
|
|
86
|
-
|
|
86
|
+
constructor() {
|
|
87
87
|
super({
|
|
88
88
|
transform(chunk, controller) {
|
|
89
89
|
controller.enqueue(chunk.value);
|
|
@@ -101,18 +101,18 @@ export interface ConsumableReadableStreamController<T> {
|
|
|
101
101
|
|
|
102
102
|
export interface ConsumableReadableStreamSource<T> {
|
|
103
103
|
start?(
|
|
104
|
-
controller: ConsumableReadableStreamController<T
|
|
104
|
+
controller: ConsumableReadableStreamController<T>,
|
|
105
105
|
): void | PromiseLike<void>;
|
|
106
106
|
pull?(
|
|
107
|
-
controller: ConsumableReadableStreamController<T
|
|
107
|
+
controller: ConsumableReadableStreamController<T>,
|
|
108
108
|
): void | PromiseLike<void>;
|
|
109
109
|
cancel?(reason: any): void | PromiseLike<void>;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
export class ConsumableReadableStream<T> extends ReadableStream<Consumable<T>> {
|
|
113
|
-
|
|
113
|
+
constructor(
|
|
114
114
|
source: ConsumableReadableStreamSource<T>,
|
|
115
|
-
strategy?: QueuingStrategy<T
|
|
115
|
+
strategy?: QueuingStrategy<T>,
|
|
116
116
|
) {
|
|
117
117
|
let wrappedController:
|
|
118
118
|
| ConsumableReadableStreamController<T>
|
|
@@ -155,7 +155,7 @@ export class ConsumableReadableStream<T> extends ReadableStream<Consumable<T>> {
|
|
|
155
155
|
await source.cancel?.(reason);
|
|
156
156
|
},
|
|
157
157
|
},
|
|
158
|
-
wrappedStrategy
|
|
158
|
+
wrappedStrategy,
|
|
159
159
|
);
|
|
160
160
|
}
|
|
161
161
|
}
|
|
@@ -168,18 +168,18 @@ export interface ConsumableWritableStreamSink<T> {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
export class ConsumableWritableStream<T> extends WritableStream<Consumable<T>> {
|
|
171
|
-
|
|
171
|
+
static async write<T>(
|
|
172
172
|
writer: WritableStreamDefaultWriter<Consumable<T>>,
|
|
173
|
-
value: T
|
|
173
|
+
value: T,
|
|
174
174
|
) {
|
|
175
175
|
const consumable = new Consumable(value);
|
|
176
176
|
await writer.write(consumable);
|
|
177
177
|
await consumable.consumed;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
|
|
180
|
+
constructor(
|
|
181
181
|
sink: ConsumableWritableStreamSink<T>,
|
|
182
|
-
strategy?: QueuingStrategy<T
|
|
182
|
+
strategy?: QueuingStrategy<T>,
|
|
183
183
|
) {
|
|
184
184
|
let wrappedStrategy: QueuingStrategy<Consumable<T>> | undefined;
|
|
185
185
|
if (strategy) {
|
|
@@ -210,21 +210,21 @@ export class ConsumableWritableStream<T> extends WritableStream<Consumable<T>> {
|
|
|
210
210
|
return sink.close?.();
|
|
211
211
|
},
|
|
212
212
|
},
|
|
213
|
-
wrappedStrategy
|
|
213
|
+
wrappedStrategy,
|
|
214
214
|
);
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
export interface ConsumableTransformer<I, O> {
|
|
219
219
|
start?(
|
|
220
|
-
controller: ConsumableReadableStreamController<O
|
|
220
|
+
controller: ConsumableReadableStreamController<O>,
|
|
221
221
|
): void | PromiseLike<void>;
|
|
222
222
|
transform?(
|
|
223
223
|
chunk: I,
|
|
224
|
-
controller: ConsumableReadableStreamController<O
|
|
224
|
+
controller: ConsumableReadableStreamController<O>,
|
|
225
225
|
): void | PromiseLike<void>;
|
|
226
226
|
flush?(
|
|
227
|
-
controller: ConsumableReadableStreamController<O
|
|
227
|
+
controller: ConsumableReadableStreamController<O>,
|
|
228
228
|
): void | PromiseLike<void>;
|
|
229
229
|
}
|
|
230
230
|
|
|
@@ -232,7 +232,7 @@ export class ConsumableTransformStream<I, O> extends TransformStream<
|
|
|
232
232
|
Consumable<I>,
|
|
233
233
|
Consumable<O>
|
|
234
234
|
> {
|
|
235
|
-
|
|
235
|
+
constructor(transformer: ConsumableTransformer<I, O>) {
|
|
236
236
|
let wrappedController:
|
|
237
237
|
| ConsumableReadableStreamController<O>
|
|
238
238
|
| undefined;
|
|
@@ -254,8 +254,9 @@ export class ConsumableTransformStream<I, O> extends TransformStream<
|
|
|
254
254
|
await transformer.start?.(wrappedController);
|
|
255
255
|
},
|
|
256
256
|
async transform(chunk) {
|
|
257
|
-
await chunk.tryConsume(
|
|
258
|
-
|
|
257
|
+
await chunk.tryConsume(
|
|
258
|
+
(value) =>
|
|
259
|
+
transformer.transform?.(value, wrappedController!),
|
|
259
260
|
);
|
|
260
261
|
chunk.consume();
|
|
261
262
|
},
|
|
@@ -270,7 +271,7 @@ export class ConsumableInspectStream<T> extends TransformStream<
|
|
|
270
271
|
Consumable<T>,
|
|
271
272
|
Consumable<T>
|
|
272
273
|
> {
|
|
273
|
-
|
|
274
|
+
constructor(callback: (value: T) => void) {
|
|
274
275
|
super({
|
|
275
276
|
transform(chunk, controller) {
|
|
276
277
|
callback(chunk.value);
|
package/src/decode-utf8.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { decodeUtf8 } from "@yume-chan/struct";
|
|
|
3
3
|
import { TransformStream } from "./stream.js";
|
|
4
4
|
|
|
5
5
|
export class DecodeUtf8Stream extends TransformStream<Uint8Array, string> {
|
|
6
|
-
|
|
6
|
+
constructor() {
|
|
7
7
|
super({
|
|
8
8
|
transform(chunk, controller) {
|
|
9
9
|
controller.enqueue(decodeUtf8(chunk));
|