@@ -19,6 +19,7 @@ spec:infra; type:dfn; text:list
19
19
spec:html; type:dfn; text:entangle
20
20
spec:html; type:dfn; text:message port post message steps
21
21
spec:html; type:dfn; text:port message queue
22
+ spec:html; type:dfn; text:transferable objects
22
23
</pre>
23
24
24
25
<pre class="anchors">
@@ -571,7 +572,7 @@ callback UnderlyingSourceStartCallback = any (ReadableStreamController controlle
571
572
callback UnderlyingSourcePullCallback = Promise<undefined> (ReadableStreamController controller);
572
573
callback UnderlyingSourceCancelCallback = Promise<undefined> (optional any reason);
573
574
574
- enum ReadableStreamType { "bytes" };
575
+ enum ReadableStreamType { "bytes", "transfer" };
575
576
</xmp>
576
577
577
578
<dl>
@@ -639,8 +640,7 @@ enum ReadableStreamType { "bytes" };
639
640
something more persistently wrong.
640
641
</div>
641
642
642
- <dt> <dfn dict-member for="UnderlyingSource" lt="type"><code>type</code></dfn> (byte streams
643
- only)</dt>
643
+ <dt> <dfn dict-member for="UnderlyingSource" lt="type"><code>type</code></dfn> </dt>
644
644
<dd>
645
645
<p> Can be set to "<dfn enum-value for="ReadableStreamType">bytes</dfn> " to signal that the
646
646
constructed {{ReadableStream}} is a <a>readable byte stream</a> . This ensures that the resulting
@@ -651,6 +651,14 @@ enum ReadableStreamType { "bytes" };
651
651
<p> For an example of how to set up a readable byte stream, including using the different
652
652
controller interface, see [[#example-rbs-push]] .
653
653
654
+ <p> Can be set to "<dfn enum-value for="ReadableStreamType">transfer</dfn> " to signal that the
655
+ constructed {{ReadableStream}} will transfer or serialize chunks before enqueuing them.
656
+ This ensures that enqueued chunks are not mutable by the source.
657
+ Transferred or serialized chunks may have <dfn>closing steps</dfn> which are executed if
658
+ enqueued chunks are dequeued without being provided to the application, for instance when
659
+ a {{ReadableStream}} is errored.
660
+ </p>
661
+
654
662
<p> Setting any value other than "{{ReadableStreamType/bytes}} " or undefined will cause the
655
663
{{ReadableStream()}} constructor to throw an exception.
656
664
@@ -801,7 +809,8 @@ option. If {{UnderlyingSource/type}} is set to undefined (including via omission
801
809
1. Perform ? [$SetUpReadableByteStreamControllerFromUnderlyingSource$] ([=this=] ,
802
810
|underlyingSource|, |underlyingSourceDict|, |highWaterMark|).
803
811
1. Otherwise,
804
- 1. Assert: |underlyingSourceDict|["{{UnderlyingSource/type}}"] does not [=map/exist=] .
812
+ 1. Assert: |underlyingSourceDict|["{{UnderlyingSource/type}}"] does not [=map/exist=] or
813
+ is "{{ReadableStreamType/transfer}} ".
805
814
1. Let |sizeAlgorithm| be ! [$ExtractSizeAlgorithm$] (|strategy|).
806
815
1. Let |highWaterMark| be ? [$ExtractHighWaterMark$] (|strategy|, 1).
807
816
1. Perform ? [$SetUpReadableStreamDefaultControllerFromUnderlyingSource$] ([=this=] ,
@@ -1523,6 +1532,9 @@ the following table:
1523
1532
<tr>
1524
1533
<td> <dfn>\[[stream]]</dfn>
1525
1534
<td class="non-normative"> The {{ReadableStream}} instance controlled
1535
+ <tr>
1536
+ <td> <dfn>\[[isTransferring]]</dfn>
1537
+ <td class="non-normative"> A boolean flag indicating whether to transfer enqueued chunks
1526
1538
</table>
1527
1539
1528
1540
<h4 id="rs-default-controller-prototype">Methods and properties</h4>
@@ -2235,8 +2247,8 @@ create them does not matter.
2235
2247
objects|transferring=] their [=chunks=] . However, it does introduce a noticeable asymmetry between
2236
2248
the two branches, and limits the possible [=chunks=] to serializable ones. [[!HTML]]
2237
2249
2238
- If |stream| is a [=readable byte stream=] , then |cloneForBranch2| is ignored and chunks are cloned
2239
- unconditionally.
2250
+ If |stream| is a [=readable byte stream=] , or if |stream| type is " {{ReadableStreamType/transfer}} ",
2251
+ then |cloneForBranch2| is ignored and chunks are cloned unconditionally.
2240
2252
2241
2253
<p class="note"> In this standard ReadableStreamTee is always called with |cloneForBranch2| set to
2242
2254
false; other specifications pass true via the [=ReadableStream/tee=] wrapper algorithm.
@@ -2247,6 +2259,8 @@ create them does not matter.
2247
2259
1. Assert: |cloneForBranch2| is a boolean.
2248
2260
1. If |stream|.[=ReadableStream/[[controller]]=] [=implements=] {{ReadableByteStreamController}} ,
2249
2261
return ? [$ReadableByteStreamTee$] (|stream|).
2262
+ 1. If |stream|.[=ReadableStream/[[controller]]=] .[=ReadableStreamDefaultController/[[isTransferring]]=]
2263
+ is true, return ? [$ReadableStreamDefaultTee$] (|stream|, true).
2250
2264
1. Return ? [$ReadableStreamDefaultTee$] (|stream|, |cloneForBranch2|).
2251
2265
</div>
2252
2266
@@ -2955,8 +2969,12 @@ The following abstract operations support the implementation of the
2955
2969
1. If ! [$ReadableStreamDefaultControllerCanCloseOrEnqueue$] (|controller|) is false, return.
2956
2970
1. Let |stream| be |controller|.[=ReadableStreamDefaultController/[[stream]]=] .
2957
2971
1. If ! [$IsReadableStreamLocked$] (|stream|) is true and !
2958
- [$ReadableStreamGetNumReadRequests$] (|stream|) > 0, perform !
2959
- [$ReadableStreamFulfillReadRequest$] (|stream|, |chunk|, false).
2972
+ [$ReadableStreamGetNumReadRequests$] (|stream|) > 0, perform the following steps:
2973
+ 1. Let |internalChunk| be |chunk|.
2974
+ 1. If |controller|.[=ReadableStreamDefaultController/[[isTransferring]]=] is true, perform the following steps:
2975
+ 1. Set |internalChunk| to [$StructuredTransferOrSerialize$] (|chunk|).
2976
+ 1. If |internalChunk| is an abrupt completion, return.
2977
+ 1. ![$ReadableStreamFulfillReadRequest$] (|stream|, |internalChunk|, false).
2960
2978
1. Otherwise,
2961
2979
1. Let |result| be the result of performing
2962
2980
|controller|.[=ReadableStreamDefaultController/[[strategySizeAlgorithm]]=] , passing in |chunk|,
@@ -3029,7 +3047,7 @@ The following abstract operations support the implementation of the
3029
3047
<dfn abstract-op lt="SetUpReadableStreamDefaultController"
3030
3048
id="set-up-readable-stream-default-controller"> SetUpReadableStreamDefaultController(|stream|,
3031
3049
|controller|, |startAlgorithm|, |pullAlgorithm|, |cancelAlgorithm|, |highWaterMark|,
3032
- |sizeAlgorithm|)</dfn> performs the following steps:
3050
+ |sizeAlgorithm|, |isTransferring| )</dfn> performs the following steps:
3033
3051
3034
3052
1. Assert: |stream|.[=ReadableStream/[[controller]]=] is undefined.
3035
3053
1. Set |controller|.[=ReadableStreamDefaultController/[[stream]]=] to |stream|.
@@ -3039,8 +3057,9 @@ The following abstract operations support the implementation of the
3039
3057
|controller|.[=ReadableStreamDefaultController/[[pullAgain]]=] , and
3040
3058
|controller|.[=ReadableStreamDefaultController/[[pulling]]=] to false.
3041
3059
1. Set |controller|.[=ReadableStreamDefaultController/[[strategySizeAlgorithm]]=] to
3042
- |sizeAlgorithm| and |controller|.[=ReadableStreamDefaultController/[[strategyHWM]]=] to
3043
- |highWaterMark|.
3060
+ |sizeAlgorithm|, |controller|.[=ReadableStreamDefaultController/[[strategyHWM]]=] to
3061
+ |highWaterMark| and |controller|.[=ReadableStreamDefaultController/[[isTransferring]]=] to
3062
+ |isTransferring|.
3044
3063
1. Set |controller|.[=ReadableStreamDefaultController/[[pullAlgorithm]]=] to |pullAlgorithm|.
3045
3064
1. Set |controller|.[=ReadableStreamDefaultController/[[cancelAlgorithm]]=] to |cancelAlgorithm|.
3046
3065
1. Set |stream|.[=ReadableStream/[[controller]]=] to |controller|.
@@ -3065,6 +3084,9 @@ The following abstract operations support the implementation of the
3065
3084
1. Let |startAlgorithm| be an algorithm that returns undefined.
3066
3085
1. Let |pullAlgorithm| be an algorithm that returns [=a promise resolved with=] undefined.
3067
3086
1. Let |cancelAlgorithm| be an algorithm that returns [=a promise resolved with=] undefined.
3087
+ 1. Let |cancelAlgorithm| be an algorithm that returns [=a promise resolved with=] undefined.
3088
+ 1. Let |isTransferring| be true if |underlyingSourceDict|["{{UnderlyingSource/pull}}"] is
3089
+ "{{ReadableStreamType/transfer}} " and false otherwise.
3068
3090
1. If |underlyingSourceDict|["{{UnderlyingSource/start}}"] [=map/exists=] , then set
3069
3091
|startAlgorithm| to an algorithm which returns the result of [=invoking=]
3070
3092
|underlyingSourceDict|["{{UnderlyingSource/start}}"] with argument list
@@ -3078,7 +3100,7 @@ The following abstract operations support the implementation of the
3078
3100
[=invoking=] |underlyingSourceDict|["{{UnderlyingSource/cancel}}"] with argument list
3079
3101
« |reason| » and [=callback this value=] |underlyingSource|.
3080
3102
1. Perform ? [$SetUpReadableStreamDefaultController$] (|stream|, |controller|, |startAlgorithm|,
3081
- |pullAlgorithm|, |cancelAlgorithm|, |highWaterMark|, |sizeAlgorithm|).
3103
+ |pullAlgorithm|, |cancelAlgorithm|, |highWaterMark|, |sizeAlgorithm|, |isTransferring| ).
3082
3104
</div>
3083
3105
3084
3106
<h4 id="rbs-controller-abstract-ops">Byte stream controllers</h4>
@@ -6346,8 +6368,8 @@ In what follows, a <dfn>value-with-size</dfn> is a [=struct=] with the two [=str
6346
6368
for="value-with-size"> value</dfn> and <dfn for="value-with-size">size</dfn> .
6347
6369
6348
6370
<div algorithm>
6349
- <dfn abstract-op lt="DequeueValue" id="dequeue-value">DequeueValue(|container|)</dfn> performs the
6350
- following steps:
6371
+ <dfn abstract-op lt="DequeueValue" id="dequeue-value">DequeueValue(|container|)</dfn> performs
6372
+ the following steps:
6351
6373
6352
6374
1. Assert: |container| has \[[queue]] and \[[queueTotalSize]] internal slots.
6353
6375
1. Assert: |container|.\[[queue]] is not [=list/is empty|empty=] .
@@ -6368,7 +6390,11 @@ for="value-with-size">value</dfn> and <dfn for="value-with-size">size</dfn>.
6368
6390
1. Assert: |container| has \[[queue]] and \[[queueTotalSize]] internal slots.
6369
6391
1. If ! [$IsNonNegativeNumber$] (|size|) is false, throw a {{RangeError}} exception.
6370
6392
1. If |size| is +∞, throw a {{RangeError}} exception.
6371
- 1. [=list/Append=] a new [=value-with-size=] with [=value-with-size/value=] |value| and
6393
+ 1. Let |enqueuedValue| be |value|.
6394
+ 1. If |container|.\[[isTransferring]] is true, perform the following steps:
6395
+ 1. Set |enqueuedValue| to [$StructuredTransferOrSerialize$] (|value|).
6396
+ 1. If |enqueuedValue| is an abrupt completion, return.
6397
+ 1. [=list/Append=] a new [=value-with-size=] with [=value-with-size/value=] |enqueuedValue| and
6372
6398
[=value-with-size/size=] |size| to |container|.\[[queue]] .
6373
6399
1. Set |container|.\[[queueTotalSize]] to |container|.\[[queueTotalSize]] + |size|.
6374
6400
</div>
@@ -6388,6 +6414,10 @@ for="value-with-size">value</dfn> and <dfn for="value-with-size">size</dfn>.
6388
6414
performs the following steps:
6389
6415
6390
6416
1. Assert: |container| has \[[queue]] and \[[queueTotalSize]] internal slots.
6417
+ 1. If |container|.\[[isTransferring]] is true, perform the following steps until |container|.\[[queue]]
6418
+ is [=list/is empty|empty=] :
6419
+ 1. Let |chunk| be ! [$DequeueValue$] ([=this=] ).
6420
+ 1. If |chunk| has [=closing steps=] , perform the [=closing steps=] given |chunk|.
6391
6421
1. Set |container|.\[[queue]] to a new empty [=list=] .
6392
6422
1. Set |container|.\[[queueTotalSize]] to 0.
6393
6423
</div>
@@ -6596,6 +6626,18 @@ The following abstract operations are a grab-bag of utilities.
6596
6626
1. Return ? [$StructuredDeserialize$] (|serialized|, [=the current Realm=] ).
6597
6627
</div>
6598
6628
6629
+ <div algorithm>
6630
+ <dfn abstract-op lt="StructuredTransferOrSerialize">StructuredTransferOrSerialize(|value|)</dfn>
6631
+ performs the following steps:
6632
+ 1. If |value| is [=transferable objects|transferable=] , perform the following steps:
6633
+ // FIXME: We should probably handle other transferable types like ArrayBuffers.
6634
+ 1. Let |serialized| be ! [$StructuredSerializeWithTransfer$] (|value|, « |value| »).
6635
+ 1. Let |deserialized| be ! [$StructuredDeserializeWithTransfer$] (|serialized|,
6636
+ [=the current Realm=] ).
6637
+ 1. return |deserialized|.\[[Deserialized]] .
6638
+ 1. return [$StructuredClone$] (|value|).
6639
+ </div>
6640
+
6599
6641
<h2 id="other-specs">Using streams in other specifications</h2>
6600
6642
6601
6643
Much of this standard concerns itself with the internal machinery of streams. Other specifications
0 commit comments