@@ -22,6 +22,7 @@ const {
22
22
SymbolAsyncIterator,
23
23
SymbolDispose,
24
24
SymbolToStringTag,
25
+ TypedArrayPrototypeGetLength,
25
26
Uint8Array,
26
27
} = primordials ;
27
28
@@ -33,6 +34,7 @@ const {
33
34
ERR_INVALID_ARG_TYPE ,
34
35
ERR_INVALID_STATE ,
35
36
ERR_INVALID_THIS ,
37
+ ERR_OUT_OF_RANGE ,
36
38
} ,
37
39
} = require ( 'internal/errors' ) ;
38
40
@@ -58,8 +60,8 @@ const {
58
60
validateAbortSignal,
59
61
validateBuffer,
60
62
validateObject,
61
- kValidateObjectAllowNullable ,
62
- kValidateObjectAllowFunction ,
63
+ kValidateObjectAllowObjects ,
64
+ kValidateObjectAllowObjectsAndNull ,
63
65
} = require ( 'internal/validators' ) ;
64
66
65
67
const {
@@ -246,10 +248,10 @@ class ReadableStream {
246
248
* @param {UnderlyingSource } [source]
247
249
* @param {QueuingStrategy } [strategy]
248
250
*/
249
- constructor ( source = { } , strategy = kEmptyObject ) {
251
+ constructor ( source = kEmptyObject , strategy = kEmptyObject ) {
250
252
markTransferMode ( this , false , true ) ;
251
- if ( source === null )
252
- throw new ERR_INVALID_ARG_VALUE ( 'source' , 'Object ' , source ) ;
253
+ validateObject ( source , 'source' , kValidateObjectAllowObjects ) ;
254
+ validateObject ( strategy , 'strategy ' , kValidateObjectAllowObjectsAndNull ) ;
253
255
this [ kState ] = createReadableStreamState ( ) ;
254
256
255
257
this [ kIsClosedPromise ] = createDeferredPromise ( ) ;
@@ -332,7 +334,7 @@ class ReadableStream {
332
334
getReader ( options = kEmptyObject ) {
333
335
if ( ! isReadableStream ( this ) )
334
336
throw new ERR_INVALID_THIS ( 'ReadableStream' ) ;
335
- validateObject ( options , 'options' , kValidateObjectAllowNullable | kValidateObjectAllowFunction ) ;
337
+ validateObject ( options , 'options' , kValidateObjectAllowObjectsAndNull ) ;
336
338
const mode = options ?. mode ;
337
339
338
340
if ( mode === undefined )
@@ -370,6 +372,7 @@ class ReadableStream {
370
372
371
373
// The web platform tests require that these be handled one at a
372
374
// time and in a specific order. options can be null or undefined.
375
+ validateObject ( options , 'options' , kValidateObjectAllowObjectsAndNull ) ;
373
376
const preventAbort = options ?. preventAbort ;
374
377
const preventCancel = options ?. preventCancel ;
375
378
const preventClose = options ?. preventClose ;
@@ -412,6 +415,7 @@ class ReadableStream {
412
415
destination ) ;
413
416
}
414
417
418
+ validateObject ( options , 'options' , kValidateObjectAllowObjectsAndNull ) ;
415
419
const preventAbort = options ?. preventAbort ;
416
420
const preventCancel = options ?. preventCancel ;
417
421
const preventClose = options ?. preventClose ;
@@ -456,10 +460,8 @@ class ReadableStream {
456
460
values ( options = kEmptyObject ) {
457
461
if ( ! isReadableStream ( this ) )
458
462
throw new ERR_INVALID_THIS ( 'ReadableStream' ) ;
459
- validateObject ( options , 'options' ) ;
460
- const {
461
- preventCancel = false ,
462
- } = options ;
463
+ validateObject ( options , 'options' , kValidateObjectAllowObjectsAndNull ) ;
464
+ const preventCancel = ! ! ( options ?. preventCancel ) ;
463
465
464
466
// eslint-disable-next-line no-use-before-define
465
467
const reader = new ReadableStreamDefaultReader ( this ) ;
@@ -929,47 +931,62 @@ class ReadableStreamBYOBReader {
929
931
930
932
/**
931
933
* @param {ArrayBufferView } view
934
+ * @param {{
935
+ * min? : number
936
+ * }} [options]
932
937
* @returns {Promise<{
933
- * view : ArrayBufferView,
938
+ * value : ArrayBufferView,
934
939
* done : boolean,
935
940
* }>}
936
941
*/
937
- read ( view ) {
942
+ async read ( view , options = kEmptyObject ) {
938
943
if ( ! isReadableStreamBYOBReader ( this ) )
939
- return PromiseReject ( new ERR_INVALID_THIS ( 'ReadableStreamBYOBReader' ) ) ;
944
+ throw new ERR_INVALID_THIS ( 'ReadableStreamBYOBReader' ) ;
940
945
if ( ! isArrayBufferView ( view ) ) {
941
- return PromiseReject (
942
- new ERR_INVALID_ARG_TYPE (
943
- 'view' ,
944
- [
945
- 'Buffer ',
946
- 'TypedArray ',
947
- 'DataView' ,
948
- ] ,
949
- view ) ) ;
946
+ throw new ERR_INVALID_ARG_TYPE (
947
+ 'view' ,
948
+ [
949
+ 'Buffer' ,
950
+ 'TypedArray ',
951
+ 'DataView ',
952
+ ] ,
953
+ view ,
954
+ ) ;
950
955
}
956
+ validateObject ( options , 'options' , kValidateObjectAllowObjectsAndNull ) ;
951
957
952
958
const viewByteLength = ArrayBufferViewGetByteLength ( view ) ;
953
959
const viewBuffer = ArrayBufferViewGetBuffer ( view ) ;
954
960
const viewBufferByteLength = ArrayBufferPrototypeGetByteLength ( viewBuffer ) ;
955
961
956
962
if ( viewByteLength === 0 || viewBufferByteLength === 0 ) {
957
- return PromiseReject (
958
- new ERR_INVALID_STATE . TypeError (
959
- 'View or Viewed ArrayBuffer is zero-length or detached' ,
960
- ) ,
961
- ) ;
963
+ throw new ERR_INVALID_STATE . TypeError (
964
+ 'View or Viewed ArrayBuffer is zero-length or detached' ) ;
962
965
}
963
966
964
967
// Supposed to assert here that the view's buffer is not
965
968
// detached, but there's no API available to use to check that.
969
+
970
+ const min = options ?. min ?? 1 ;
971
+ if ( typeof min !== 'number' )
972
+ throw new ERR_INVALID_ARG_TYPE ( 'options.min' , 'number' , min ) ;
973
+ if ( ! NumberIsInteger ( min ) )
974
+ throw new ERR_INVALID_ARG_VALUE ( 'options.min' , min , 'must be an integer' ) ;
975
+ if ( min <= 0 )
976
+ throw new ERR_INVALID_ARG_VALUE ( 'options.min' , min , 'must be greater than 0' ) ;
977
+ if ( ! isDataView ( view ) ) {
978
+ if ( min > TypedArrayPrototypeGetLength ( view ) ) {
979
+ throw new ERR_OUT_OF_RANGE ( 'options.min' , '<= view.length' , min ) ;
980
+ }
981
+ } else if ( min > viewByteLength ) {
982
+ throw new ERR_OUT_OF_RANGE ( 'options.min' , '<= view.byteLength' , min ) ;
983
+ }
984
+
966
985
if ( this [ kState ] . stream === undefined ) {
967
- return PromiseReject (
968
- new ERR_INVALID_STATE . TypeError (
969
- 'The reader is not attached to a stream' ) ) ;
986
+ throw new ERR_INVALID_STATE . TypeError ( 'The reader is not attached to a stream' ) ;
970
987
}
971
988
const readIntoRequest = new ReadIntoRequest ( ) ;
972
- readableStreamBYOBReaderRead ( this , view , readIntoRequest ) ;
989
+ readableStreamBYOBReaderRead ( this , view , min , readIntoRequest ) ;
973
990
return readIntoRequest . promise ;
974
991
}
975
992
@@ -1883,7 +1900,7 @@ function readableByteStreamTee(stream) {
1883
1900
reading = false ;
1884
1901
} ,
1885
1902
} ;
1886
- readableStreamBYOBReaderRead ( reader , view , readIntoRequest ) ;
1903
+ readableStreamBYOBReaderRead ( reader , view , 1 , readIntoRequest ) ;
1887
1904
}
1888
1905
1889
1906
function pull1Algorithm ( ) {
@@ -2210,7 +2227,7 @@ function readableStreamReaderGenericRelease(reader) {
2210
2227
reader [ kState ] . stream = undefined ;
2211
2228
}
2212
2229
2213
- function readableStreamBYOBReaderRead ( reader , view , readIntoRequest ) {
2230
+ function readableStreamBYOBReaderRead ( reader , view , min , readIntoRequest ) {
2214
2231
const {
2215
2232
stream,
2216
2233
} = reader [ kState ] ;
@@ -2223,6 +2240,7 @@ function readableStreamBYOBReaderRead(reader, view, readIntoRequest) {
2223
2240
readableByteStreamControllerPullInto (
2224
2241
stream [ kState ] . controller ,
2225
2242
view ,
2243
+ min ,
2226
2244
readIntoRequest ) ;
2227
2245
}
2228
2246
@@ -2495,7 +2513,7 @@ function readableByteStreamControllerClose(controller) {
2495
2513
2496
2514
if ( pendingPullIntos . length ) {
2497
2515
const firstPendingPullInto = pendingPullIntos [ 0 ] ;
2498
- if ( firstPendingPullInto . bytesFilled > 0 ) {
2516
+ if ( firstPendingPullInto . bytesFilled % firstPendingPullInto . elementSize !== 0 ) {
2499
2517
const error = new ERR_INVALID_STATE . TypeError ( 'Partial read' ) ;
2500
2518
readableByteStreamControllerError ( controller , error ) ;
2501
2519
throw error ;
@@ -2512,7 +2530,7 @@ function readableByteStreamControllerCommitPullIntoDescriptor(stream, desc) {
2512
2530
2513
2531
let done = false ;
2514
2532
if ( stream [ kState ] . state === 'closed' ) {
2515
- desc . bytesFilled = 0 ;
2533
+ assert ( desc . bytesFilled % desc . elementSize === 0 ) ;
2516
2534
done = true ;
2517
2535
}
2518
2536
@@ -2601,6 +2619,7 @@ function readableByteStreamControllerHandleQueueDrain(controller) {
2601
2619
function readableByteStreamControllerPullInto (
2602
2620
controller ,
2603
2621
view ,
2622
+ min ,
2604
2623
readIntoRequest ) {
2605
2624
const {
2606
2625
closeRequested,
@@ -2613,6 +2632,11 @@ function readableByteStreamControllerPullInto(
2613
2632
elementSize = view . constructor . BYTES_PER_ELEMENT ;
2614
2633
ctor = view . constructor ;
2615
2634
}
2635
+
2636
+ const minimumFill = min * elementSize ;
2637
+ assert ( minimumFill >= elementSize && minimumFill <= view . byteLength ) ;
2638
+ assert ( minimumFill % elementSize === 0 ) ;
2639
+
2616
2640
const buffer = ArrayBufferViewGetBuffer ( view ) ;
2617
2641
const byteOffset = ArrayBufferViewGetByteOffset ( view ) ;
2618
2642
const byteLength = ArrayBufferViewGetByteLength ( view ) ;
@@ -2631,6 +2655,7 @@ function readableByteStreamControllerPullInto(
2631
2655
byteOffset,
2632
2656
byteLength,
2633
2657
bytesFilled : 0 ,
2658
+ minimumFill,
2634
2659
elementSize,
2635
2660
ctor,
2636
2661
type : 'byob' ,
@@ -2718,7 +2743,7 @@ function readableByteStreamControllerRespond(controller, bytesWritten) {
2718
2743
}
2719
2744
2720
2745
function readableByteStreamControllerRespondInClosedState ( controller , desc ) {
2721
- assert ( ! desc . bytesFilled ) ;
2746
+ assert ( desc . bytesFilled % desc . elementSize === 0 ) ;
2722
2747
if ( desc . type === 'none' ) {
2723
2748
readableByteStreamControllerShiftPendingPullInto ( controller ) ;
2724
2749
}
@@ -2895,17 +2920,18 @@ function readableByteStreamControllerFillPullIntoDescriptorFromQueue(
2895
2920
byteLength,
2896
2921
byteOffset,
2897
2922
bytesFilled,
2923
+ minimumFill,
2898
2924
elementSize,
2899
2925
} = desc ;
2900
- const currentAlignedBytes = bytesFilled - ( bytesFilled % elementSize ) ;
2901
2926
const maxBytesToCopy = MathMin (
2902
2927
controller [ kState ] . queueTotalSize ,
2903
2928
byteLength - bytesFilled ) ;
2904
2929
const maxBytesFilled = bytesFilled + maxBytesToCopy ;
2905
2930
const maxAlignedBytes = maxBytesFilled - ( maxBytesFilled % elementSize ) ;
2906
2931
let totalBytesToCopyRemaining = maxBytesToCopy ;
2907
2932
let ready = false ;
2908
- if ( maxAlignedBytes > currentAlignedBytes ) {
2933
+ assert ( bytesFilled < minimumFill ) ;
2934
+ if ( maxAlignedBytes >= minimumFill ) {
2909
2935
totalBytesToCopyRemaining = maxAlignedBytes - bytesFilled ;
2910
2936
ready = true ;
2911
2937
}
@@ -2948,7 +2974,7 @@ function readableByteStreamControllerFillPullIntoDescriptorFromQueue(
2948
2974
if ( ! ready ) {
2949
2975
assert ( ! controller [ kState ] . queueTotalSize ) ;
2950
2976
assert ( desc . bytesFilled > 0 ) ;
2951
- assert ( desc . bytesFilled < elementSize ) ;
2977
+ assert ( desc . bytesFilled < minimumFill ) ;
2952
2978
}
2953
2979
return ready ;
2954
2980
}
@@ -3004,7 +3030,7 @@ function readableByteStreamControllerRespondInReadableState(
3004
3030
return ;
3005
3031
}
3006
3032
3007
- if ( desc . bytesFilled < desc . elementSize )
3033
+ if ( desc . bytesFilled < desc . minimumFill )
3008
3034
return ;
3009
3035
3010
3036
readableByteStreamControllerShiftPendingPullInto ( controller ) ;
@@ -3189,6 +3215,7 @@ function readableByteStreamControllerPullSteps(controller, readRequest) {
3189
3215
byteOffset : 0 ,
3190
3216
byteLength : autoAllocateChunkSize ,
3191
3217
bytesFilled : 0 ,
3218
+ minimumFill : 1 ,
3192
3219
elementSize : 1 ,
3193
3220
ctor : Uint8Array ,
3194
3221
type : 'default' ,
0 commit comments