Skip to content

Commit 00931bd

Browse files
committed
stream: support typed arrays
1 parent a492646 commit 00931bd

File tree

5 files changed

+121
-11
lines changed

5 files changed

+121
-11
lines changed

lib/internal/streams/readable.js

+9-6
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const {
3636
SymbolAsyncIterator,
3737
SymbolSpecies,
3838
TypedArrayPrototypeSet,
39+
Uint8Array,
3940
} = primordials;
4041

4142
module.exports = Readable;
@@ -420,11 +421,12 @@ function readableAddChunkUnshiftByteMode(stream, state, chunk, encoding) {
420421
chunk = Buffer.from(chunk, encoding);
421422
}
422423
}
423-
} else if (Stream._isUint8Array(chunk)) {
424-
chunk = Stream._uint8ArrayToBuffer(chunk);
424+
} else if (Stream._isArrayBufferView(chunk)) {
425+
const array = new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);
426+
chunk = Stream._uint8ArrayToBuffer(array);
425427
} else if (chunk !== undefined && !(chunk instanceof Buffer)) {
426428
errorOrDestroy(stream, new ERR_INVALID_ARG_TYPE(
427-
'chunk', ['string', 'Buffer', 'Uint8Array'], chunk));
429+
'chunk', ['string', 'Buffer', 'TypedArray', 'BufferView'], chunk));
428430
return false;
429431
}
430432

@@ -473,12 +475,13 @@ function readableAddChunkPushByteMode(stream, state, chunk, encoding) {
473475
}
474476
} else if (chunk instanceof Buffer) {
475477
encoding = '';
476-
} else if (Stream._isUint8Array(chunk)) {
477-
chunk = Stream._uint8ArrayToBuffer(chunk);
478+
} else if (Stream._isArrayBufferView(chunk)) {
479+
const array = new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);
480+
chunk = Stream._uint8ArrayToBuffer(array);
478481
encoding = '';
479482
} else if (chunk !== undefined) {
480483
errorOrDestroy(stream, new ERR_INVALID_ARG_TYPE(
481-
'chunk', ['string', 'Buffer', 'Uint8Array'], chunk));
484+
'chunk', ['string', 'Buffer', 'TypedArray', 'BufferView'], chunk));
482485
return false;
483486
}
484487

lib/internal/streams/writable.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const {
3535
StringPrototypeToLowerCase,
3636
Symbol,
3737
SymbolHasInstance,
38+
Uint8Array,
3839
} = primordials;
3940

4041
module.exports = Writable;
@@ -467,12 +468,13 @@ function _write(stream, chunk, encoding, cb) {
467468
}
468469
} else if (chunk instanceof Buffer) {
469470
encoding = 'buffer';
470-
} else if (Stream._isUint8Array(chunk)) {
471-
chunk = Stream._uint8ArrayToBuffer(chunk);
471+
} else if (Stream._isArrayBufferView(chunk)) {
472+
const array = new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);
473+
chunk = Stream._uint8ArrayToBuffer(array);
472474
encoding = 'buffer';
473475
} else {
474476
throw new ERR_INVALID_ARG_TYPE(
475-
'chunk', ['string', 'Buffer', 'Uint8Array'], chunk);
477+
'chunk', ['string', 'Buffer', 'TypedArray', 'BufferView'], chunk);
476478
}
477479
}
478480

lib/stream.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ ObjectDefineProperty(eos, customPromisify, {
137137
// Backwards-compat with node 0.4.x
138138
Stream.Stream = Stream;
139139

140-
Stream._isUint8Array = require('internal/util/types').isUint8Array;
140+
Stream._isArrayBufferView = require('internal/util/types').isArrayBufferView;
141141
Stream._uint8ArrayToBuffer = function _uint8ArrayToBuffer(chunk) {
142142
return new internalBuffer.FastBuffer(chunk.buffer,
143143
chunk.byteOffset,

test/parallel/test-net-write-arguments.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ assert.throws(() => {
3434
code: 'ERR_INVALID_ARG_TYPE',
3535
name: 'TypeError',
3636
message: 'The "chunk" argument must be of type string or an instance of ' +
37-
`Buffer or Uint8Array.${common.invalidArgTypeHelper(value)}`
37+
`Buffer, TypedArray, or BufferView.${common.invalidArgTypeHelper(value)}`
3838
});
3939
});
+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
5+
const { Readable, Writable } = require('stream');
6+
7+
const buffer = Buffer.from('ABCD');
8+
const views = common.getArrayBufferViews(buffer);
9+
10+
{
11+
// Simple Writable test.
12+
let n = 0;
13+
const writable = new Writable({
14+
write: common.mustCall((chunk, encoding, cb) => {
15+
assert(chunk instanceof Buffer);
16+
assert(ArrayBuffer.isView(chunk));
17+
assert.deepStrictEqual(common.getBufferSources(chunk)[n], views[n]);
18+
n++;
19+
cb();
20+
}, views.length),
21+
});
22+
23+
views.forEach((msg) => writable.write(msg));
24+
writable.end();
25+
}
26+
27+
{
28+
// Writable test with object mode True.
29+
let n = 0;
30+
const writable = new Writable({
31+
objectMode: true,
32+
write: common.mustCall((chunk, encoding, cb) => {
33+
assert(!(chunk instanceof Buffer));
34+
assert(ArrayBuffer.isView(chunk));
35+
assert.deepStrictEqual(common.getBufferSources(chunk)[n], views[n]);
36+
n++;
37+
cb();
38+
}, views.length),
39+
});
40+
41+
views.forEach((msg) => writable.write(msg));
42+
writable.end();
43+
}
44+
45+
46+
{
47+
// Writable test, multiple writes carried out via writev.
48+
let n = 0;
49+
let callback;
50+
const writable = new Writable({
51+
write: common.mustCall((chunk, encoding, cb) => {
52+
assert(chunk instanceof Buffer);
53+
assert(ArrayBuffer.isView(chunk));
54+
assert.deepStrictEqual(common.getBufferSources(chunk)[n], views[n]);
55+
n++;
56+
callback = cb;
57+
}),
58+
59+
writev: common.mustCall((chunks, cb) => {
60+
assert.strictEqual(chunks.length, views.length);
61+
let res = '';
62+
for (const chunk of chunks) {
63+
assert.strictEqual(chunk.encoding, 'buffer');
64+
res += chunk.chunk;
65+
}
66+
assert.strictEqual(res, 'ABCD'.repeat(9));
67+
}),
68+
69+
});
70+
views.forEach((msg) => writable.write(msg));
71+
writable.end(views[0]);
72+
callback();
73+
}
74+
75+
76+
{
77+
// Simple Readable test.
78+
const readable = new Readable({
79+
read() {}
80+
});
81+
82+
readable.push(views[1]);
83+
readable.push(views[2]);
84+
readable.unshift(views[0]);
85+
86+
const buf = readable.read();
87+
assert(buf instanceof Buffer);
88+
assert.deepStrictEqual([...buf], [...views[0], ...views[1], ...views[2]]);
89+
}
90+
91+
{
92+
// Readable test, setEncoding.
93+
const readable = new Readable({
94+
read() {}
95+
});
96+
97+
readable.setEncoding('utf8');
98+
99+
readable.push(views[1]);
100+
readable.push(views[2]);
101+
readable.unshift(views[0]);
102+
103+
const out = readable.read();
104+
assert.strictEqual(out, 'ABCD'.repeat(3));
105+
}

0 commit comments

Comments
 (0)