Streams: Implement stream pipe-to (#35650)

* implement PipeTo, stub pipe_to

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* define a data structure to manage the piping

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* implement propagation of errors forward and backward, stub shutdown and shutdown with action

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* adding more fine-grain shutdown variants to state

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* implement progagate closing backward and forward

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* implement shutdown and actions

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* implement reading and writing

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* implement shutdown continuation and finalize

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* fix typo

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* add can_gc arguments

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* implement writer close with error propagation

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* move and document wait on pending write

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* more docs

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* write pending reads as part of shutdown

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* turn on piping test suite

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* add comment about using Rust api
improve comment on result
add comment on backpressure

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* fix multiple propagations

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* fix writing of chunks

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* fix error and close propagation
update test expectations

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* fix warnings

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* improve docs
remove redundant logic in pending writes

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* fix clippy

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* remove unnecessary expansion of visibility of enqueued value to_jsval

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* remove unnecessary conditional accessing of streams when propagating states

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* improve docs

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* remove unused result var

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* fix typo

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* remove redundant logic dealing with closed sources with pending writes

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* add doc links for shutdown actions

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* add comments on the need to return early when shutting down before checking close and error states

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* fmt

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>

* Update test expectations

Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>

* fix can_gc

Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>

---------

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>
Signed-off-by: Taym Haddadi <haddadi.taym@gmail.com>
Co-authored-by: Taym Haddadi <haddadi.taym@gmail.com>
This commit is contained in:
Gregory Terzian 2025-03-18 19:13:09 +08:00 committed by GitHub
parent 67a5f285ed
commit 8d39d7706a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 1319 additions and 29 deletions

View file

@ -241,6 +241,8 @@ skip: true
skip: false
[streams]
skip: true
[piping]
skip: false
[readable-streams]
skip: false
[readable-byte-streams]

View file

@ -1,3 +0,0 @@
[response-body-read-task-handling.html]
[piping from a body stream to a JS-written WritableStream should occur in a microtask scope]
expected: FAIL

View file

@ -2,17 +2,11 @@
[using pipeThrough on Response body should disturb it synchronously]
expected: FAIL
[using pipeTo on Response body should disturb it synchronously]
expected: FAIL
[response-stream-disturbed-by-pipe.any.html]
[using pipeThrough on Response body should disturb it synchronously]
expected: FAIL
[using pipeTo on Response body should disturb it synchronously]
expected: FAIL
[response-stream-disturbed-by-pipe.any.serviceworker.html]
expected: ERROR

View file

@ -1,5 +1,4 @@
[response-stream-with-broken-then.any.worker.html]
expected: TIMEOUT
[Attempt to inject {done: false, value: bye} via Object.prototype.then.]
expected: FAIL
@ -23,7 +22,6 @@
expected: ERROR
[response-stream-with-broken-then.any.html]
expected: CRASH
[Attempt to inject {done: false, value: bye} via Object.prototype.then.]
expected: FAIL

View file

@ -0,0 +1,29 @@
[abort.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR
[abort.any.shadowrealm-in-window.html]
expected: ERROR
[abort.any.html]
expected: ERROR
[abort.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
[abort.any.sharedworker.html]
expected: ERROR
[abort.any.shadowrealm-in-sharedworker.html]
expected: ERROR
[abort.any.serviceworker.html]
expected: ERROR
[abort.any.worker.html]
expected: ERROR
[abort.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
[abort.any.shadowrealm-in-shadowrealm.html]
expected: ERROR

View file

@ -0,0 +1,27 @@
[close-propagation-backward.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
[close-propagation-backward.any.serviceworker.html]
expected: ERROR
[close-propagation-backward.any.html]
[close-propagation-backward.any.sharedworker.html]
expected: ERROR
[close-propagation-backward.any.shadowrealm-in-shadowrealm.html]
expected: ERROR
[close-propagation-backward.any.shadowrealm-in-sharedworker.html]
expected: ERROR
[close-propagation-backward.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR
[close-propagation-backward.any.shadowrealm-in-window.html]
expected: ERROR
[close-propagation-backward.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
[close-propagation-backward.any.worker.html]

View file

@ -0,0 +1,27 @@
[close-propagation-forward.any.shadowrealm-in-sharedworker.html]
expected: ERROR
[close-propagation-forward.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
[close-propagation-forward.any.shadowrealm-in-window.html]
expected: ERROR
[close-propagation-forward.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR
[close-propagation-forward.any.worker.html]
[close-propagation-forward.any.serviceworker.html]
expected: ERROR
[close-propagation-forward.any.shadowrealm-in-shadowrealm.html]
expected: ERROR
[close-propagation-forward.any.sharedworker.html]
expected: ERROR
[close-propagation-forward.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
[close-propagation-forward.any.html]

View file

@ -0,0 +1,27 @@
[error-propagation-backward.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
[error-propagation-backward.any.shadowrealm-in-sharedworker.html]
expected: ERROR
[error-propagation-backward.any.shadowrealm-in-window.html]
expected: ERROR
[error-propagation-backward.any.worker.html]
[error-propagation-backward.any.html]
[error-propagation-backward.any.shadowrealm-in-shadowrealm.html]
expected: ERROR
[error-propagation-backward.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
[error-propagation-backward.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR
[error-propagation-backward.any.sharedworker.html]
expected: ERROR
[error-propagation-backward.any.serviceworker.html]
expected: ERROR

View file

@ -0,0 +1,27 @@
[error-propagation-forward.any.html]
[error-propagation-forward.any.serviceworker.html]
expected: ERROR
[error-propagation-forward.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
[error-propagation-forward.any.shadowrealm-in-sharedworker.html]
expected: ERROR
[error-propagation-forward.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
[error-propagation-forward.any.shadowrealm-in-shadowrealm.html]
expected: ERROR
[error-propagation-forward.any.sharedworker.html]
expected: ERROR
[error-propagation-forward.any.worker.html]
[error-propagation-forward.any.shadowrealm-in-window.html]
expected: ERROR
[error-propagation-forward.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR

View file

@ -0,0 +1,27 @@
[flow-control.any.html]
[flow-control.any.serviceworker.html]
expected: ERROR
[flow-control.any.worker.html]
[flow-control.any.sharedworker.html]
expected: ERROR
[flow-control.any.shadowrealm-in-shadowrealm.html]
expected: ERROR
[flow-control.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
[flow-control.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR
[flow-control.any.shadowrealm-in-sharedworker.html]
expected: ERROR
[flow-control.any.shadowrealm-in-window.html]
expected: ERROR
[flow-control.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR

View file

@ -0,0 +1,27 @@
[general-addition.any.sharedworker.html]
expected: ERROR
[general-addition.any.html]
[general-addition.any.shadowrealm-in-shadowrealm.html]
expected: ERROR
[general-addition.any.shadowrealm-in-window.html]
expected: ERROR
[general-addition.any.serviceworker.html]
expected: ERROR
[general-addition.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
[general-addition.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR
[general-addition.any.shadowrealm-in-sharedworker.html]
expected: ERROR
[general-addition.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
[general-addition.any.worker.html]

View file

@ -0,0 +1,27 @@
[general.any.sharedworker.html]
expected: ERROR
[general.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
[general.any.worker.html]
[general.any.serviceworker.html]
expected: ERROR
[general.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
[general.any.shadowrealm-in-window.html]
expected: ERROR
[general.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR
[general.any.shadowrealm-in-sharedworker.html]
expected: ERROR
[general.any.html]
[general.any.shadowrealm-in-shadowrealm.html]
expected: ERROR

View file

@ -0,0 +1,27 @@
[multiple-propagation.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR
[multiple-propagation.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
[multiple-propagation.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
[multiple-propagation.any.serviceworker.html]
expected: ERROR
[multiple-propagation.any.shadowrealm-in-window.html]
expected: ERROR
[multiple-propagation.any.shadowrealm-in-shadowrealm.html]
expected: ERROR
[multiple-propagation.any.shadowrealm-in-sharedworker.html]
expected: ERROR
[multiple-propagation.any.worker.html]
[multiple-propagation.any.html]
[multiple-propagation.any.sharedworker.html]
expected: ERROR

View file

@ -0,0 +1,142 @@
[pipe-through.any.shadowrealm-in-shadowrealm.html]
expected: ERROR
[pipe-through.any.serviceworker.html]
expected: ERROR
[pipe-through.any.worker.html]
expected: ERROR
[Piping through a duck-typed pass-through transform stream should work]
expected: FAIL
[Piping through a transform errored on the writable end does not cause an unhandled promise rejection]
expected: FAIL
[pipeThrough should not call pipeTo on this]
expected: FAIL
[pipeThrough should not call pipeTo on the ReadableStream prototype]
expected: FAIL
[pipeThrough should brand-check this and not allow 'null']
expected: FAIL
[pipeThrough should brand-check this and not allow 'undefined']
expected: FAIL
[pipeThrough should brand-check this and not allow '0']
expected: FAIL
[pipeThrough should brand-check this and not allow 'NaN']
expected: FAIL
[pipeThrough should brand-check this and not allow 'true']
expected: FAIL
[pipeThrough should brand-check this and not allow 'ReadableStream']
expected: FAIL
[pipeThrough should brand-check this and not allow '[object ReadableStream\]']
expected: FAIL
[pipeThrough should brand-check writable and not allow 'null']
expected: FAIL
[pipeThrough should brand-check writable and not allow 'undefined']
expected: FAIL
[pipeThrough should brand-check writable and not allow '0']
expected: FAIL
[pipeThrough should brand-check writable and not allow 'NaN']
expected: FAIL
[pipeThrough should brand-check writable and not allow 'true']
expected: FAIL
[pipeThrough should brand-check writable and not allow 'WritableStream']
expected: FAIL
[pipeThrough should brand-check writable and not allow '[object WritableStream\]']
expected: FAIL
[pipeThrough should rethrow errors from accessing readable or writable]
expected: FAIL
[pipe-through.any.sharedworker.html]
expected: ERROR
[pipe-through.any.shadowrealm-in-window.html]
expected: ERROR
[pipe-through.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
[pipe-through.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR
[pipe-through.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
[pipe-through.any.shadowrealm-in-sharedworker.html]
expected: ERROR
[pipe-through.any.html]
expected: ERROR
[Piping through a duck-typed pass-through transform stream should work]
expected: FAIL
[Piping through a transform errored on the writable end does not cause an unhandled promise rejection]
expected: FAIL
[pipeThrough should not call pipeTo on this]
expected: FAIL
[pipeThrough should not call pipeTo on the ReadableStream prototype]
expected: FAIL
[pipeThrough should brand-check this and not allow 'null']
expected: FAIL
[pipeThrough should brand-check this and not allow 'undefined']
expected: FAIL
[pipeThrough should brand-check this and not allow '0']
expected: FAIL
[pipeThrough should brand-check this and not allow 'NaN']
expected: FAIL
[pipeThrough should brand-check this and not allow 'true']
expected: FAIL
[pipeThrough should brand-check this and not allow 'ReadableStream']
expected: FAIL
[pipeThrough should brand-check this and not allow '[object ReadableStream\]']
expected: FAIL
[pipeThrough should brand-check writable and not allow 'null']
expected: FAIL
[pipeThrough should brand-check writable and not allow 'undefined']
expected: FAIL
[pipeThrough should brand-check writable and not allow '0']
expected: FAIL
[pipeThrough should brand-check writable and not allow 'NaN']
expected: FAIL
[pipeThrough should brand-check writable and not allow 'true']
expected: FAIL
[pipeThrough should brand-check writable and not allow 'WritableStream']
expected: FAIL
[pipeThrough should brand-check writable and not allow '[object WritableStream\]']
expected: FAIL
[pipeThrough should rethrow errors from accessing readable or writable]
expected: FAIL

View file

@ -0,0 +1,29 @@
[then-interception.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
[then-interception.any.shadowrealm-in-shadowrealm.html]
expected: ERROR
[then-interception.any.serviceworker.html]
expected: ERROR
[then-interception.any.worker.html]
expected: CRASH
[then-interception.any.html]
expected: CRASH
[then-interception.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR
[then-interception.any.shadowrealm-in-window.html]
expected: ERROR
[then-interception.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
[then-interception.any.sharedworker.html]
expected: ERROR
[then-interception.any.shadowrealm-in-sharedworker.html]
expected: ERROR

View file

@ -0,0 +1,59 @@
[throwing-options.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR
[throwing-options.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR
[throwing-options.any.serviceworker.html]
expected: ERROR
[throwing-options.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
[throwing-options.any.shadowrealm-in-sharedworker.html]
expected: ERROR
[throwing-options.any.shadowrealm-in-shadowrealm.html]
expected: ERROR
[throwing-options.any.shadowrealm-in-window.html]
expected: ERROR
[throwing-options.any.html]
expected: TIMEOUT
[pipeThrough should stop after getting preventAbort throws]
expected: FAIL
[pipeThrough should stop after getting preventCancel throws]
expected: FAIL
[pipeThrough should stop after getting preventClose throws]
expected: FAIL
[pipeTo should stop after getting signal throws]
expected: TIMEOUT
[pipeThrough should stop after getting signal throws]
expected: FAIL
[throwing-options.any.worker.html]
expected: TIMEOUT
[pipeThrough should stop after getting preventAbort throws]
expected: FAIL
[pipeThrough should stop after getting preventCancel throws]
expected: FAIL
[pipeThrough should stop after getting preventClose throws]
expected: FAIL
[pipeTo should stop after getting signal throws]
expected: TIMEOUT
[pipeThrough should stop after getting signal throws]
expected: FAIL
[throwing-options.any.sharedworker.html]
expected: ERROR

View file

@ -0,0 +1,33 @@
[transform-streams.any.shadowrealm-in-dedicatedworker.html]
expected: ERROR
[transform-streams.https.any.shadowrealm-in-serviceworker.html]
expected: ERROR
[transform-streams.any.sharedworker.html]
expected: ERROR
[transform-streams.any.shadowrealm-in-sharedworker.html]
expected: ERROR
[transform-streams.any.worker.html]
[Piping through an identity transform stream should close the destination when the source closes]
expected: FAIL
[transform-streams.any.shadowrealm-in-shadowrealm.html]
expected: ERROR
[transform-streams.any.html]
[Piping through an identity transform stream should close the destination when the source closes]
expected: FAIL
[transform-streams.any.shadowrealm-in-window.html]
expected: ERROR
[transform-streams.any.serviceworker.html]
expected: ERROR
[transform-streams.https.any.shadowrealm-in-audioworklet.html]
expected: ERROR

View file

@ -5,17 +5,11 @@
expected: ERROR
[patched-global.any.html]
[pipeTo() should not call Promise.prototype.then()]
expected: FAIL
[ReadableStream async iterator should use the original values of getReader() and ReadableStreamDefaultReader methods]
expected: FAIL
[patched-global.any.worker.html]
[pipeTo() should not call Promise.prototype.then()]
expected: FAIL
[ReadableStream async iterator should use the original values of getReader() and ReadableStreamDefaultReader methods]
expected: FAIL

View file

@ -5,14 +5,8 @@
expected: ERROR
[reentrant-strategies.any.html]
[pipeTo() inside size() should behave as expected]
expected: FAIL
[reentrant-strategies.any.worker.html]
[pipeTo() inside size() should behave as expected]
expected: FAIL
[reentrant-strategies.any.shadowrealm.html]
expected: TIMEOUT