aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/writablestreamdefaultcontroller.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/writablestreamdefaultcontroller.rs')
-rw-r--r--components/script/dom/writablestreamdefaultcontroller.rs252
1 files changed, 168 insertions, 84 deletions
diff --git a/components/script/dom/writablestreamdefaultcontroller.rs b/components/script/dom/writablestreamdefaultcontroller.rs
index 751f5d8d976..084165a6892 100644
--- a/components/script/dom/writablestreamdefaultcontroller.rs
+++ b/components/script/dom/writablestreamdefaultcontroller.rs
@@ -14,11 +14,11 @@ use js::rust::{HandleObject as SafeHandleObject, HandleValue as SafeHandleValue,
use super::bindings::codegen::Bindings::QueuingStrategyBinding::QueuingStrategySize;
use crate::dom::bindings::callback::ExceptionHandling;
use crate::dom::bindings::codegen::Bindings::UnderlyingSinkBinding::{
- UnderlyingSink, UnderlyingSinkAbortCallback, UnderlyingSinkCloseCallback,
- UnderlyingSinkStartCallback, UnderlyingSinkWriteCallback,
+ UnderlyingSinkAbortCallback, UnderlyingSinkCloseCallback, UnderlyingSinkStartCallback,
+ UnderlyingSinkWriteCallback,
};
use crate::dom::bindings::codegen::Bindings::WritableStreamDefaultControllerBinding::WritableStreamDefaultControllerMethods;
-use crate::dom::bindings::error::{Error, ErrorToJsval};
+use crate::dom::bindings::error::{Error, ErrorToJsval, Fallible};
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use crate::dom::globalscope::GlobalScope;
@@ -173,11 +173,11 @@ impl Callback for TransferBackPressurePromiseReaction {
self.port
.pack_and_post_message_handling_error("chunk", chunk.handle(), can_gc);
- // Disentangle port.
- global.disentangle_port(&self.port);
-
// If result is an abrupt completion,
if let Err(error) = result {
+ // Disentangle port.
+ global.disentangle_port(&self.port, can_gc);
+
// Return a promise rejected with result.[[Value]].
self.result_promise.reject_error(error, can_gc);
} else {
@@ -268,15 +268,46 @@ impl Callback for WriteAlgorithmRejectionHandler {
/// The type of sink algorithms we are using.
#[derive(JSTraceable, PartialEq)]
+#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
pub enum UnderlyingSinkType {
/// Algorithms are provided by Js callbacks.
- Js,
+ Js {
+ /// <https://streams.spec.whatwg.org/#writablestreamdefaultcontroller-abortalgorithm>
+ abort: RefCell<Option<Rc<UnderlyingSinkAbortCallback>>>,
+
+ start: RefCell<Option<Rc<UnderlyingSinkStartCallback>>>,
+
+ /// <https://streams.spec.whatwg.org/#writablestreamdefaultcontroller-closealgorithm>
+ close: RefCell<Option<Rc<UnderlyingSinkCloseCallback>>>,
+
+ /// <https://streams.spec.whatwg.org/#writablestreamdefaultcontroller-writealgorithm>
+ write: RefCell<Option<Rc<UnderlyingSinkWriteCallback>>>,
+ },
/// Algorithms supporting streams transfer are implemented in Rust.
/// The promise and port used in those algorithms are stored here.
Transfer {
backpressure_promise: Rc<RefCell<Option<Rc<Promise>>>>,
port: Dom<MessagePort>,
},
+ /// Algorithms supporting transform streams are implemented in Rust.
+ #[allow(unused)]
+ Transform(/*Dom<TransformStream>, Rc<Promise>*/),
+}
+
+impl UnderlyingSinkType {
+ pub(crate) fn new_js(
+ abort: Option<Rc<UnderlyingSinkAbortCallback>>,
+ start: Option<Rc<UnderlyingSinkStartCallback>>,
+ close: Option<Rc<UnderlyingSinkCloseCallback>>,
+ write: Option<Rc<UnderlyingSinkWriteCallback>>,
+ ) -> Self {
+ UnderlyingSinkType::Js {
+ abort: RefCell::new(abort),
+ start: RefCell::new(start),
+ close: RefCell::new(close),
+ write: RefCell::new(write),
+ }
+ }
}
/// <https://streams.spec.whatwg.org/#ws-default-controller-class>
@@ -284,21 +315,11 @@ pub enum UnderlyingSinkType {
pub struct WritableStreamDefaultController {
reflector_: Reflector,
- #[ignore_malloc_size_of = "Rc is hard"]
+ /// The type of underlying sink used. Besides the default JS one,
+ /// there will be others for stream transfer, and for transform stream.
+ #[ignore_malloc_size_of = "underlying_sink_type"]
underlying_sink_type: UnderlyingSinkType,
- /// <https://streams.spec.whatwg.org/#writablestreamdefaultcontroller-abortalgorithm>
- #[ignore_malloc_size_of = "Rc is hard"]
- abort: RefCell<Option<Rc<UnderlyingSinkAbortCallback>>>,
-
- /// <https://streams.spec.whatwg.org/#writablestreamdefaultcontroller-closealgorithm>
- #[ignore_malloc_size_of = "Rc is hard"]
- close: RefCell<Option<Rc<UnderlyingSinkCloseCallback>>>,
-
- /// <https://streams.spec.whatwg.org/#writablestreamdefaultcontroller-writealgorithm>
- #[ignore_malloc_size_of = "Rc is hard"]
- write: RefCell<Option<Rc<UnderlyingSinkWriteCallback>>>,
-
/// The JS object used as `this` when invoking sink algorithms.
#[ignore_malloc_size_of = "mozjs"]
underlying_sink_obj: Heap<*mut JSObject>,
@@ -325,7 +346,6 @@ impl WritableStreamDefaultController {
#[cfg_attr(crown, allow(crown::unrooted_must_root))]
fn new_inherited(
underlying_sink_type: UnderlyingSinkType,
- underlying_sink: &UnderlyingSink,
strategy_hwm: f64,
strategy_size: Rc<QueuingStrategySize>,
) -> WritableStreamDefaultController {
@@ -334,9 +354,6 @@ impl WritableStreamDefaultController {
underlying_sink_type,
queue: Default::default(),
stream: Default::default(),
- abort: RefCell::new(underlying_sink.abort.clone()),
- close: RefCell::new(underlying_sink.close.clone()),
- write: RefCell::new(underlying_sink.write.clone()),
underlying_sink_obj: Default::default(),
strategy_hwm,
strategy_size: RefCell::new(Some(strategy_size)),
@@ -344,10 +361,10 @@ impl WritableStreamDefaultController {
}
}
+ #[cfg_attr(crown, allow(crown::unrooted_must_root))]
pub(crate) fn new(
global: &GlobalScope,
underlying_sink_type: UnderlyingSinkType,
- underlying_sink: &UnderlyingSink,
strategy_hwm: f64,
strategy_size: Rc<QueuingStrategySize>,
can_gc: CanGc,
@@ -355,7 +372,6 @@ impl WritableStreamDefaultController {
reflect_dom_object(
Box::new(WritableStreamDefaultController::new_inherited(
underlying_sink_type,
- underlying_sink,
strategy_hwm,
strategy_size,
)),
@@ -375,27 +391,44 @@ impl WritableStreamDefaultController {
/// <https://streams.spec.whatwg.org/#writable-stream-default-controller-clear-algorithms>
fn clear_algorithms(&self) {
- // Set controller.[[writeAlgorithm]] to undefined.
- self.write.borrow_mut().take();
+ match &self.underlying_sink_type {
+ UnderlyingSinkType::Js {
+ abort,
+ start: _,
+ close,
+ write,
+ } => {
+ // Set controller.[[writeAlgorithm]] to undefined.
+ write.borrow_mut().take();
- // Set controller.[[closeAlgorithm]] to undefined.
- self.close.borrow_mut().take();
+ // Set controller.[[closeAlgorithm]] to undefined.
+ close.borrow_mut().take();
- // Set controller.[[abortAlgorithm]] to undefined.
- self.abort.borrow_mut().take();
+ // Set controller.[[abortAlgorithm]] to undefined.
+ abort.borrow_mut().take();
+ },
+ UnderlyingSinkType::Transfer {
+ backpressure_promise,
+ ..
+ } => {
+ backpressure_promise.borrow_mut().take();
+ },
+ UnderlyingSinkType::Transform() => {
+ return;
+ },
+ }
// Set controller.[[strategySizeAlgorithm]] to undefined.
self.strategy_size.borrow_mut().take();
}
- /// <https://streams.spec.whatwg.org/#set-up-writable-stream-default-controllerr>
+ /// <https://streams.spec.whatwg.org/#set-up-writable-stream-default-controller>
#[allow(unsafe_code)]
pub(crate) fn setup(
&self,
cx: SafeJSContext,
global: &GlobalScope,
stream: &WritableStream,
- start: &Option<Rc<UnderlyingSinkStartCallback>>,
can_gc: CanGc,
) -> Result<(), Error> {
// Assert: stream implements WritableStream.
@@ -436,40 +469,7 @@ impl WritableStreamDefaultController {
// Let startResult be the result of performing startAlgorithm. (This may throw an exception.)
// Let startPromise be a promise resolved with startResult.
- let start_promise = if let Some(start) = start {
- rooted!(in(*cx) let mut result_object = ptr::null_mut::<JSObject>());
- rooted!(in(*cx) let mut result: JSVal);
- rooted!(in(*cx) let this_object = self.underlying_sink_obj.get());
- start.Call_(
- &this_object.handle(),
- self,
- result.handle_mut(),
- ExceptionHandling::Rethrow,
- can_gc,
- )?;
- let is_promise = unsafe {
- if result.is_object() {
- result_object.set(result.to_object());
- IsPromiseObject(result_object.handle().into_handle())
- } else {
- false
- }
- };
- if is_promise {
- let promise = Promise::new_with_js_promise(result_object.handle(), cx);
- promise
- } else {
- Promise::new_resolved(global, cx, result.get(), can_gc)
- }
- } else {
- // Note: we are either here because the Js algorithm is none,
- // or because we are suppporting a stream transfer as
- // part of #abstract-opdef-setupcrossrealmtransformwritable
- // and the logic is the same for both.
-
- // Let startAlgorithm be an algorithm that returns undefined.
- Promise::new_resolved(global, cx, (), can_gc)
- };
+ let start_promise = self.start_algorithm(cx, global, can_gc)?;
let rooted_default_controller = DomRoot::from_ref(self);
@@ -509,6 +509,64 @@ impl WritableStreamDefaultController {
self.advance_queue_if_needed(cx, global, can_gc);
}
+ #[allow(unsafe_code)]
+ fn start_algorithm(
+ &self,
+ cx: SafeJSContext,
+ global: &GlobalScope,
+ can_gc: CanGc,
+ ) -> Fallible<Rc<Promise>> {
+ match &self.underlying_sink_type {
+ UnderlyingSinkType::Js {
+ start,
+ abort: _,
+ close: _,
+ write: _,
+ } => {
+ let algo = start.borrow().clone();
+ let start_promise = if let Some(start) = algo {
+ rooted!(in(*cx) let mut result_object = ptr::null_mut::<JSObject>());
+ rooted!(in(*cx) let mut result: JSVal);
+ rooted!(in(*cx) let this_object = self.underlying_sink_obj.get());
+ start.Call_(
+ &this_object.handle(),
+ self,
+ result.handle_mut(),
+ ExceptionHandling::Rethrow,
+ can_gc,
+ )?;
+ let is_promise = unsafe {
+ if result.is_object() {
+ result_object.set(result.to_object());
+ IsPromiseObject(result_object.handle().into_handle())
+ } else {
+ false
+ }
+ };
+ if is_promise {
+ let promise = Promise::new_with_js_promise(result_object.handle(), cx);
+ promise
+ } else {
+ Promise::new_resolved(global, cx, result.get(), can_gc)
+ }
+ } else {
+ // Let startAlgorithm be an algorithm that returns undefined.
+ Promise::new_resolved(global, cx, (), can_gc)
+ };
+
+ Ok(start_promise)
+ },
+ UnderlyingSinkType::Transfer { .. } => {
+ // Let startAlgorithm be an algorithm that returns undefined.
+ Ok(Promise::new_resolved(global, cx, (), can_gc))
+ },
+ UnderlyingSinkType::Transform() => {
+ // Let startAlgorithm be an algorithm that returns startPromise.
+ todo!()
+ },
+ }
+ }
+
/// <https://streams.spec.whatwg.org/#ref-for-abstract-opdef-writablestreamcontroller-abortsteps>
pub(crate) fn abort_steps(
&self,
@@ -517,10 +575,15 @@ impl WritableStreamDefaultController {
reason: SafeHandleValue,
can_gc: CanGc,
) -> Rc<Promise> {
- let result = match self.underlying_sink_type {
- UnderlyingSinkType::Js => {
+ let result = match &self.underlying_sink_type {
+ UnderlyingSinkType::Js {
+ abort,
+ start: _,
+ close: _,
+ write: _,
+ } => {
rooted!(in(*cx) let this_object = self.underlying_sink_obj.get());
- let algo = self.abort.borrow().clone();
+ let algo = abort.borrow().clone();
// Let result be the result of performing this.[[abortAlgorithm]], passing reason.
let result = if let Some(algo) = algo {
algo.Call_(
@@ -538,7 +601,7 @@ impl WritableStreamDefaultController {
promise
})
},
- UnderlyingSinkType::Transfer { ref port, .. } => {
+ UnderlyingSinkType::Transfer { port, .. } => {
// The steps from the `abortAlgorithm` at
// <https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformwritable>
@@ -546,7 +609,7 @@ impl WritableStreamDefaultController {
let result = port.pack_and_post_message_handling_error("error", reason, can_gc);
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
let promise = Promise::new(global, can_gc);
@@ -559,6 +622,10 @@ impl WritableStreamDefaultController {
}
promise
},
+ UnderlyingSinkType::Transform() => {
+ // Return ! TransformStreamDefaultSinkAbortAlgorithm(stream, reason).
+ todo!()
+ },
};
// Perform ! WritableStreamDefaultControllerClearAlgorithms(controller).
@@ -575,10 +642,15 @@ impl WritableStreamDefaultController {
global: &GlobalScope,
can_gc: CanGc,
) -> Rc<Promise> {
- match self.underlying_sink_type {
- UnderlyingSinkType::Js => {
+ match &self.underlying_sink_type {
+ UnderlyingSinkType::Js {
+ abort: _,
+ start: _,
+ close: _,
+ write,
+ } => {
rooted!(in(*cx) let this_object = self.underlying_sink_obj.get());
- let algo = self.write.borrow().clone();
+ let algo = write.borrow().clone();
let result = if let Some(algo) = algo {
algo.Call_(
&this_object.handle(),
@@ -597,9 +669,8 @@ impl WritableStreamDefaultController {
})
},
UnderlyingSinkType::Transfer {
- ref backpressure_promise,
- ref port,
- ..
+ backpressure_promise,
+ port,
} => {
// The steps from the `writeAlgorithm` at
// <https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformwritable>
@@ -636,6 +707,10 @@ impl WritableStreamDefaultController {
.append_native_handler(&handler, comp, can_gc);
result_promise
},
+ UnderlyingSinkType::Transform() => {
+ // Return ! TransformStreamDefaultSinkWriteAlgorithm(stream, chunk).
+ todo!()
+ },
}
}
@@ -646,11 +721,16 @@ impl WritableStreamDefaultController {
global: &GlobalScope,
can_gc: CanGc,
) -> Rc<Promise> {
- match self.underlying_sink_type {
- UnderlyingSinkType::Js => {
+ match &self.underlying_sink_type {
+ UnderlyingSinkType::Js {
+ abort: _,
+ start: _,
+ close,
+ write: _,
+ } => {
rooted!(in(*cx) let mut this_object = ptr::null_mut::<JSObject>());
this_object.set(self.underlying_sink_obj.get());
- let algo = self.close.borrow().clone();
+ let algo = close.borrow().clone();
let result = if let Some(algo) = algo {
algo.Call_(&this_object.handle(), ExceptionHandling::Rethrow, can_gc)
} else {
@@ -662,7 +742,7 @@ impl WritableStreamDefaultController {
promise
})
},
- UnderlyingSinkType::Transfer { ref port, .. } => {
+ UnderlyingSinkType::Transfer { port, .. } => {
// The steps from the `closeAlgorithm` at
// <https://streams.spec.whatwg.org/#abstract-opdef-setupcrossrealmtransformwritable>
@@ -672,11 +752,15 @@ impl WritableStreamDefaultController {
.expect("Sending close should not fail.");
// Disentangle port.
- global.disentangle_port(port);
+ global.disentangle_port(port, can_gc);
// Return a promise resolved with undefined.
Promise::new_resolved(global, cx, (), can_gc)
},
+ UnderlyingSinkType::Transform() => {
+ // Return ! TransformStreamDefaultSinkCloseAlgorithm(stream).
+ todo!()
+ },
}
}