@@ -23,6 +23,7 @@ const {
23
23
SymbolAsyncIterator,
24
24
SymbolDispose,
25
25
SymbolToStringTag,
26
+ TypedArrayPrototypeGetLength,
26
27
Uint8Array,
27
28
} = primordials ;
28
29
@@ -34,6 +35,7 @@ const {
34
35
ERR_INVALID_ARG_TYPE ,
35
36
ERR_INVALID_STATE ,
36
37
ERR_INVALID_THIS ,
38
+ ERR_OUT_OF_RANGE ,
37
39
} ,
38
40
} = require ( 'internal/errors' ) ;
39
41
@@ -59,8 +61,8 @@ const {
59
61
validateAbortSignal,
60
62
validateBuffer,
61
63
validateObject,
62
- kValidateObjectAllowNullable ,
63
- kValidateObjectAllowFunction ,
64
+ kValidateObjectAllowObjects ,
65
+ kValidateObjectAllowObjectsAndNull ,
64
66
} = require ( 'internal/validators' ) ;
65
67
66
68
const {
@@ -247,9 +249,9 @@ class ReadableStream {
247
249
* @param {UnderlyingSource } [source]
248
250
* @param {QueuingStrategy } [strategy]
249
251
*/
250
- constructor ( source = { } , strategy = kEmptyObject ) {
251
- if ( source === null )
252
- throw new ERR_INVALID_ARG_VALUE ( 'source' , 'Object ' , source ) ;
252
+ constructor ( source = kEmptyObject , strategy = kEmptyObject ) {
253
+ validateObject ( source , 'source' , kValidateObjectAllowObjects ) ;
254
+ validateObject ( strategy , 'strategy ' , kValidateObjectAllowObjectsAndNull ) ;
253
255
this [ kState ] = createReadableStreamState ( ) ;
254
256
255
257
this [ kIsClosedPromise ] = createDeferredPromise ( ) ;
@@ -335,7 +337,7 @@ class ReadableStream {
335
337
getReader ( options = kEmptyObject ) {
336
338
if ( ! isReadableStream ( this ) )
337
339
throw new ERR_INVALID_THIS ( 'ReadableStream' ) ;
338
- validateObject ( options , 'options' , kValidateObjectAllowNullable | kValidateObjectAllowFunction ) ;
340
+ validateObject ( options , 'options' , kValidateObjectAllowObjectsAndNull ) ;
339
341
const mode = options ?. mode ;
340
342
341
343
if ( mode === undefined )
@@ -373,6 +375,7 @@ class ReadableStream {
373
375
374
376
// The web platform tests require that these be handled one at a
375
377
// time and in a specific order. options can be null or undefined.
378
+ validateObject ( options , 'options' , kValidateObjectAllowObjectsAndNull ) ;
376
379
const preventAbort = options ?. preventAbort ;
377
380
const preventCancel = options ?. preventCancel ;
378
381
const preventClose = options ?. preventClose ;
@@ -415,6 +418,7 @@ class ReadableStream {
415
418
destination ) ;
416
419
}
417
420
421
+ validateObject ( options , 'options' , kValidateObjectAllowObjectsAndNull ) ;
418
422
const preventAbort = options ?. preventAbort ;
419
423
const preventCancel = options ?. preventCancel ;
420
424
const preventClose = options ?. preventClose ;
@@ -459,10 +463,8 @@ class ReadableStream {
459
463
values ( options = kEmptyObject ) {
460
464
if ( ! isReadableStream ( this ) )
461
465
throw new ERR_INVALID_THIS ( 'ReadableStream' ) ;
462
- validateObject ( options , 'options' ) ;
463
- const {
464
- preventCancel = false ,
465
- } = options ;
466
+ validateObject ( options , 'options' , kValidateObjectAllowObjectsAndNull ) ;
467
+ const preventCancel = ! ! ( options ?. preventCancel ) ;
466
468
467
469
// eslint-disable-next-line no-use-before-define
468
470
const reader = new ReadableStreamDefaultReader ( this ) ;
@@ -926,47 +928,62 @@ class ReadableStreamBYOBReader {
926
928
927
929
/**
928
930
* @param {ArrayBufferView } view
931
+ * @param {{
932
+ * min? : number
933
+ * }} [options]
929
934
* @returns {Promise<{
930
- * view : ArrayBufferView,
935
+ * value : ArrayBufferView,
931
936
* done : boolean,
932
937
* }>}
933
938
*/
934
- read ( view ) {
939
+ async read ( view , options = kEmptyObject ) {
935
940
if ( ! isReadableStreamBYOBReader ( this ) )
936
- return PromiseReject ( new ERR_INVALID_THIS ( 'ReadableStreamBYOBReader' ) ) ;
941
+ throw new ERR_INVALID_THIS ( 'ReadableStreamBYOBReader' ) ;
937
942
if ( ! isArrayBufferView ( view ) ) {
938
- return PromiseReject (
939
- new ERR_INVALID_ARG_TYPE (
940
- 'view' ,
941
- [
942
- 'Buffer ',
943
- 'TypedArray ',
944
- 'DataView' ,
945
- ] ,
946
- view ) ) ;
943
+ throw new ERR_INVALID_ARG_TYPE (
944
+ 'view' ,
945
+ [
946
+ 'Buffer' ,
947
+ 'TypedArray ',
948
+ 'DataView ',
949
+ ] ,
950
+ view ,
951
+ ) ;
947
952
}
953
+ validateObject ( options , 'options' , kValidateObjectAllowObjectsAndNull ) ;
948
954
949
955
const viewByteLength = ArrayBufferViewGetByteLength ( view ) ;
950
956
const viewBuffer = ArrayBufferViewGetBuffer ( view ) ;
951
957
const viewBufferByteLength = ArrayBufferPrototypeGetByteLength ( viewBuffer ) ;
952
958
953
959
if ( viewByteLength === 0 || viewBufferByteLength === 0 ) {
954
- return PromiseReject (
955
- new ERR_INVALID_STATE . TypeError (
956
- 'View or Viewed ArrayBuffer is zero-length or detached' ,
957
- ) ,
958
- ) ;
960
+ throw new ERR_INVALID_STATE . TypeError (
961
+ 'View or Viewed ArrayBuffer is zero-length or detached' ) ;
959
962
}
960
963
961
964
// Supposed to assert here that the view's buffer is not
962
965
// detached, but there's no API available to use to check that.
966
+
967
+ const min = options ?. min ?? 1 ;
968
+ if ( typeof min !== 'number' )
969
+ throw new ERR_INVALID_ARG_TYPE ( 'options.min' , 'number' , min ) ;
970
+ if ( ! NumberIsInteger ( min ) )
971
+ throw new ERR_INVALID_ARG_VALUE ( 'options.min' , min , 'must be an integer' ) ;
972
+ if ( min <= 0 )
973
+ throw new ERR_INVALID_ARG_VALUE ( 'options.min' , min , 'must be greater than 0' ) ;
974
+ if ( ! isDataView ( view ) ) {
975
+ if ( min > TypedArrayPrototypeGetLength ( view ) ) {
976
+ throw new ERR_OUT_OF_RANGE ( 'options.min' , '<= view.length' , min ) ;
977
+ }
978
+ } else if ( min > viewByteLength ) {
979
+ throw new ERR_OUT_OF_RANGE ( 'options.min' , '<= view.byteLength' , min ) ;
980
+ }
981
+
963
982
if ( this [ kState ] . stream === undefined ) {
964
- return PromiseReject (
965
- new ERR_INVALID_STATE . TypeError (
966
- 'The reader is not attached to a stream' ) ) ;
983
+ throw new ERR_INVALID_STATE . TypeError ( 'The reader is not attached to a stream' ) ;
967
984
}
968
985
const readIntoRequest = new ReadIntoRequest ( ) ;
969
- readableStreamBYOBReaderRead ( this , view , readIntoRequest ) ;
986
+ readableStreamBYOBReaderRead ( this , view , min , readIntoRequest ) ;
970
987
return readIntoRequest . promise ;
971
988
}
972
989
@@ -1880,7 +1897,7 @@ function readableByteStreamTee(stream) {
1880
1897
reading = false ;
1881
1898
} ,
1882
1899
} ;
1883
- readableStreamBYOBReaderRead ( reader , view , readIntoRequest ) ;
1900
+ readableStreamBYOBReaderRead ( reader , view , 1 , readIntoRequest ) ;
1884
1901
}
1885
1902
1886
1903
function pull1Algorithm ( ) {
@@ -2207,7 +2224,7 @@ function readableStreamReaderGenericRelease(reader) {
2207
2224
reader [ kState ] . stream = undefined ;
2208
2225
}
2209
2226
2210
- function readableStreamBYOBReaderRead ( reader , view , readIntoRequest ) {
2227
+ function readableStreamBYOBReaderRead ( reader , view , min , readIntoRequest ) {
2211
2228
const {
2212
2229
stream,
2213
2230
} = reader [ kState ] ;
@@ -2220,6 +2237,7 @@ function readableStreamBYOBReaderRead(reader, view, readIntoRequest) {
2220
2237
readableByteStreamControllerPullInto (
2221
2238
stream [ kState ] . controller ,
2222
2239
view ,
2240
+ min ,
2223
2241
readIntoRequest ) ;
2224
2242
}
2225
2243
@@ -2492,7 +2510,7 @@ function readableByteStreamControllerClose(controller) {
2492
2510
2493
2511
if ( pendingPullIntos . length ) {
2494
2512
const firstPendingPullInto = pendingPullIntos [ 0 ] ;
2495
- if ( firstPendingPullInto . bytesFilled > 0 ) {
2513
+ if ( firstPendingPullInto . bytesFilled % firstPendingPullInto . elementSize !== 0 ) {
2496
2514
const error = new ERR_INVALID_STATE . TypeError ( 'Partial read' ) ;
2497
2515
readableByteStreamControllerError ( controller , error ) ;
2498
2516
throw error ;
@@ -2509,7 +2527,7 @@ function readableByteStreamControllerCommitPullIntoDescriptor(stream, desc) {
2509
2527
2510
2528
let done = false ;
2511
2529
if ( stream [ kState ] . state === 'closed' ) {
2512
- desc . bytesFilled = 0 ;
2530
+ assert ( desc . bytesFilled % desc . elementSize === 0 ) ;
2513
2531
done = true ;
2514
2532
}
2515
2533
@@ -2598,6 +2616,7 @@ function readableByteStreamControllerHandleQueueDrain(controller) {
2598
2616
function readableByteStreamControllerPullInto (
2599
2617
controller ,
2600
2618
view ,
2619
+ min ,
2601
2620
readIntoRequest ) {
2602
2621
const {
2603
2622
closeRequested,
@@ -2610,6 +2629,11 @@ function readableByteStreamControllerPullInto(
2610
2629
elementSize = view . constructor . BYTES_PER_ELEMENT ;
2611
2630
ctor = view . constructor ;
2612
2631
}
2632
+
2633
+ const minimumFill = min * elementSize ;
2634
+ assert ( minimumFill >= elementSize && minimumFill <= view . byteLength ) ;
2635
+ assert ( minimumFill % elementSize === 0 ) ;
2636
+
2613
2637
const buffer = ArrayBufferViewGetBuffer ( view ) ;
2614
2638
const byteOffset = ArrayBufferViewGetByteOffset ( view ) ;
2615
2639
const byteLength = ArrayBufferViewGetByteLength ( view ) ;
@@ -2628,6 +2652,7 @@ function readableByteStreamControllerPullInto(
2628
2652
byteOffset,
2629
2653
byteLength,
2630
2654
bytesFilled : 0 ,
2655
+ minimumFill,
2631
2656
elementSize,
2632
2657
ctor,
2633
2658
type : 'byob' ,
@@ -2715,7 +2740,7 @@ function readableByteStreamControllerRespond(controller, bytesWritten) {
2715
2740
}
2716
2741
2717
2742
function readableByteStreamControllerRespondInClosedState ( controller , desc ) {
2718
- assert ( ! desc . bytesFilled ) ;
2743
+ assert ( desc . bytesFilled % desc . elementSize === 0 ) ;
2719
2744
if ( desc . type === 'none' ) {
2720
2745
readableByteStreamControllerShiftPendingPullInto ( controller ) ;
2721
2746
}
@@ -2892,17 +2917,18 @@ function readableByteStreamControllerFillPullIntoDescriptorFromQueue(
2892
2917
byteLength,
2893
2918
byteOffset,
2894
2919
bytesFilled,
2920
+ minimumFill,
2895
2921
elementSize,
2896
2922
} = desc ;
2897
- const currentAlignedBytes = bytesFilled - ( bytesFilled % elementSize ) ;
2898
2923
const maxBytesToCopy = MathMin (
2899
2924
controller [ kState ] . queueTotalSize ,
2900
2925
byteLength - bytesFilled ) ;
2901
2926
const maxBytesFilled = bytesFilled + maxBytesToCopy ;
2902
2927
const maxAlignedBytes = maxBytesFilled - ( maxBytesFilled % elementSize ) ;
2903
2928
let totalBytesToCopyRemaining = maxBytesToCopy ;
2904
2929
let ready = false ;
2905
- if ( maxAlignedBytes > currentAlignedBytes ) {
2930
+ assert ( bytesFilled < minimumFill ) ;
2931
+ if ( maxAlignedBytes >= minimumFill ) {
2906
2932
totalBytesToCopyRemaining = maxAlignedBytes - bytesFilled ;
2907
2933
ready = true ;
2908
2934
}
@@ -2945,7 +2971,7 @@ function readableByteStreamControllerFillPullIntoDescriptorFromQueue(
2945
2971
if ( ! ready ) {
2946
2972
assert ( ! controller [ kState ] . queueTotalSize ) ;
2947
2973
assert ( desc . bytesFilled > 0 ) ;
2948
- assert ( desc . bytesFilled < elementSize ) ;
2974
+ assert ( desc . bytesFilled < minimumFill ) ;
2949
2975
}
2950
2976
return ready ;
2951
2977
}
@@ -3001,7 +3027,7 @@ function readableByteStreamControllerRespondInReadableState(
3001
3027
return ;
3002
3028
}
3003
3029
3004
- if ( desc . bytesFilled < desc . elementSize )
3030
+ if ( desc . bytesFilled < desc . minimumFill )
3005
3031
return ;
3006
3032
3007
3033
readableByteStreamControllerShiftPendingPullInto ( controller ) ;
@@ -3186,6 +3212,7 @@ function readableByteStreamControllerPullSteps(controller, readRequest) {
3186
3212
byteOffset : 0 ,
3187
3213
byteLength : autoAllocateChunkSize ,
3188
3214
bytesFilled : 0 ,
3215
+ minimumFill : 1 ,
3189
3216
elementSize : 1 ,
3190
3217
ctor : Uint8Array ,
3191
3218
type : 'default' ,
0 commit comments