aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/writablestream.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/writablestream.rs')
-rw-r--r--components/script/dom/writablestream.rs90
1 files changed, 88 insertions, 2 deletions
diff --git a/components/script/dom/writablestream.rs b/components/script/dom/writablestream.rs
index c8a91cd7475..da0fe3b5957 100644
--- a/components/script/dom/writablestream.rs
+++ b/components/script/dom/writablestream.rs
@@ -3,11 +3,13 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::{Cell, RefCell};
-use std::collections::VecDeque;
+use std::collections::{HashMap, VecDeque};
use std::mem;
use std::ptr::{self};
use std::rc::Rc;
+use base::id::MessagePortId;
+use constellation_traits::MessagePortImpl;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
use js::jsval::{JSVal, ObjectValue, UndefinedValue};
@@ -25,13 +27,15 @@ use crate::dom::bindings::conversions::ConversionResult;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
+use crate::dom::bindings::structuredclone::{StructuredData, StructuredDataReader};
+use crate::dom::bindings::transferable::Transferable;
use crate::dom::countqueuingstrategy::{extract_high_water_mark, extract_size_algorithm};
use crate::dom::domexception::{DOMErrorName, DOMException};
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageport::MessagePort;
use crate::dom::promise::Promise;
use crate::dom::promisenativehandler::{Callback, PromiseNativeHandler};
-use crate::dom::readablestream::get_type_and_value_from_message;
+use crate::dom::readablestream::{ReadableStream, get_type_and_value_from_message};
use crate::dom::writablestreamdefaultcontroller::{
UnderlyingSinkType, WritableStreamDefaultController,
};
@@ -1107,3 +1111,85 @@ impl CrossRealmTransformWritable {
global.disentangle_port(port);
}
}
+
+/// <https://streams.spec.whatwg.org/#ws-transfer>
+impl Transferable for WritableStream {
+ type Id = MessagePortId;
+ type Data = MessagePortImpl;
+
+ /// <https://streams.spec.whatwg.org/#ref-for-writablestream%E2%91%A0%E2%91%A4>
+ fn transfer(&self) -> Result<(MessagePortId, MessagePortImpl), ()> {
+ // If ! IsWritableStreamLocked(value) is true, throw a "DataCloneError" DOMException.
+ if self.is_locked() {
+ return Err(());
+ }
+
+ let global = self.global();
+ let realm = enter_realm(&*global);
+ let comp = InRealm::Entered(&realm);
+ let cx = GlobalScope::get_cx();
+ let can_gc = CanGc::note();
+
+ // Let port1 be a new MessagePort in the current Realm.
+ let port_1 = MessagePort::new(&global, can_gc);
+ global.track_message_port(&port_1, None);
+
+ // Let port2 be a new MessagePort in the current Realm.
+ let port_2 = MessagePort::new(&global, can_gc);
+ global.track_message_port(&port_2, None);
+
+ // Entangle port1 and port2.
+ global.entangle_ports(*port_1.message_port_id(), *port_2.message_port_id());
+
+ // Let readable be a new ReadableStream in the current Realm.
+ let readable = ReadableStream::new_with_proto(&global, None, can_gc);
+
+ // Perform ! SetUpCrossRealmTransformReadable(readable, port1).
+ readable.setup_cross_realm_transform_readable(cx, &port_1, can_gc);
+
+ // Let promise be ! ReadableStreamPipeTo(readable, value, false, false, false).
+ let promise = readable.pipe_to(cx, &global, self, false, false, false, comp, can_gc);
+
+ // Set promise.[[PromiseIsHandled]] to true.
+ promise.set_promise_is_handled();
+
+ // Set dataHolder.[[port]] to ! StructuredSerializeWithTransfer(port2, « port2 »).
+ port_2.transfer()
+ }
+
+ /// <https://streams.spec.whatwg.org/#ref-for-writablestream%E2%91%A0%E2%91%A4>
+ fn transfer_receive(
+ owner: &GlobalScope,
+ id: MessagePortId,
+ port_impl: MessagePortImpl,
+ ) -> Result<DomRoot<Self>, ()> {
+ let cx = GlobalScope::get_cx();
+ let can_gc = CanGc::note();
+
+ // Their transfer-receiving steps, given dataHolder and value, are:
+ // Note: dataHolder is used in `structuredclone.rs`, and value is created here.
+ let value = WritableStream::new_with_proto(owner, None, can_gc);
+
+ // Let deserializedRecord be ! StructuredDeserializeWithTransfer(dataHolder.[[port]], the current Realm).
+ // Done with the `Deserialize` derive of `MessagePortImpl`.
+
+ // Let port be deserializedRecord.[[Deserialized]].
+ let transferred_port = MessagePort::transfer_receive(owner, id, port_impl)?;
+
+ // Perform ! SetUpCrossRealmTransformWritable(value, port).
+ value.setup_cross_realm_transform_writable(cx, &transferred_port, can_gc);
+ Ok(value)
+ }
+
+ /// Note: we are relying on the port transfer, so the data returned here are related to the port.
+ fn serialized_storage(data: StructuredData<'_>) -> &mut Option<HashMap<Self::Id, Self::Data>> {
+ match data {
+ StructuredData::Reader(r) => &mut r.port_impls,
+ StructuredData::Writer(w) => &mut w.ports,
+ }
+ }
+
+ fn deserialized_storage(reader: &mut StructuredDataReader) -> &mut Option<Vec<DomRoot<Self>>> {
+ &mut reader.writable_streams
+ }
+}