Transfer ReadableStream (#36181)

<!-- Please describe your changes on the following line: -->

Add transfer support to ReadableStream. Part of
https://github.com/servo/servo/issues/34676

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by
`[X]` when the step is complete, and replace `___` with appropriate
data: -->
- [ ] `./mach build -d` does not report any errors
- [ ] `./mach test-tidy` does not report any errors
- [ ] These changes fix #___ (GitHub issue number if applicable)

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because ___

<!-- Also, please make sure that "Allow edits from maintainers" checkbox
is checked, so that we can help you if you get stuck somewhere along the
way.-->

<!-- Pull requests that do not address these steps are welcome, but they
will require additional verification as part of the review process. -->

---------

Signed-off-by: gterzian <2792687+gterzian@users.noreply.github.com>
This commit is contained in:
Gregory Terzian 2025-04-15 15:39:26 +08:00 committed by GitHub
parent c9489ca04f
commit f8b6b9f7b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 983 additions and 75 deletions

View file

@ -7,7 +7,7 @@ use std::rc::Rc;
use dom_struct::dom_struct;
use js::jsapi::{Heap, IsPromiseObject, JSObject};
use js::jsval::JSVal;
use js::jsval::{JSVal, UndefinedValue};
use js::rust::{Handle as SafeHandle, HandleObject, HandleValue as SafeHandleValue, IntoHandle};
use crate::dom::bindings::callback::ExceptionHandling;
@ -18,6 +18,7 @@ use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_w
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::defaultteeunderlyingsource::DefaultTeeUnderlyingSource;
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageport::MessagePort;
use crate::dom::promise::Promise;
use crate::script_runtime::CanGc;
@ -40,6 +41,8 @@ pub(crate) enum UnderlyingSourceType {
Js(JsUnderlyingSource, Heap<*mut JSObject>),
/// Tee
Tee(Dom<DefaultTeeUnderlyingSource>),
/// Transfer, with the port used in some of the algorithms.
Transfer(Dom<MessagePort>),
}
impl UnderlyingSourceType {
@ -49,7 +52,8 @@ impl UnderlyingSourceType {
self,
UnderlyingSourceType::Memory(_) |
UnderlyingSourceType::Blob(_) |
UnderlyingSourceType::FetchResponse
UnderlyingSourceType::FetchResponse |
UnderlyingSourceType::Transfer(_)
)
}
@ -128,6 +132,28 @@ impl UnderlyingSourceContainer {
// Call the cancel algorithm for the appropriate branch.
tee_underlyin_source.cancel_algorithm(reason, can_gc)
},
UnderlyingSourceType::Transfer(port) => {
// Let cancelAlgorithm be the following steps, taking a reason argument:
// from <https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformreadable
// Let result be PackAndPostMessageHandlingError(port, "error", reason).
let result = port.pack_and_post_message_handling_error("error", reason, can_gc);
// Disentangle port.
self.global().disentangle_port(port);
let promise = Promise::new(&self.global(), can_gc);
// If result is an abrupt completion,
if let Err(error) = result {
// Return a promise rejected with result.[[Value]].
promise.reject_error(error, can_gc);
} else {
// Otherwise, return a promise resolved with undefined.
promise.resolve_native(&(), can_gc);
}
Some(Ok(promise))
},
_ => None,
}
}
@ -158,6 +184,22 @@ impl UnderlyingSourceContainer {
// Call the pull algorithm for the appropriate branch.
Some(Ok(tee_underlyin_source.pull_algorithm(can_gc)))
},
UnderlyingSourceType::Transfer(port) => {
// Let pullAlgorithm be the following steps:
// from <https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformreadable
let cx = GlobalScope::get_cx();
// Perform ! PackAndPostMessage(port, "pull", undefined).
rooted!(in(*cx) let mut value = UndefinedValue());
port.pack_and_post_message("pull", value.handle(), can_gc)
.expect("Sending pull should not fail.");
// Return a promise resolved with undefined.
let promise = Promise::new(&self.global(), can_gc);
promise.resolve_native(&(), can_gc);
Some(Ok(promise))
},
// Note: other source type have no pull steps for now.
_ => None,
}
@ -217,6 +259,11 @@ impl UnderlyingSourceContainer {
// Let startAlgorithm be an algorithm that returns undefined.
None
},
UnderlyingSourceType::Transfer(_) => {
// Let startAlgorithm be an algorithm that returns undefined.
// from <https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformreadable
None
},
_ => None,
}
}