diff --git a/components/script/dom/bindings/constructor.rs b/components/script/dom/bindings/constructor.rs index 4eb56a01d06..93c8c9514b1 100644 --- a/components/script/dom/bindings/constructor.rs +++ b/components/script/dom/bindings/constructor.rs @@ -397,14 +397,14 @@ pub(crate) unsafe fn call_html_constructor + DomObject>( .is_ok() } -pub(crate) unsafe fn call_default_constructor( +pub(crate) unsafe fn call_default_constructor( cx: JSContext, args: &CallArgs, - global: &GlobalScope, + global: &D::GlobalScope, proto_id: PrototypeList::ID, ctor_name: &str, creator: unsafe fn(JSContext, HandleObject, *mut ProtoOrIfaceArray), - constructor: impl FnOnce(JSContext, &CallArgs, &GlobalScope, HandleObject) -> bool, + constructor: impl FnOnce(JSContext, &CallArgs, &D::GlobalScope, HandleObject) -> bool, ) -> bool { if !args.is_constructing() { throw_constructor_without_new(cx, ctor_name); diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs index a0ce1eb70fe..7d276923c7c 100644 --- a/components/script/dom/bindings/conversions.rs +++ b/components/script/dom/bindings/conversions.rs @@ -58,7 +58,6 @@ use crate::dom::htmlcollection::HTMLCollection; use crate::dom::htmlformcontrolscollection::HTMLFormControlsCollection; use crate::dom::htmloptionscollection::HTMLOptionsCollection; use crate::dom::nodelist::NodeList; -use crate::dom::windowproxy::WindowProxy; impl ToJSValConvertible for Finite { #[inline] @@ -425,10 +424,10 @@ where /// Get a `DomRoot` for a WindowProxy accessible from a `HandleValue`. /// Caller is responsible for throwing a JS exception if needed in case of error. -pub(crate) unsafe fn windowproxy_from_handlevalue( +pub(crate) unsafe fn windowproxy_from_handlevalue( v: HandleValue, _cx: *mut JSContext, -) -> Result, ()> { +) -> Result, ()> { if !v.get().is_object() { return Err(()); } @@ -438,6 +437,6 @@ pub(crate) unsafe fn windowproxy_from_handlevalue( } let mut value = UndefinedValue(); GetProxyReservedSlot(object, 0, &mut value); - let ptr = value.to_private() as *const WindowProxy; + let ptr = value.to_private() as *const D::WindowProxy; Ok(DomRoot::from_ref(&*ptr)) } diff --git a/components/script/dom/bindings/import.rs b/components/script/dom/bindings/import.rs index 756e8ef9f39..c24de0363a1 100644 --- a/components/script/dom/bindings/import.rs +++ b/components/script/dom/bindings/import.rs @@ -26,7 +26,7 @@ pub(crate) mod base { ChannelInterpretationValues, }; pub(crate) use crate::dom::bindings::codegen::DomTypes::DomTypes; - pub(crate) use crate::dom::bindings::codegen::UnionTypes; + pub(crate) use crate::dom::bindings::codegen::{GenericUnionTypes, UnionTypes}; pub(crate) use crate::dom::bindings::conversions::{ root_from_handlevalue, ConversionBehavior, ConversionResult, FromJSValConvertible, StringificationBehavior, ToJSValConvertible, @@ -35,14 +35,15 @@ pub(crate) mod base { pub(crate) use crate::dom::bindings::error::{throw_dom_exception, Fallible}; pub(crate) use crate::dom::bindings::num::Finite; pub(crate) use crate::dom::bindings::proxyhandler::CrossOriginProperties; - pub(crate) use crate::dom::bindings::reflector::{DomGlobal, DomObject}; + pub(crate) use crate::dom::bindings::reflector::{DomGlobalGeneric, DomObject}; pub(crate) use crate::dom::bindings::root::DomRoot; pub(crate) use crate::dom::bindings::str::{ByteString, DOMString, USVString}; pub(crate) use crate::dom::bindings::trace::RootedTraceableBox; pub(crate) use crate::dom::bindings::utils::{ - get_dictionary_property, set_dictionary_property, ThreadUnsafeOnceLock, + get_dictionary_property, set_dictionary_property, DomHelpers, ThreadUnsafeOnceLock, }; - pub(crate) use crate::dom::globalscope::GlobalScope; + pub(crate) use crate::dom::globalscope::{GlobalScope, GlobalScopeHelpers}; + pub(crate) use crate::dom::promise::PromiseHelpers; pub(crate) use crate::script_runtime::JSContext as SafeJSContext; } diff --git a/components/script/dom/bindings/iterable.rs b/components/script/dom/bindings/iterable.rs index dd9b3b13405..4b932dfc262 100644 --- a/components/script/dom/bindings/iterable.rs +++ b/components/script/dom/bindings/iterable.rs @@ -7,6 +7,7 @@ //! Implementation of `iterable<...>` and `iterable<..., ...>` WebIDL declarations. use std::cell::Cell; +use std::marker::PhantomData; use std::ptr; use std::ptr::NonNull; @@ -15,18 +16,20 @@ use js::conversions::ToJSValConvertible; use js::jsapi::{Heap, JSObject}; use js::jsval::UndefinedValue; use js::rust::{HandleObject, HandleValue, MutableHandleObject}; +use script_bindings::conversions::IDLInterface; +use script_bindings::utils::DOMClass; use crate::dom::bindings::codegen::Bindings::IterableIteratorBinding::{ IterableKeyAndValueResult, IterableKeyOrValueResult, }; use crate::dom::bindings::error::Fallible; use crate::dom::bindings::reflector::{ - reflect_dom_object, DomGlobal, DomObjectIteratorWrap, DomObjectWrap, Reflector, + reflect_dom_object, DomGlobalGeneric, DomObjectIteratorWrap, DomObjectWrap, Reflector, }; use crate::dom::bindings::root::{Dom, DomRoot, Root}; -use crate::dom::bindings::trace::{JSTraceable, RootedTraceableBox}; -use crate::dom::globalscope::GlobalScope; +use crate::dom::bindings::trace::{JSTraceable, NoTrace, RootedTraceableBox}; use crate::script_runtime::{CanGc, JSContext}; +use crate::DomTypes; /// The values that an iterator will iterate over. #[derive(JSTraceable, MallocSizeOf)] @@ -55,14 +58,41 @@ pub(crate) trait Iterable { /// An iterator over the iterable entries of a given DOM interface. #[dom_struct] -pub(crate) struct IterableIterator { +pub(crate) struct IterableIterator< + D: DomTypes, + T: DomObjectIteratorWrap + JSTraceable + Iterable + DomGlobalGeneric, +> { reflector: Reflector, iterable: Dom, type_: IteratorType, index: Cell, + _marker: NoTrace>, } -impl IterableIterator { +impl + JSTraceable + Iterable> IterableIterator { + pub fn global(&self) -> DomRoot { + >::global(self) + } +} + +impl< + D: DomTypes, + T: DomObjectIteratorWrap + + JSTraceable + + Iterable + + DomGlobalGeneric + + IDLInterface + + IteratorDerives, + > IDLInterface for IterableIterator +{ + fn derives(class: &'static DOMClass) -> bool { + ::derives(class) + } +} + +impl + JSTraceable + Iterable + DomGlobalGeneric> + IterableIterator +{ /// Create a new iterator instance for the provided iterable DOM interface. pub(crate) fn new(iterable: &T, type_: IteratorType) -> DomRoot { let iterator = Box::new(IterableIterator { @@ -70,6 +100,7 @@ impl IterableIterator { type_, iterable: Dom::from_ref(iterable), index: Cell::new(0), + _marker: NoTrace(PhantomData), }); reflect_dom_object(iterator, &*iterable.global(), CanGc::note()) } @@ -119,16 +150,26 @@ impl IterableIterator { } } -impl DomObjectWrap for IterableIterator { +impl + JSTraceable + Iterable + DomGlobalGeneric> + DomObjectWrap for IterableIterator +{ const WRAP: unsafe fn( JSContext, - &GlobalScope, + &D::GlobalScope, Option, Box, CanGc, ) -> Root> = T::ITER_WRAP; } +/// A version of the [IDLInterface] trait that is specific to types that have +/// iterators defined for them. This allows the `script` crate to define the +/// derives check for the concrete interface type, while the [IteratableIterator] +/// type defined in this module can be parameterized over an unknown generic. +pub trait IteratorDerives { + fn derives(class: &'static DOMClass) -> bool; +} + fn dict_return( cx: JSContext, mut result: MutableHandleObject, diff --git a/components/script/dom/bindings/mod.rs b/components/script/dom/bindings/mod.rs index ee934ca2af1..e37cb3e485c 100644 --- a/components/script/dom/bindings/mod.rs +++ b/components/script/dom/bindings/mod.rs @@ -179,9 +179,16 @@ pub(crate) mod codegen { include!(concat!(env!("BINDINGS_OUT_DIR"), "/DomTypes.rs")); } #[allow(dead_code)] - pub(crate) mod Bindings { + pub(crate) mod GenericBindings { include!(concat!(env!("BINDINGS_OUT_DIR"), "/Bindings/mod.rs")); } + #[allow(dead_code)] + pub(crate) mod Bindings { + include!(concat!( + env!("BINDINGS_OUT_DIR"), + "/ConcreteBindings/mod.rs" + )); + } pub(crate) mod InterfaceObjectMap { include!(concat!(env!("BINDINGS_OUT_DIR"), "/InterfaceObjectMap.rs")); pub(crate) use script_bindings::codegen::Globals::Globals; @@ -206,6 +213,10 @@ pub(crate) mod codegen { clippy::upper_case_acronyms, clippy::enum_variant_names )] + pub(crate) mod GenericUnionTypes { + include!(concat!(env!("BINDINGS_OUT_DIR"), "/GenericUnionTypes.rs")); + } + #[allow(dead_code)] pub(crate) mod UnionTypes { include!(concat!(env!("BINDINGS_OUT_DIR"), "/UnionTypes.rs")); } diff --git a/components/script/dom/bindings/reflector.rs b/components/script/dom/bindings/reflector.rs index 1f3b399d10c..210eb5127d0 100644 --- a/components/script/dom/bindings/reflector.rs +++ b/components/script/dom/bindings/reflector.rs @@ -10,59 +10,74 @@ use crate::dom::bindings::conversions::DerivedFrom; use crate::dom::bindings::iterable::{Iterable, IterableIterator}; use crate::dom::bindings::root::{Dom, DomRoot, Root}; use crate::dom::bindings::trace::JSTraceable; -use crate::dom::globalscope::GlobalScope; +use crate::dom::globalscope::{GlobalScope, GlobalScopeHelpers}; use crate::realms::AlreadyInRealm; use crate::script_runtime::{CanGc, JSContext}; +use crate::DomTypes; /// Create the reflector for a new DOM object and yield ownership to the /// reflector. -pub(crate) fn reflect_dom_object(obj: Box, global: &U, can_gc: CanGc) -> DomRoot +pub(crate) fn reflect_dom_object(obj: Box, global: &U, can_gc: CanGc) -> DomRoot where - T: DomObject + DomObjectWrap, - U: DerivedFrom, + D: DomTypes, + T: DomObject + DomObjectWrap, + U: DerivedFrom, { let global_scope = global.upcast(); - unsafe { T::WRAP(GlobalScope::get_cx(), global_scope, None, obj, can_gc) } + unsafe { T::WRAP(D::GlobalScope::get_cx(), global_scope, None, obj, can_gc) } } -pub(crate) fn reflect_dom_object_with_proto( +pub(crate) fn reflect_dom_object_with_proto( obj: Box, global: &U, proto: Option, can_gc: CanGc, ) -> DomRoot where - T: DomObject + DomObjectWrap, - U: DerivedFrom, + D: DomTypes, + T: DomObject + DomObjectWrap, + U: DerivedFrom, { let global_scope = global.upcast(); - unsafe { T::WRAP(GlobalScope::get_cx(), global_scope, proto, obj, can_gc) } + unsafe { T::WRAP(D::GlobalScope::get_cx(), global_scope, proto, obj, can_gc) } } -pub trait DomGlobal: DomObject { +pub(crate) trait DomGlobalGeneric: DomObject { /// Returns the [`GlobalScope`] of the realm that the [`DomObject`] was created in. If this /// object is a `Node`, this will be different from it's owning `Document` if adopted by. For /// `Node`s it's almost always better to use `NodeTraits::owning_global`. - fn global(&self) -> DomRoot + fn global(&self) -> DomRoot where Self: Sized, { - let realm = AlreadyInRealm::assert_for_cx(GlobalScope::get_cx()); - GlobalScope::from_reflector(self, &realm) + let realm = AlreadyInRealm::assert_for_cx(D::GlobalScope::get_cx()); + D::GlobalScope::from_reflector(self, &realm) } } -impl DomGlobal for T {} +impl DomGlobalGeneric for T {} + +pub(crate) trait DomGlobal { + fn global(&self) -> DomRoot; +} + +impl> DomGlobal for T { + fn global(&self) -> DomRoot { + >::global(self) + } +} pub(crate) use script_bindings::reflector::{DomObject, MutDomObject, Reflector}; /// A trait to provide a function pointer to wrap function for DOM objects. -pub(crate) trait DomObjectWrap: Sized + DomObject { +pub(crate) trait DomObjectWrap: + Sized + DomObject + DomGlobalGeneric +{ /// Function pointer to the general wrap function type #[allow(clippy::type_complexity)] const WRAP: unsafe fn( JSContext, - &GlobalScope, + &D::GlobalScope, Option, Box, CanGc, @@ -71,14 +86,16 @@ pub(crate) trait DomObjectWrap: Sized + DomObject { /// A trait to provide a function pointer to wrap function for /// DOM iterator interfaces. -pub(crate) trait DomObjectIteratorWrap: DomObjectWrap + JSTraceable + Iterable { +pub(crate) trait DomObjectIteratorWrap: + DomObjectWrap + JSTraceable + Iterable +{ /// Function pointer to the wrap function for `IterableIterator` #[allow(clippy::type_complexity)] const ITER_WRAP: unsafe fn( JSContext, - &GlobalScope, + &D::GlobalScope, Option, - Box>, + Box>, CanGc, - ) -> Root>>; + ) -> Root>>; } diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index b1f5c395531..631ba43c4d5 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -37,15 +37,18 @@ use js::rust::{ use js::JS_CALLEE; use crate::dom::bindings::codegen::InterfaceObjectMap; -use crate::dom::bindings::codegen::PrototypeList::PROTO_OR_IFACE_LENGTH; +use crate::dom::bindings::codegen::PrototypeList::{self, PROTO_OR_IFACE_LENGTH}; +use crate::dom::bindings::constructor::call_html_constructor; use crate::dom::bindings::conversions::{ - jsstring_to_str, private_from_proto_check, PrototypeCheck, + jsstring_to_str, private_from_proto_check, DerivedFrom, PrototypeCheck, }; -use crate::dom::bindings::error::throw_invalid_this; +use crate::dom::bindings::error::{throw_dom_exception, throw_invalid_this, Error}; +use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::str::DOMString; use crate::dom::bindings::trace::trace_object; use crate::dom::windowproxy::WindowProxyHandler; -use crate::script_runtime::JSContext as SafeJSContext; +use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; +use crate::DomTypes; /// A OnceLock wrapping a type that is not considered threadsafe by the Rust compiler, but /// will be used in a threadsafe manner (it will not be mutated, after being initialized). @@ -660,3 +663,40 @@ pub(crate) unsafe fn exception_to_promise(cx: *mut JSContext, rval: RawMutableHa false } } + +/// Operations that must be invoked from the generated bindings. +pub(crate) trait DomHelpers { + fn throw_dom_exception(cx: SafeJSContext, global: &D::GlobalScope, result: Error); + + unsafe fn call_html_constructor + DomObject>( + cx: SafeJSContext, + args: &CallArgs, + global: &D::GlobalScope, + proto_id: crate::dom::bindings::codegen::PrototypeList::ID, + creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray), + can_gc: CanGc, + ) -> bool; +} + +impl DomHelpers for crate::DomTypeHolder { + fn throw_dom_exception( + cx: SafeJSContext, + global: &::GlobalScope, + result: Error, + ) { + throw_dom_exception(cx, global, result) + } + + unsafe fn call_html_constructor< + T: DerivedFrom<::Element> + DomObject, + >( + cx: SafeJSContext, + args: &CallArgs, + global: &::GlobalScope, + proto_id: PrototypeList::ID, + creator: unsafe fn(SafeJSContext, HandleObject, *mut ProtoOrIfaceArray), + can_gc: CanGc, + ) -> bool { + call_html_constructor::(cx, args, global, proto_id, creator, can_gc) + } +} diff --git a/components/script/dom/bytelengthqueuingstrategy.rs b/components/script/dom/bytelengthqueuingstrategy.rs index dd22c076820..b4916879c7f 100644 --- a/components/script/dom/bytelengthqueuingstrategy.rs +++ b/components/script/dom/bytelengthqueuingstrategy.rs @@ -14,8 +14,9 @@ use super::bindings::codegen::Bindings::FunctionBinding::Function; use super::bindings::codegen::Bindings::QueuingStrategyBinding::{ ByteLengthQueuingStrategyMethods, QueuingStrategyInit, }; -use super::bindings::import::module::{DomGlobal, DomRoot, Fallible, Reflector}; -use super::bindings::reflector::reflect_dom_object_with_proto; +use super::bindings::error::Fallible; +use super::bindings::reflector::{reflect_dom_object_with_proto, DomGlobal, Reflector}; +use super::bindings::root::DomRoot; use super::types::GlobalScope; use crate::dom::bindings::import::module::get_dictionary_property; use crate::native_fn; diff --git a/components/script/dom/countqueuingstrategy.rs b/components/script/dom/countqueuingstrategy.rs index fc9618f6c19..40801ba05c8 100644 --- a/components/script/dom/countqueuingstrategy.rs +++ b/components/script/dom/countqueuingstrategy.rs @@ -13,8 +13,9 @@ use super::bindings::codegen::Bindings::FunctionBinding::Function; use super::bindings::codegen::Bindings::QueuingStrategyBinding::{ CountQueuingStrategyMethods, QueuingStrategy, QueuingStrategyInit, QueuingStrategySize, }; -use super::bindings::import::module::{DomGlobal, DomRoot, Error, Fallible, Reflector}; -use super::bindings::reflector::reflect_dom_object_with_proto; +use super::bindings::error::{Error, Fallible}; +use super::bindings::reflector::{reflect_dom_object_with_proto, DomGlobal, Reflector}; +use super::bindings::root::DomRoot; use super::types::GlobalScope; use crate::script_runtime::CanGc; use crate::{native_fn, native_raw_obj_fn}; diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 951bafc0b63..b16e404ccbd 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -3331,9 +3331,23 @@ unsafe fn global_scope_from_global_static(global: *mut JSObject) -> DomRoot { unsafe fn from_context(cx: *mut JSContext, realm: InRealm) -> DomRoot; + fn get_cx() -> SafeJSContext; + unsafe fn from_object(obj: *mut JSObject) -> DomRoot; + fn from_reflector( + reflector: &impl DomObject, + realm: &AlreadyInRealm, + ) -> DomRoot; + + unsafe fn from_object_maybe_wrapped( + obj: *mut JSObject, + cx: *mut JSContext, + ) -> DomRoot; + + fn origin(&self) -> &MutableOrigin; } #[allow(unsafe_code)] @@ -3341,4 +3355,24 @@ impl GlobalScopeHelpers for GlobalScope { unsafe fn from_context(cx: *mut JSContext, realm: InRealm) -> DomRoot { GlobalScope::from_context(cx, realm) } + + fn get_cx() -> SafeJSContext { + GlobalScope::get_cx() + } + + unsafe fn from_object(obj: *mut JSObject) -> DomRoot { + GlobalScope::from_object(obj) + } + + fn from_reflector(reflector: &impl DomObject, realm: &AlreadyInRealm) -> DomRoot { + GlobalScope::from_reflector(reflector, realm) + } + + unsafe fn from_object_maybe_wrapped(obj: *mut JSObject, cx: *mut JSContext) -> DomRoot { + GlobalScope::from_object_maybe_wrapped(obj, cx) + } + + fn origin(&self) -> &MutableOrigin { + GlobalScope::origin(self) + } } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 225334c2710..320a4b1b02e 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -1925,7 +1925,7 @@ fn as_uintptr(t: &T) -> uintptr_t { impl Node { pub(crate) fn reflect_node(node: Box, document: &Document, can_gc: CanGc) -> DomRoot where - N: DerivedFrom + DomObject + DomObjectWrap, + N: DerivedFrom + DomObject + DomObjectWrap, { Self::reflect_node_with_proto(node, document, None, can_gc) } @@ -1937,7 +1937,7 @@ impl Node { can_gc: CanGc, ) -> DomRoot where - N: DerivedFrom + DomObject + DomObjectWrap, + N: DerivedFrom + DomObject + DomObjectWrap, { let window = document.window(); reflect_dom_object_with_proto(node, window, proto, can_gc) diff --git a/components/script/dom/promise.rs b/components/script/dom/promise.rs index 46fc9c88dba..36abbfdc35f 100644 --- a/components/script/dom/promise.rs +++ b/components/script/dom/promise.rs @@ -384,3 +384,22 @@ fn create_native_handler_function( obj.get() } } + +/// Operations that must be invoked from the generated bindings. +pub(crate) trait PromiseHelpers { + fn new_resolved( + global: &D::GlobalScope, + cx: SafeJSContext, + value: impl ToJSValConvertible, + ) -> Rc; +} + +impl PromiseHelpers for Promise { + fn new_resolved( + global: &GlobalScope, + cx: SafeJSContext, + value: impl ToJSValConvertible, + ) -> Rc { + Promise::new_resolved(global, cx, value) + } +} diff --git a/components/script/dom/readablestream.rs b/components/script/dom/readablestream.rs index 1c1eceab0ba..019a290c96d 100644 --- a/components/script/dom/readablestream.rs +++ b/components/script/dom/readablestream.rs @@ -26,7 +26,7 @@ use crate::dom::bindings::codegen::Bindings::UnderlyingSourceBinding::Underlying use crate::dom::bindings::conversions::{ConversionBehavior, ConversionResult}; use crate::dom::bindings::error::Error; use crate::dom::bindings::import::module::Fallible; -use crate::dom::bindings::import::module::UnionTypes::ReadableStreamDefaultReaderOrReadableStreamBYOBReader as ReadableStreamReader; +use crate::dom::bindings::codegen::UnionTypes::ReadableStreamDefaultReaderOrReadableStreamBYOBReader as ReadableStreamReader; use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto}; use crate::dom::bindings::root::{DomRoot, MutNullableDom, Dom}; use crate::dom::bindings::trace::RootedTraceableBox; @@ -666,13 +666,13 @@ impl ReadableStream { // If stream.[[state]] is "closed", return a promise resolved with undefined. if self.is_closed() { - let promise = Promise::new(&self.reflector_.global(), can_gc); + let promise = Promise::new(&self.global(), can_gc); promise.resolve_native(&()); return promise; } // If stream.[[state]] is "errored", return a promise rejected with stream.[[storedError]]. if self.is_errored() { - let promise = Promise::new(&self.reflector_.global(), can_gc); + let promise = Promise::new(&self.global(), can_gc); unsafe { let cx = GlobalScope::get_cx(); rooted!(in(*cx) let mut rval = UndefinedValue()); @@ -708,7 +708,7 @@ impl ReadableStream { // Create a new promise, // and setup a handler in order to react to the fulfillment of sourceCancelPromise. - let global = self.reflector_.global(); + let global = self.global(); let result_promise = Promise::new(&global, can_gc); let fulfillment_handler = Box::new(SourceCancelPromiseFulfillmentHandler { result: result_promise.clone(), @@ -784,7 +784,7 @@ impl ReadableStream { // Let reason2 be undefined. let reason_2 = Rc::new(Heap::boxed(UndefinedValue())); // Let cancelPromise be a new promise. - let cancel_promise = Promise::new(&self.reflector_.global(), can_gc); + let cancel_promise = Promise::new(&self.global(), can_gc); let tee_source_1 = DefaultTeeUnderlyingSource::new( &reader, @@ -824,7 +824,7 @@ impl ReadableStream { // Set branch_1 to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancel1Algorithm). let branch_1 = create_readable_stream( - &self.reflector_.global(), + &self.global(), underlying_source_type_branch_1, QueuingStrategy::empty(), can_gc, @@ -834,7 +834,7 @@ impl ReadableStream { // Set branch_2 to ! CreateReadableStream(startAlgorithm, pullAlgorithm, cancel2Algorithm). let branch_2 = create_readable_stream( - &self.reflector_.global(), + &self.global(), underlying_source_type_branch_2, QueuingStrategy::empty(), can_gc, diff --git a/components/script/dom/readablestreamdefaultcontroller.rs b/components/script/dom/readablestreamdefaultcontroller.rs index e264c0e3569..327b1ee71e4 100644 --- a/components/script/dom/readablestreamdefaultcontroller.rs +++ b/components/script/dom/readablestreamdefaultcontroller.rs @@ -19,7 +19,7 @@ use super::bindings::root::Dom; use crate::dom::bindings::buffer_source::create_buffer_source; use crate::dom::bindings::callback::ExceptionHandling; use crate::dom::bindings::codegen::Bindings::ReadableStreamDefaultControllerBinding::ReadableStreamDefaultControllerMethods; -use crate::dom::bindings::import::module::UnionTypes::ReadableStreamDefaultControllerOrReadableByteStreamController as Controller; +use crate::dom::bindings::codegen::UnionTypes::ReadableStreamDefaultControllerOrReadableByteStreamController as Controller; use crate::dom::bindings::import::module::{throw_dom_exception, Error, Fallible}; use crate::dom::bindings::reflector::{reflect_dom_object, DomGlobal, Reflector}; use crate::dom::bindings::root::{DomRoot, MutNullableDom}; diff --git a/components/script/dom/readablestreamdefaultreader.rs b/components/script/dom/readablestreamdefaultreader.rs index bb82593caa9..08955cba378 100644 --- a/components/script/dom/readablestreamdefaultreader.rs +++ b/components/script/dom/readablestreamdefaultreader.rs @@ -374,7 +374,7 @@ impl ReadableStreamDefaultReaderMethods for ReadableStream return Promise::new_rejected(&self.global(), cx, error.handle()); } // Let promise be a new promise. - let promise = Promise::new(&self.reflector_.global(), can_gc); + let promise = Promise::new(&self.global(), can_gc); // Let readRequest be a new read request with the following items: // chunk steps, given chunk diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs index 46941148ead..c21bb26a55e 100644 --- a/components/script/webdriver_handlers.rs +++ b/components/script/webdriver_handlers.rs @@ -1069,14 +1069,15 @@ pub(crate) fn handle_get_property( property.handle_mut(), ) } { - Ok(_) => match unsafe { - jsval_to_webdriver(*cx, &node.reflector().global(), property.handle()) - } { - Ok(property) => property, - Err(_) => WebDriverJSValue::Undefined, + Ok(_) => { + match unsafe { jsval_to_webdriver(*cx, &node.global(), property.handle()) } + { + Ok(property) => property, + Err(_) => WebDriverJSValue::Undefined, + } }, Err(error) => { - throw_dom_exception(cx, &node.reflector().global(), error); + throw_dom_exception(cx, &node.global(), error); WebDriverJSValue::Undefined }, } diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf index 53fa5e1b5a9..ae6ee4a5617 100644 --- a/components/script_bindings/codegen/Bindings.conf +++ b/components/script_bindings/codegen/Bindings.conf @@ -414,6 +414,7 @@ DOMInterfaces = { 'Promise': { 'spiderMonkeyInterface': True, + 'additionalTraits': ["crate::dom::promise::PromiseHelpers"] }, 'Range': { diff --git a/components/script_bindings/codegen/CodegenRust.py b/components/script_bindings/codegen/CodegenRust.py index 61aa4b3d333..b6c223ff53a 100644 --- a/components/script_bindings/codegen/CodegenRust.py +++ b/components/script_bindings/codegen/CodegenRust.py @@ -16,15 +16,18 @@ import functools from WebIDL import ( BuiltinTypes, + IDLArgument, IDLBuiltinType, IDLDefaultDictionaryValue, IDLEmptySequenceValue, + IDLInterface, IDLInterfaceMember, IDLNullableType, IDLNullValue, IDLObject, IDLPromiseType, IDLType, + IDLTypedefType, IDLUndefinedValue, IDLWrapperType, ) @@ -60,6 +63,42 @@ RUST_KEYWORDS = {"abstract", "alignof", "as", "become", "box", "break", "const", "use", "virtual", "where", "while", "yield"} +def genericsForType(t): + if containsDomInterface(t): + return ("", "") + return ("", "") + + +def isDomInterface(t, logging=False): + while isinstance(t, IDLNullableType) or isinstance(t, IDLWrapperType): + t = t.inner + if isinstance(t, IDLInterface): + return True + if t.isCallback(): + return False + return t.isInterface() and (t.isGeckoInterface() or (t.isSpiderMonkeyInterface() and not t.isBufferSource())) + + +def containsDomInterface(t, logging=False): + if isinstance(t, IDLArgument): + t = t.type + if isinstance(t, IDLTypedefType): + t = t.innerType + while isinstance(t, IDLNullableType) or isinstance(t, IDLWrapperType): + t = t.inner + if t.isEnum(): + return False + if isDomInterface(t): + return True + if t.isUnion(): + return any(map(lambda x: containsDomInterface(x), t.flatMemberTypes)) + if t.isDictionary(): + return any(map(lambda x: containsDomInterface(x), t.members)) or (t.parent and containsDomInterface(t.parent)) + if t.isSequence(): + return containsDomInterface(t.inner) + return False + + def toStringBool(arg): return str(not not arg).lower() @@ -537,7 +576,8 @@ def typeIsSequenceOrHasSequenceMember(type): def union_native_type(t): name = t.unroll().name - return f'UnionTypes::{name}' + generic = "" if containsDomInterface(t) else "" + return f'GenericUnionTypes::{name}{generic}' # Unfortunately, .capitalize() on a string will lowercase things inside the @@ -801,21 +841,21 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, { // Scope for our JSAutoRealm. rooted!(in(*cx) let globalObj = CurrentGlobalOrNull(*cx)); - let promiseGlobal = GlobalScope::from_object_maybe_wrapped(globalObj.handle().get(), *cx); + let promiseGlobal = D::GlobalScope::from_object_maybe_wrapped(globalObj.handle().get(), *cx); rooted!(in(*cx) let mut valueToResolve = $${val}.get()); if !JS_WrapValue(*cx, valueToResolve.handle_mut()) { $*{exceptionCode} } - Promise::new_resolved(&promiseGlobal, cx, valueToResolve.handle()) + D::Promise::new_resolved(&promiseGlobal, cx, valueToResolve.handle()) } """, exceptionCode=exceptionCode) if isArgument: - declType = CGGeneric("&Promise") + declType = CGGeneric("&D::Promise") else: - declType = CGGeneric("Rc") + declType = CGGeneric("Rc") return handleOptional(templateBody, declType, handleDefault("None")) if type.isGeckoInterface(): @@ -844,7 +884,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, elif isArgument: descriptorType = descriptor.argumentType elif descriptor.interface.identifier.name == "WindowProxy": - conversionFunction = "windowproxy_from_handlevalue" + conversionFunction = "windowproxy_from_handlevalue::" if failureCode is None: unwrapFailureCode = ( @@ -1144,8 +1184,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, assert not type.nullable() or (isMember and isMember != "Dictionary") typeName = f"{CGDictionary.makeModuleName(type.inner)}::{CGDictionary.makeDictionaryName(type.inner)}" + if containsDomInterface(type): + typeName += "" declType = CGGeneric(typeName) - empty = f"{typeName}::empty()" + empty = f"{typeName.replace('', '')}::empty()" if type_needs_tracing(type): declType = CGTemplatedType("RootedTraceableBox", declType) @@ -1456,7 +1498,7 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): return result if returnType.isPromise(): assert not returnType.nullable() - return CGGeneric("Rc") + return CGGeneric("Rc") if returnType.isGeckoInterface(): descriptor = descriptorProvider.getDescriptor( returnType.unroll().inner.identifier.name) @@ -1491,7 +1533,8 @@ def getRetvalDeclarationForType(returnType, descriptorProvider): if returnType.isDictionary(): nullable = returnType.nullable() dictName = returnType.inner.name if nullable else returnType.name - result = CGGeneric(dictName) + generic = "" if containsDomInterface(returnType) else "" + result = CGGeneric(f"{dictName}{generic}") if type_needs_tracing(returnType): result = CGWrapper(result, pre="RootedTraceableBox<", post=">") if nullable: @@ -2496,7 +2539,7 @@ static NAMESPACE_OBJECT_CLASS: NamespaceObjectClass = unsafe {{ }}; """ if self.descriptor.interface.ctor(): - constructorBehavior = f"InterfaceConstructorBehavior::call({CONSTRUCT_HOOK_NAME})" + constructorBehavior = f"InterfaceConstructorBehavior::call({CONSTRUCT_HOOK_NAME}::)" else: constructorBehavior = "InterfaceConstructorBehavior::throw()" name = self.descriptor.interface.identifier.name @@ -2504,16 +2547,9 @@ static NAMESPACE_OBJECT_CLASS: NamespaceObjectClass = unsafe {{ return f""" static INTERFACE_OBJECT_CLASS: ThreadUnsafeOnceLock = ThreadUnsafeOnceLock::new(); -pub(crate) fn init_interface_object() {{ +pub(crate) fn init_interface_object() {{ INTERFACE_OBJECT_CLASS.set(NonCallbackInterfaceObjectClass::new( - {{ - // Intermediate `const` because as of nightly-2018-10-05, - // rustc is conservative in promotion to `'static` of the return values of `const fn`s: - // https://github.com/rust-lang/rust/issues/54846 - // https://github.com/rust-lang/rust/pull/53851 - const BEHAVIOR: InterfaceConstructorBehavior = {constructorBehavior}; - &BEHAVIOR - }}, + Box::leak(Box::new({constructorBehavior})), {representation}, PrototypeList::ID::{name}, {self.descriptor.prototypeDepth}, @@ -2645,6 +2681,7 @@ def UnionTypes(descriptors, dictionaries, callbacks, typedefs, config): def DomTypes(descriptors, descriptorProvider, dictionaries, callbacks, typedefs, config): traits = [ + "crate::dom::bindings::utils::DomHelpers", "js::rust::Trace", "malloc_size_of::MallocSizeOf", "Sized", @@ -2682,7 +2719,8 @@ def DomTypes(descriptors, descriptorProvider, dictionaries, callbacks, typedefs, traits += [f"crate::dom::bindings::like::Setlike"] if iterableDecl.hasKeyType(): traits += [ - "crate::dom::bindings::reflector::DomObjectIteratorWrap", + "crate::dom::bindings::reflector::DomObjectIteratorWrap", + "crate::dom::bindings::iterable::IteratorDerives", ] if descriptor.weakReferenceable: @@ -2693,7 +2731,8 @@ def DomTypes(descriptors, descriptorProvider, dictionaries, callbacks, typedefs, "js::conversions::ToJSValConvertible", "crate::dom::bindings::reflector::MutDomObject", "crate::dom::bindings::reflector::DomObject", - "crate::dom::bindings::reflector::DomGlobal", + "crate::dom::bindings::reflector::DomGlobalGeneric", + "malloc_size_of::MallocSizeOf", ] if descriptor.register: @@ -2708,7 +2747,7 @@ def DomTypes(descriptors, descriptorProvider, dictionaries, callbacks, typedefs, ] if descriptor.concrete and not descriptor.isGlobal(): - traits += ["crate::dom::bindings::reflector::DomObjectWrap"] + traits += ["crate::dom::bindings::reflector::DomObjectWrap"] if not descriptor.interface.isCallback() and not descriptor.interface.isIteratorInterface(): nonConstMembers = [m for m in descriptor.interface.members if not m.isConst()] @@ -3011,7 +3050,7 @@ class CGWrapMethod(CGAbstractMethod): assert not descriptor.interface.isCallback() assert not descriptor.isGlobal() args = [Argument('SafeJSContext', 'cx'), - Argument('&GlobalScope', 'scope'), + Argument('&D::GlobalScope', 'scope'), Argument('Option', 'given_proto'), Argument(f"Box<{descriptor.concreteType}>", 'object'), Argument('CanGc', '_can_gc')] @@ -3033,7 +3072,7 @@ class CGWrapMethod(CGAbstractMethod): create = f""" let handler: *const libc::c_void = - RegisterBindings::proxy_handlers::{self.descriptor.concreteType} + RegisterBindings::proxy_handlers::{self.descriptor.interface.identifier.name} .load(std::sync::atomic::Ordering::Acquire); rooted!(in(*cx) let obj = NewProxyObject( *cx, @@ -3088,7 +3127,7 @@ assert!(((*get_object_class(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0); let _ac = JSAutoRealm::new(*cx, scope.get()); rooted!(in(*cx) let mut canonical_proto = ptr::null_mut::()); -GetProtoObject(cx, scope, canonical_proto.handle_mut()); +GetProtoObject::(cx, scope, canonical_proto.handle_mut()); assert!(!canonical_proto.is_null()); {create} @@ -3128,7 +3167,7 @@ class CGWrapGlobalMethod(CGAbstractMethod): return CGGeneric(f""" let raw = Root::new(MaybeUnreflectedDom::from_box(object)); -let origin = (*raw.as_ptr()).upcast::().origin(); +let origin = (*raw.as_ptr()).upcast::().origin(); rooted!(in(*cx) let mut obj = ptr::null_mut::()); create_global_object( @@ -3144,7 +3183,7 @@ let root = raw.reflect_with(obj.get()); let _ac = JSAutoRealm::new(*cx, obj.get()); rooted!(in(*cx) let mut canonical_proto = ptr::null_mut::()); -GetProtoObject(cx, obj.handle(), canonical_proto.handle_mut()); +GetProtoObject::(cx, obj.handle(), canonical_proto.handle_mut()); assert!(JS_SetPrototype(*cx, obj.handle(), canonical_proto.handle())); let mut immutable = false; assert!(JS_SetImmutablePrototype(*cx, obj.handle(), &mut immutable)); @@ -3174,13 +3213,13 @@ class CGIDLInterface(CGThing): def define(self): interface = self.descriptor.interface - name = self.descriptor.concreteType + name = interface.identifier.name if (interface.getUserData("hasConcreteDescendant", False) or interface.getUserData("hasProxyDescendant", False)): depth = self.descriptor.prototypeDepth check = f"class.interface_chain[{depth}] == PrototypeList::ID::{name}" elif self.descriptor.proxy: - check = "ptr::eq(class, &Class)" + check = "ptr::eq(class, unsafe { Class.get() })" else: check = "ptr::eq(class, unsafe { &Class.get().dom_class })" return f""" @@ -3193,6 +3232,28 @@ impl IDLInterface for {name} {{ """ +class CGIteratorDerives(CGThing): + """ + Class for codegen of an implementation of the IteratorDerives trait. + """ + def __init__(self, descriptor): + CGThing.__init__(self) + self.descriptor = descriptor + + def define(self): + iterableInterface = self.descriptor.interface.iterableInterface + name = iterableInterface.identifier.name + bindingModule = f"crate::dom::bindings::codegen::Bindings::{toBindingPath(self.descriptor)}" + return f""" +impl crate::dom::bindings::iterable::IteratorDerives for {name} {{ + #[inline] + fn derives(class: &'static DOMClass) -> bool {{ + unsafe {{ ptr::eq(class, &{bindingModule}::Class.get().dom_class) }} + }} +}} +""" + + class CGDomObjectWrap(CGThing): """ Class for codegen of an implementation of the DomObjectWrap trait. @@ -3202,10 +3263,9 @@ class CGDomObjectWrap(CGThing): self.descriptor = descriptor def define(self): - name = self.descriptor.concreteType - name = f"dom::{name.lower()}::{name}" + ifaceName = self.descriptor.interface.identifier.name return f""" -impl DomObjectWrap for {name} {{ +impl DomObjectWrap for {firstCap(ifaceName)} {{ const WRAP: unsafe fn( SafeJSContext, &GlobalScope, @@ -3229,14 +3289,14 @@ class CGDomObjectIteratorWrap(CGThing): assert self.descriptor.interface.isIteratorInterface() name = self.descriptor.interface.iterableInterface.identifier.name return f""" -impl DomObjectIteratorWrap for {name} {{ +impl DomObjectIteratorWrap for {name} {{ const ITER_WRAP: unsafe fn( SafeJSContext, &GlobalScope, Option, - Box>, + Box>, CanGc, - ) -> Root>> = Wrap::; + ) -> Root>> = Wrap::; }} """ @@ -3370,7 +3430,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): args = [Argument('SafeJSContext', 'cx'), Argument('HandleObject', 'global'), Argument('*mut ProtoOrIfaceArray', 'cache')] CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args, - unsafe=True) + unsafe=True, templateArgs=['D: DomTypes']) self.properties = properties self.haveUnscopables = haveUnscopables self.haveLegacyWindowAliases = haveLegacyWindowAliases @@ -3429,7 +3489,7 @@ assert!((*cache)[PrototypeList::Constructor::{name} as usize].is_null()); getPrototypeProto = f"prototype_proto.set({protoGetter}(*cx))" else: getPrototypeProto = ( - f"{toBindingNamespace(parentName)}::GetProtoObject(cx, global, prototype_proto.handle_mut())" + f"{toBindingNamespace(parentName)}::GetProtoObject::(cx, global, prototype_proto.handle_mut())" ) code = [CGGeneric(f""" @@ -3498,7 +3558,7 @@ assert!((*cache)[PrototypeList::ID::{proto_properties['id']} as usize].is_null() if parentName: parentName = toBindingNamespace(parentName) code.append(CGGeneric(f""" -{parentName}::GetConstructorObject(cx, global, interface_proto.handle_mut());""")) +{parentName}::GetConstructorObject::(cx, global, interface_proto.handle_mut());""")) else: code.append(CGGeneric("interface_proto.set(GetRealmFunctionPrototype(*cx));")) code.append(CGGeneric(f""" @@ -3589,7 +3649,7 @@ assert!((*cache)[PrototypeList::Constructor::{properties['id']} as usize].is_nul hook = f"{CONSTRUCT_HOOK_NAME}_{constructor.identifier.name}" name = str_to_cstr(constructor.identifier.name) length = methodLength(constructor) - specs.append(CGGeneric(f"({hook} as ConstructorClassHook, {name}, {length})")) + specs.append(CGGeneric(f"({hook}:: as ConstructorClassHook, {name}, {length})")) values = CGIndenter(CGList(specs, "\n"), 4) code.append(CGWrapper(values, pre=f"{decl} = [\n", post="\n];")) code.append(CGGeneric("create_named_constructors(cx, global, &named_constructors, prototype.handle());")) @@ -3636,14 +3696,14 @@ class CGGetPerInterfaceObject(CGAbstractMethod): Argument('HandleObject', 'global'), Argument('MutableHandleObject', 'mut rval')] CGAbstractMethod.__init__(self, descriptor, name, - 'void', args, pub=pub) + 'void', args, pub=pub, templateArgs=['D: DomTypes']) self.id = f"{idPrefix}::{MakeNativeName(self.descriptor.name)}" self.variant = self.id.split('::')[-2] def definition_body(self): return CGGeneric( "get_per_interface_object_handle" - f"(cx, global, ProtoOrIfaceIndex::{self.variant}({self.id}), CreateInterfaceObjects, rval)" + f"(cx, global, ProtoOrIfaceIndex::{self.variant}({self.id}), CreateInterfaceObjects::, rval)" ) @@ -3730,6 +3790,8 @@ class CGDefineProxyHandler(CGAbstractMethod): getOwnEnumerablePropertyKeys = "getOwnEnumerablePropertyKeys::" return CGGeneric(f""" +init_proxy_handler_dom_class::(); + let traps = ProxyTraps {{ enter: None, getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor::), @@ -3763,7 +3825,7 @@ let traps = ProxyTraps {{ isConstructor: None, }}; -CreateProxyHandler(&traps, Class.as_void_ptr())\ +CreateProxyHandler(&traps, unsafe {{ Class.get() }}.as_void_ptr())\ """) @@ -3779,7 +3841,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod): Argument('HandleObject', 'global'), ] CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', - 'void', args, pub=True) + 'void', args, pub=True, templateArgs=['D: DomTypes']) if self.descriptor.interface.isCallback() or self.descriptor.interface.isNamespace(): idPrefix = "PrototypeList::Constructor" else: @@ -3793,7 +3855,8 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod): def definition_body(self): return CGGeneric( "define_dom_interface" - f"(cx, global, ProtoOrIfaceIndex::{self.variant}({self.id}), CreateInterfaceObjects, ConstructorEnabled)" + f"(cx, global, ProtoOrIfaceIndex::{self.variant}({self.id})," + "CreateInterfaceObjects::, ConstructorEnabled)" ) @@ -3860,7 +3923,7 @@ class CGCallGenerator(CGThing): call = CGGeneric(nativeMethodName) if static: - call = CGWrapper(call, pre=f"{MakeNativeName(descriptor.interface.identifier.name)}::") + call = CGWrapper(call, pre=f"::") else: call = CGWrapper(call, pre=f"{object}.") call = CGList([call, CGWrapper(args, pre="(", post=")")]) @@ -3881,7 +3944,7 @@ class CGCallGenerator(CGThing): if isFallible: if static: - glob = "global.upcast::()" + glob = "global.upcast::()" else: glob = "&this.global()" @@ -3889,7 +3952,7 @@ class CGCallGenerator(CGThing): "let result = match result {\n" " Ok(result) => result,\n" " Err(e) => {\n" - f" throw_dom_exception(cx, {glob}, e);\n" + f" >::throw_dom_exception(cx, {glob}, e);\n" f" return{errorResult};\n" " },\n" "};")) @@ -4107,10 +4170,10 @@ class CGAbstractStaticBindingMethod(CGAbstractMethod): def definition_body(self): preamble = """\ let args = CallArgs::from_vp(vp, argc); -let global = GlobalScope::from_object(args.callee()); +let global = D::GlobalScope::from_object(args.callee()); """ if len(self.exposureSet) == 1: - preamble += f"let global = DomRoot::downcast::(global).unwrap();\n" + preamble += f"let global = DomRoot::downcast::(global).unwrap();\n" return CGList([CGGeneric(preamble), self.generate_code()]) def generate_code(self): @@ -5011,6 +5074,8 @@ def getUnionTypeTemplateVars(type, descriptorProvider): elif type.isDictionary(): name = type.name typeName = name + if containsDomInterface(type): + typeName += "" elif type.isSequence() or type.isRecord(): name = type.name inner = getUnionTypeTemplateVars(innerContainerType(type), descriptorProvider) @@ -5058,6 +5123,10 @@ def getUnionTypeTemplateVars(type, descriptorProvider): } +def traitRequiresManualImpl(name, ty): + return name == "Clone" and containsDomInterface(ty) + + class CGUnionStruct(CGThing): def __init__(self, type, descriptorProvider, config): assert not type.nullable() @@ -5065,15 +5134,40 @@ class CGUnionStruct(CGThing): CGThing.__init__(self) self.type = type - self.derives = config.getUnionConfig(str(type)).get('derives', []) + derivesList = config.getUnionConfig(str(type)).get('derives', []) + self.manualImpls = list(filter(lambda t: traitRequiresManualImpl(t, type), derivesList)) + self.derives = list(filter(lambda t: not traitRequiresManualImpl(t, type), derivesList)) self.descriptorProvider = descriptorProvider + self.generic, self.genericSuffix = genericsForType(self.type) + def membersNeedTracing(self): for t in self.type.flatMemberTypes: if type_needs_tracing(t): return True return False + def manualImplClone(self, templateVars): + arms = [f" {self.type}::{v['name']}(ref inner) => " + f"{self.type}::{v['name']}(inner.clone())," + for (v, _) in templateVars] + arms = "\n".join(arms) + return f""" +#[allow(clippy::clone_on_copy)] +impl{self.generic} Clone for {self.type}{self.genericSuffix} {{ + fn clone(&self) -> Self {{ + match self {{ +{arms} + }} + }} +}} + """ + + def manualImpl(self, t, templateVars): + if t == "Clone": + return self.manualImplClone(templateVars) + raise f"Don't know how to impl {t} for union" + def define(self): def getTypeWrapper(t): if type_needs_tracing(t): @@ -5095,19 +5189,22 @@ class CGUnionStruct(CGThing): joinedEnumValues = "\n".join(enumValues) joinedEnumConversions = "\n".join(enumConversions) derives = ["JSTraceable"] + self.derives + manualImpls = "\n".join(map(lambda t: self.manualImpl(t, templateVars), self.manualImpls)) return f""" #[derive({", ".join(derives)})] -pub(crate) enum {self.type} {{ +pub(crate) enum {self.type}{self.generic} {{ {joinedEnumValues} }} -impl ToJSValConvertible for {self.type} {{ +impl{self.generic} ToJSValConvertible for {self.type}{self.genericSuffix} {{ unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {{ match *self {{ {joinedEnumConversions} }} }} }} + +{manualImpls} """ @@ -5138,8 +5235,9 @@ class CGUnionConversionStruct(CGThing): return memberType.name def get_match(name): + generic = "::" if containsDomInterface(self.type) else "" return ( - f"match {self.type}::TryConvertTo{name}(SafeJSContext::from_ptr(cx), value) {{\n" + f"match {self.type}{generic}::TryConvertTo{name}(SafeJSContext::from_ptr(cx), value) {{\n" " Err(_) => return Err(()),\n" f" Ok(Some(value)) => return Ok(ConversionResult::Success({self.type}::{name}(value))),\n" " Ok(None) => (),\n" @@ -5254,19 +5352,20 @@ class CGUnionConversionStruct(CGThing): conversions.append(CGGeneric( f'Ok(ConversionResult::Failure("argument could not be converted to any of: {", ".join(names)}".into()))' )) + generic, genericSuffix = genericsForType(self.type) method = CGWrapper( CGIndenter(CGList(conversions, "\n\n")), pre="unsafe fn from_jsval(cx: *mut JSContext,\n" " value: HandleValue,\n" " _option: ())\n" - f" -> Result, ()> {{\n", + f" -> Result, ()> {{\n", post="\n}") return CGWrapper( CGIndenter(CGList([ CGGeneric("type Config = ();"), method, ], "\n")), - pre=f"impl FromJSValConvertible for {self.type} {{\n", + pre=f"impl{generic} FromJSValConvertible for {self.type}{genericSuffix} {{\n", post="\n}") def try_method(self, t): @@ -5289,10 +5388,11 @@ class CGUnionConversionStruct(CGThing): methods = CGIndenter(CGList([ self.try_method(t) for t in self.type.flatMemberTypes ], "\n\n")) + generic, genericSuffix = genericsForType(self.type) return f""" {from_jsval.define()} -impl {self.type} {{ +impl{generic} {self.type}{genericSuffix} {{ {methods.define()} }} """ @@ -5764,7 +5864,7 @@ class CGProxyUnwrap(CGAbstractMethod): def __init__(self, descriptor): args = [Argument('RawHandleObject', 'obj')] CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", - f'*const D::{descriptor.concreteType}', args, + f'*const {descriptor.concreteType}', args, alwaysInline=True, unsafe=True, templateArgs=['D: DomTypes']) @@ -5772,7 +5872,7 @@ class CGProxyUnwrap(CGAbstractMethod): return CGGeneric(f""" let mut slot = UndefinedValue(); GetProxyReservedSlot(obj.get(), 0, &mut slot); - let box_ = slot.to_private() as *const D::{self.descriptor.concreteType}; + let box_ = slot.to_private() as *const {self.descriptor.concreteType}; return box_;""") @@ -6312,7 +6412,7 @@ class CGDOMJSProxyHandler_getPrototype(CGAbstractExternMethod): return dedent( """ let cx = SafeJSContext::from_ptr(cx); - proxyhandler::maybe_cross_origin_get_prototype::(cx, proxy, GetProtoObject, proto) + proxyhandler::maybe_cross_origin_get_prototype::(cx, proxy, GetProtoObject::, proto) """) def definition_body(self): @@ -6396,25 +6496,25 @@ class CGClassConstructHook(CGAbstractExternMethod): else: constructor = descriptor.interface.ctor() assert constructor - CGAbstractExternMethod.__init__(self, descriptor, name, 'bool', args) + CGAbstractExternMethod.__init__(self, descriptor, name, 'bool', args, templateArgs=['D: DomTypes']) self.constructor = constructor self.exposureSet = descriptor.interface.exposureSet def definition_body(self): preamble = """let cx = SafeJSContext::from_ptr(cx); let args = CallArgs::from_vp(vp, argc); -let global = GlobalScope::from_object(JS_CALLEE(*cx, vp).to_object()); +let global = D::GlobalScope::from_object(JS_CALLEE(*cx, vp).to_object()); """ if self.constructor.isHTMLConstructor(): signatures = self.constructor.signatures() assert len(signatures) == 1 constructorCall = f""" - call_html_constructor::( + >::call_html_constructor::( cx, &args, &global, PrototypeList::ID::{MakeNativeName(self.descriptor.name)}, - CreateInterfaceObjects, + CreateInterfaceObjects::, CanGc::note() ) """ @@ -6425,7 +6525,7 @@ let global = GlobalScope::from_object(JS_CALLEE(*cx, vp).to_object()); if len(self.exposureSet) == 1: args = [ - f"global.downcast::().unwrap()", + f"global.downcast::().unwrap()", "Some(desired_proto)", "CanGc::note()" ] @@ -6438,14 +6538,14 @@ let global = GlobalScope::from_object(JS_CALLEE(*cx, vp).to_object()); constructor = CGMethodCall(args, nativeName, True, self.descriptor, self.constructor) constructorCall = f""" - call_default_constructor( + call_default_constructor::( cx, &args, &global, PrototypeList::ID::{MakeNativeName(self.descriptor.name)}, \"{ctorName}\", - CreateInterfaceObjects, - |cx: SafeJSContext, args: &CallArgs, global: &GlobalScope, desired_proto: HandleObject| {{ + CreateInterfaceObjects::, + |cx: SafeJSContext, args: &CallArgs, global: &D::GlobalScope, desired_proto: HandleObject| {{ {constructor.define()} }} ) @@ -6472,7 +6572,13 @@ class CGDOMJSProxyHandlerDOMClass(CGThing): self.descriptor = descriptor def define(self): - return f"static Class: DOMClass = {DOMClass(self.descriptor)};\n" + return f""" +static Class: ThreadUnsafeOnceLock = ThreadUnsafeOnceLock::new(); + +pub(crate) fn init_proxy_handler_dom_class() {{ + Class.set({DOMClass(self.descriptor)}); +}} +""" class CGInterfaceTrait(CGThing): @@ -6594,7 +6700,7 @@ class CGInterfaceTrait(CGThing): unsafe = 'unsafe ' if contains_unsafe_arg(arguments) else '' returnType = f" -> {rettype}" if rettype != '()' else '' selfArg = "&self" if not isStatic else "" - extra = [("global", f"&{exposedGlobal}")] if isStatic else [] + extra = [("global", f"&D::{exposedGlobal}")] if isStatic else [] if arguments and arguments[0][0] == "cx": arguments = [arguments[0]] + extra + arguments[1:] else: @@ -6610,7 +6716,7 @@ class CGInterfaceTrait(CGThing): name = (baseName or ctor.identifier.name) + ('_' * i) args = list(method_arguments(descriptor, rettype, arguments)) extra = [ - ("global", f"&{exposedGlobal}"), + ("global", f"&D::{exposedGlobal}"), ("proto", "Option"), ("can_gc", "CanGc"), ] @@ -6633,13 +6739,10 @@ class CGInterfaceTrait(CGThing): if descriptor.operations['IndexedGetter'] and not hasLength: methods.append(CGGeneric("fn Length(&self) -> u32;\n")) - if methods: - name = descriptor.interface.identifier.name - self.cgRoot = CGWrapper(CGIndenter(CGList(methods, "")), - pre=f"pub(crate) trait {name}Methods {{\n", - post="}") - else: - self.cgRoot = CGGeneric("") + name = descriptor.interface.identifier.name + self.cgRoot = CGWrapper(CGIndenter(CGList(methods, "")), + pre=f"pub(crate) trait {name}Methods {{\n", + post="}") self.empty = not methods def define(self): @@ -6715,7 +6818,7 @@ class CGInitStatics(CGThing): ] if descriptor.isMaybeCrossOriginObject() else [] crossorigin_joined = '\n'.join(crossorigin) interface = ( - "init_interface_object();" + "init_interface_object::();" if descriptor.interface.hasInterfaceObject() and not descriptor.interface.isNamespace() and not descriptor.interface.isCallback() @@ -6894,8 +6997,13 @@ class CGDescriptor(CGThing): CGIndenter(CGList([CGGeneric(str_to_cstr(name)) for name in unscopableNames], ",\n")), CGGeneric("];\n")], "\n")) - if descriptor.concrete or descriptor.hasDescendants(): + if ( + (descriptor.concrete or descriptor.hasDescendants()) + and not descriptor.interface.isIteratorInterface() + ): cgThings.append(CGIDLInterface(descriptor)) + if descriptor.interface.isIteratorInterface(): + cgThings.append(CGIteratorDerives(descriptor)) if descriptor.weakReferenceable: cgThings.append(CGWeakReferenceableTrait(descriptor)) @@ -7004,7 +7112,9 @@ class CGNonNamespacedEnum(CGThing): class CGDictionary(CGThing): def __init__(self, dictionary, descriptorProvider, config): self.dictionary = dictionary - self.derives = config.getDictConfig(dictionary.identifier.name).get('derives', []) + derivesList = config.getDictConfig(dictionary.identifier.name).get('derives', []) + self.manualImpls = list(filter(lambda t: traitRequiresManualImpl(t, self.dictionary), derivesList)) + self.derives = list(filter(lambda t: not traitRequiresManualImpl(t, self.dictionary), derivesList)) if all(CGDictionary(d, descriptorProvider, config).generatable for d in CGDictionary.getDictionaryDependencies(dictionary)): self.generatable = True @@ -7013,6 +7123,8 @@ class CGDictionary(CGThing): # Nothing else to do here return + self.generic, self.genericSuffix = genericsForType(self.dictionary) + self.memberInfo = [ (member, getJSToNativeConversionInfo(member.type, @@ -7027,10 +7139,36 @@ class CGDictionary(CGThing): return "" return f"{self.struct()}\n{self.impl()}" + def manualImplClone(self): + members = [] + for m in self.memberInfo: + memberName = self.makeMemberName(m[0].identifier.name) + members += [f" {memberName}: self.{memberName}.clone(),"] + if self.dictionary.parent: + members += [" parent: parent.clone(),"] + members = "\n".join(members) + return f""" +#[allow(clippy::clone_on_copy)] +impl{self.generic} Clone for {self.makeClassName(self.dictionary)}{self.genericSuffix} {{ + fn clone(&self) -> Self {{ + Self {{ +{members} + }} + }} +}} +""" + + def manualImpl(self, t): + if t == "Clone": + return self.manualImplClone() + raise f"Don't know how to impl {t} for dicts." + def struct(self): d = self.dictionary if d.parent: typeName = f"{self.makeModuleName(d.parent)}::{self.makeClassName(d.parent)}" + _, parentSuffix = genericsForType(d.parent) + typeName += parentSuffix if type_needs_tracing(d.parent): typeName = f"RootedTraceableBox<{typeName}>" inheritance = f" pub(crate) parent: {typeName},\n" @@ -7066,21 +7204,23 @@ class CGDictionary(CGThing): ) default = ( - f"impl Default for {self.makeClassName(d)} {{\n" + f"impl{self.generic} Default for {self.makeClassName(d)}{self.genericSuffix} {{\n" " fn default() -> Self {\n" f"{impl}" " }\n" "}\n" ) + manualImpls = "\n".join(map(lambda t: self.manualImpl(t), self.manualImpls)) joinedMemberDecls = '\n'.join(memberDecls) return ( f"#[derive({', '.join(derive)})]\n" f"{mustRoot}" - f"pub(crate) struct {self.makeClassName(d)} {{\n" + f"pub(crate) struct {self.makeClassName(d)}{self.generic} {{\n" f"{inheritance}" f"{joinedMemberDecls}\n" "}\n" + f"{manualImpls}" f"{default}" ) @@ -7134,11 +7274,11 @@ class CGDictionary(CGThing): selfName = self.makeClassName(d) if self.membersNeedTracing(): - actualType = f"RootedTraceableBox<{selfName}>" + actualType = f"RootedTraceableBox<{selfName}{self.genericSuffix}>" preInitial = f"let dictionary = RootedTraceableBox::new({selfName} {{\n" postInitial = "});\n" else: - actualType = selfName + actualType = f"{selfName}{self.genericSuffix}" preInitial = f"let dictionary = {selfName} {{\n" postInitial = "};\n" initParent = f"parent: {initParent},\n" if initParent else "" @@ -7148,7 +7288,7 @@ class CGDictionary(CGThing): if not initParent and not memberInits: unsafe_if_necessary = "" return ( - f"impl {selfName} {{\n" + f"impl{self.generic} {selfName}{self.genericSuffix} {{\n" f"{CGIndenter(CGGeneric(self.makeEmpty()), indentLevel=4).define()}\n" " pub(crate) fn new(cx: SafeJSContext, val: HandleValue) \n" f" -> Result, ()> {{\n" @@ -7170,7 +7310,7 @@ class CGDictionary(CGThing): " }\n" "}\n" "\n" - f"impl FromJSValConvertible for {actualType} {{\n" + f"impl{self.generic} FromJSValConvertible for {actualType} {{\n" " type Config = ();\n" " unsafe fn from_jsval(cx: *mut JSContext, value: HandleValue, _option: ())\n" f" -> Result, ()> {{\n" @@ -7178,12 +7318,12 @@ class CGDictionary(CGThing): " }\n" "}\n" "\n" - f"impl {selfName} {{\n" + f"impl{self.generic} {selfName}{self.genericSuffix} {{\n" " pub(crate) unsafe fn to_jsobject(&self, cx: *mut JSContext, mut obj: MutableHandleObject) {\n" f"{CGIndenter(CGList(memberInserts), indentLevel=8).define()} }}\n" "}\n" "\n" - f"impl ToJSValConvertible for {selfName} {{\n" + f"impl{self.generic} ToJSValConvertible for {selfName}{self.genericSuffix} {{\n" " unsafe fn to_jsval(&self, cx: *mut JSContext, mut rval: MutableHandleValue) {\n" " rooted!(in(cx) let mut obj = JS_NewObject(cx, ptr::null()));\n" " self.to_jsobject(cx, obj.handle_mut());\n" @@ -7366,9 +7506,124 @@ class CGRegisterProxyHandlers(CGThing): return self.root.define() +class CGConcreteBindingRoot(CGThing): + """ + Root codegen class for binding generation, specialized on the concrete + type that is used by handwritten code. Re-export all public types from + the generic bindings with type specialization applied. + """ + def __init__(self, config, prefix, webIDLFile): + descriptors = config.getDescriptors(webIDLFile=webIDLFile, + hasInterfaceObject=True) + # We also want descriptors that have an interface prototype object + # (isCallback=False), but we don't want to include a second copy + # of descriptors that we also matched in the previous line + # (hence hasInterfaceObject=False). + descriptors.extend(config.getDescriptors(webIDLFile=webIDLFile, + hasInterfaceObject=False, + isCallback=False, + register=True)) + + dictionaries = config.getDictionaries(webIDLFile=webIDLFile) + + mainCallbacks = config.getCallbacks(webIDLFile=webIDLFile) + callbackDescriptors = config.getDescriptors(webIDLFile=webIDLFile, + isCallback=True) + + enums = config.getEnums(webIDLFile) + typedefs = config.getTypedefs(webIDLFile) + + if not (descriptors or dictionaries or mainCallbacks or callbackDescriptors or enums): + self.root = None + return + + originalBinding = f"crate::dom::bindings::codegen::{prefix.replace('/', '::').replace('Concrete', 'Generic')}" + + cgthings = [] + for e in enums: + enumName = e.identifier.name + cgthings += [ + CGGeneric(f"pub(crate) use {originalBinding}::{enumName} as {enumName};"), + CGGeneric(f"pub(crate) use {originalBinding}::{enumName}Values as {enumName}Values;"), + ] + + cgthings += [CGGeneric( + f"pub(crate) type {t.identifier.name} = " + f"{originalBinding}::{t.identifier.name}" + f"{'::' if containsDomInterface(t.innerType) else ''};" + ) for t in typedefs] + + cgthings += [CGGeneric( + f"pub(crate) type {d.identifier.name} = " + f"{originalBinding}::{d.identifier.name}" + f"{'::' if containsDomInterface(d) else ''};" + ) for d in dictionaries] + + cgthings += [CGGeneric( + f"pub(crate) type {c.identifier.name} = " + f"{originalBinding}::{c.identifier.name};" + ) for c in mainCallbacks] + + cgthings += [CGGeneric(f"pub(crate) use {originalBinding} as GenericBindings;")] + for d in descriptors: + ifaceName = d.interface.identifier.name + cgthings += [ + CGGeneric( + f"pub(crate) use {originalBinding}::{firstCap(ifaceName)}_Binding as {firstCap(ifaceName)}_Binding;" + ), + ] + if not d.interface.isCallback(): + traitName = f"{ifaceName}Methods" + cgthings += [ + CGGeneric(f"pub(crate) use self::{firstCap(ifaceName)}_Binding::{traitName} as {traitName};"), + ] + if len(descriptors) == 1 and d.concrete: + cgthings += [CGGeneric(f"pub(crate) use self::{firstCap(ifaceName)}_Binding::Wrap;")] + if d.interface.hasInterfaceObject() and d.shouldHaveGetConstructorObjectMethod(): + cgthings += [CGGeneric(f""" +pub(crate) fn GetConstructorObject( + cx: SafeJSContext, global: HandleObject, rval: MutableHandleObject +) {{ + self::{firstCap(ifaceName)}_Binding::GetConstructorObject::(cx, global, rval) +}} +""")] + + constMembers = [m for m in d.interface.members if m.isConst()] + if constMembers: + constants = f"{ifaceName}Constants" + cgthings += [CGGeneric(f"pub(crate) use {originalBinding}::{constants} as {constants};")] + + for c in callbackDescriptors: + ifaceName = c.interface.identifier.name + cgthings += [CGGeneric(f"pub(crate) type {ifaceName} = {originalBinding}::{ifaceName};")] + + # And make sure we have the right number of newlines at the end + curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n") + + # Add imports + # These are the global imports (outside of the generated module) + curr = CGImports(curr, descriptors=[], callbacks=[], + dictionaries=[], enums=[], typedefs=[], + imports=[ + 'crate::dom::bindings::import::base::*', + 'crate::dom::types::*'], + config=config) + + # Add the auto-generated comment. + curr = CGWrapper(curr, pre=f"{AUTOGENERATED_WARNING_COMMENT}{ALLOWED_WARNINGS}") + + # Store the final result. + self.root = curr + + def define(self): + if not self.root: + return None + return stripTrailingWhitespace(self.root.define()) + + class CGBindingRoot(CGThing): """ - DomRoot codegen class for binding generation. Instantiate the class, and call + Root codegen class for binding generation. Instantiate the class, and call declare or define to generate header or cpp code (respectively). """ def __init__(self, config, prefix, webIDLFile): @@ -7407,9 +7662,11 @@ class CGBindingRoot(CGThing): if t.innerType.isUnion() and not t.innerType.nullable(): # Allow using the typedef's name for accessing variants. - typeDefinition = f"pub(crate) use self::{type} as {name};" + typeDefinition = f"pub(crate) use self::{type.replace('', '')} as {name};" else: - typeDefinition = f"pub(crate) type {name} = {type};" + generic = "" if containsDomInterface(t.innerType) else "" + replacedType = type.replace("D::", "::") + typeDefinition = f"pub(crate) type {name}{generic} = {replacedType};" cgthings.append(CGGeneric(typeDefinition)) @@ -7643,12 +7900,17 @@ class CGCallback(CGClass): visibility="pub", explicit=False, baseConstructors=[ - f"{self.baseName}::new()" + f"{self.baseName.replace('', '')}::new()" ])] def getMethodImpls(self, method): assert method.needThisHandling args = list(method.args) + # Callbacks are not generic over DomTypes yet, so we need to manually + # re-specialize any use of generics within these generated methods. + for arg in args: + arg.argType = arg.argType.replace('D::', '').replace('', '') + method.returnType = method.returnType.replace('D::', '') # Strip out the JSContext*/JSObject* args # that got added. assert args[0].name == "cx" and args[0].argType == "SafeJSContext" @@ -7686,14 +7948,15 @@ class CGCallback(CGClass): bodyWithoutThis = ( f"{setupCall}\n" f"unsafe {{ self.{method.name}({', '.join(argnamesWithoutThis)}) }}") + method.body = method.body.replace('D::', '').replace('>::', '') return [ClassMethod(f'{method.name}_', method.returnType, args, bodyInHeader=True, templateArgs=["T: ThisReflector"], - body=bodyWithThis, + body=bodyWithThis.replace('D::', ''), visibility='pub'), ClassMethod(f'{method.name}__', method.returnType, argsWithoutThis, bodyInHeader=True, - body=bodyWithoutThis, + body=bodyWithoutThis.replace('D::', ''), visibility='pub'), method] @@ -8256,7 +8519,8 @@ class GlobalGenRoots(): pairs.append((ctor.identifier.name, binding_mod, binding_ns)) pairs.sort(key=operator.itemgetter(0)) mappings = [ - CGGeneric(f'"{pair[0]}": "codegen::Bindings::{pair[1]}::{pair[2]}::DefineDOMInterface"') + CGGeneric(f'"{pair[0]}": "codegen::Bindings::{pair[1]}' + f'::{pair[2]}::DefineDOMInterface::"') for pair in pairs ] return CGWrapper( @@ -8449,6 +8713,26 @@ impl Clone for TopTypeId { curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) return curr + @staticmethod + def ConcreteUnionTypes(config): + unions = set() + cgthings = [] + allTypes = getAllTypes( + config.getDescriptors(), config.getDictionaries(), config.getCallbacks(), config.typedefs + ) + for (t, descriptor) in allTypes: + t = t.unroll() + name = str(t) + if not t.isUnion() or name in unions: + continue + unions.add(name) + generic = "" if containsDomInterface(t) else "" + cgthings += [CGGeneric(f"pub(crate) type {name} = " + f"crate::dom::bindings::codegen::GenericUnionTypes::{name}{generic};\n")] + curr = CGList(cgthings) + curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) + return curr + @staticmethod def UnionTypes(config): diff --git a/components/script_bindings/codegen/Configuration.py b/components/script_bindings/codegen/Configuration.py index bae19bb915a..3f7b9ad6d9b 100644 --- a/components/script_bindings/codegen/Configuration.py +++ b/components/script_bindings/codegen/Configuration.py @@ -209,10 +209,12 @@ class Descriptor(DescriptorProvider): # nativeType of the iterable interface. That way we can have a # templated implementation for all the duplicated iterator # functionality. + prefix = "D::" if self.interface.isIteratorInterface(): itrName = self.interface.iterableInterface.identifier.name itrDesc = self.getDescriptor(itrName) nativeTypeDefault = iteratorNativeType(itrDesc) + prefix = "" typeName = desc.get('nativeType', nativeTypeDefault) @@ -232,15 +234,15 @@ class Descriptor(DescriptorProvider): self.argumentType = "???" self.nativeType = ty else: - self.returnType = "DomRoot<%s>" % typeName - self.argumentType = "&%s" % typeName - self.nativeType = "*const %s" % typeName + self.returnType = "DomRoot<%s%s>" % (prefix, typeName) + self.argumentType = "&%s%s" % (prefix, typeName) + self.nativeType = "*const %s%s" % (prefix, typeName) if self.interface.isIteratorInterface(): pathDefault = 'crate::dom::bindings::iterable::IterableIterator' else: pathDefault = 'crate::dom::types::%s' % MakeNativeName(typeName) - self.concreteType = typeName + self.concreteType = "%s%s" % (prefix, typeName) self.register = desc.get('register', True) self.path = desc.get('path', pathDefault) self.inRealmMethods = [name for name in desc.get('inRealms', [])] @@ -489,7 +491,7 @@ def getIdlFileName(object): def getModuleFromObject(object): - return ('crate::dom::bindings::codegen::Bindings::' + getIdlFileName(object) + 'Binding') + return ('crate::dom::bindings::codegen::GenericBindings::' + getIdlFileName(object) + 'Binding') def getTypesFromDescriptor(descriptor): @@ -547,7 +549,7 @@ def iteratorNativeType(descriptor, infer=False): iterableDecl = descriptor.interface.maplikeOrSetlikeOrIterable assert (iterableDecl.isIterable() and iterableDecl.isPairIterator()) \ or iterableDecl.isSetlike() or iterableDecl.isMaplike() - res = "IterableIterator%s" % ("" if infer else '<%s>' % descriptor.interface.identifier.name) + res = "IterableIterator%s" % ("" if infer else '' % descriptor.interface.identifier.name) # todo: this hack is telling us that something is still wrong in codegen if iterableDecl.isSetlike() or iterableDecl.isMaplike(): res = f"crate::dom::bindings::iterable::{res}" diff --git a/components/script_bindings/codegen/run.py b/components/script_bindings/codegen/run.py index 3ef7f296715..47279fda047 100644 --- a/components/script_bindings/codegen/run.py +++ b/components/script_bindings/codegen/run.py @@ -28,7 +28,7 @@ def main(): import WebIDL from Configuration import Configuration - from CodegenRust import CGBindingRoot + from CodegenRust import CGBindingRoot, CGConcreteBindingRoot parser = WebIDL.Parser(make_dir(os.path.join(out_dir, "cache"))) webidls = [name for name in os.listdir(webidls_dir) if name.endswith(".webidl")] @@ -48,6 +48,7 @@ def main(): parser_results = parser.finish() config = Configuration(config_file, parser_results) make_dir(os.path.join(out_dir, "Bindings")) + make_dir(os.path.join(out_dir, "ConcreteBindings")) for name, filename in [ ("PrototypeList", "PrototypeList.rs"), @@ -59,7 +60,9 @@ def main(): ("InheritTypes", "InheritTypes.rs"), ("ConcreteInheritTypes", "ConcreteInheritTypes.rs"), ("Bindings", "Bindings/mod.rs"), - ("UnionTypes", "UnionTypes.rs"), + ("Bindings", "ConcreteBindings/mod.rs"), + ("UnionTypes", "GenericUnionTypes.rs"), + ("ConcreteUnionTypes", "UnionTypes.rs"), ("DomTypes", "DomTypes.rs"), ("DomTypeHolder", "DomTypeHolder.rs"), ]: @@ -74,6 +77,11 @@ def main(): if module: with open(os.path.join(out_dir, prefix + ".rs"), "wb") as f: f.write(module.encode("utf-8")) + prefix = "ConcreteBindings/%sBinding" % webidl[:-len(".webidl")] + module = CGConcreteBindingRoot(config, prefix, filename).define() + if module: + with open(os.path.join(out_dir, prefix + ".rs"), "wb") as f: + f.write(module.encode("utf-8")) def make_dir(path):