diff options
Diffstat (limited to 'components/script/dom/writablestreamdefaultcontroller.rs')
-rw-r--r-- | components/script/dom/writablestreamdefaultcontroller.rs | 252 |
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!() + }, } } |