11use std:: any:: { Any , TypeId } ;
2+ use std:: mem:: MaybeUninit ;
23use std:: ops:: Deref ;
3- use std:: { marker, mem} ;
4+ use std:: ptr:: DynMetadata ;
5+ use std:: { marker, mem, ptr} ;
46
57use js_sys:: { Array , Function , Reflect , Uint8Array } ;
68use wasm_bindgen:: closure:: Closure ;
@@ -11,7 +13,6 @@ use web_sys::HtmlElement;
1113use crate :: dom:: { impl_shadow_host_for_element, DynamicElement , Name , ParentNode } ;
1214use crate :: finalization_registry:: FinalizationRegistry ;
1315use crate :: html:: { impl_html_element_traits, CustomElementName } ;
14- use crate :: util:: type_id_to_u64;
1516use crate :: InvalidCast ;
1617use crate :: { dom_exception_wrapper, impl_common_wrapper_traits} ;
1718
@@ -20,24 +21,19 @@ thread_local! {
2021 let callback = |held_value: JsValue | {
2122 // Reconstruct the Box<dyn Any> that holds the data, then drop it.
2223
23- let pointer_data : Uint8Array = held_value. unchecked_into( ) ;
24+ let serialized_data : Uint8Array = held_value. unchecked_into( ) ;
2425
25- // Copy pointer data to WASM linear memory that we can operate on.
26- let mut scratch = [ 0u8 ; 24 ] ;
27- let size_of_usize = mem:: size_of:: <usize >( ) ;
26+ let mut uninit_custom_element_data = MaybeUninit :: <CustomElementData >:: uninit( ) ;
27+ let data_ptr = uninit_custom_element_data. as_mut_ptr( ) ;
2828
29- pointer_data . copy_to ( & mut scratch [ ..size_of_usize * 2 + 8 ] ) ;
29+ deserialize_custom_element_data ( & wasm_bindgen :: memory ( ) , data_ptr , & serialized_data ) ;
3030
31- let ( address_bytes, rest) = scratch. split_at( size_of_usize) ;
32- let ( vtable_bytes, _) = rest. split_at( size_of_usize) ;
33-
34- let address_usize = usize :: from_ne_bytes( address_bytes. try_into( ) . unwrap_throw( ) ) ;
35- let vtable_usize = usize :: from_ne_bytes( vtable_bytes. try_into( ) . unwrap_throw( ) ) ;
36-
37- let ptr: * mut dyn Any = unsafe { mem:: transmute( ( address_usize, vtable_usize) ) } ;
31+ let custom_element_data = unsafe {
32+ uninit_custom_element_data. assume_init( )
33+ } ;
3834
3935 unsafe {
40- mem:: drop( Box :: from_raw( ptr ) ) ;
36+ mem:: drop( Box :: from_raw( custom_element_data . to_dyn_any_ptr ( ) ) ) ;
4137 }
4238 } ;
4339
@@ -51,6 +47,18 @@ thread_local! {
5147 } ;
5248}
5349
50+ struct CustomElementData {
51+ address : * mut ( ) ,
52+ metadata : DynMetadata < dyn Any > ,
53+ type_id : TypeId ,
54+ }
55+
56+ impl CustomElementData {
57+ fn to_dyn_any_ptr ( & self ) -> * mut dyn Any {
58+ ptr:: from_raw_parts_mut ( self . address , self . metadata )
59+ }
60+ }
61+
5462pub ( crate ) mod extendable_element_seal {
5563 pub trait Seal {
5664 const EXTENDED_NAME : Option < & ' static str > ;
@@ -95,14 +103,14 @@ where
95103 E : ExtendableElement ,
96104{
97105 fn from_raw_unchecked ( raw : RawCustomElement ) -> Self {
98- let mut scratch = [ 0u8 ; 24 ] ;
99- let size_of_usize = mem:: size_of :: < usize > ( ) ;
106+ let mut uninit_custom_element_data = MaybeUninit :: < CustomElementData > :: uninit ( ) ;
107+ let data_ptr = uninit_custom_element_data. as_mut_ptr ( ) ;
108+
109+ raw. deserialize_custom_element_data ( & wasm_bindgen:: memory ( ) , data_ptr) ;
100110
101- raw . data ( ) . copy_to ( & mut scratch [ 0 ..size_of_usize * 2 + 8 ] ) ;
111+ let custom_element_data = unsafe { uninit_custom_element_data . assume_init ( ) } ;
102112
103- let data_ptr_bits =
104- usize:: from_ne_bytes ( scratch[ ..size_of_usize] . try_into ( ) . unwrap_throw ( ) ) ;
105- let data = <* const T >:: from_bits ( data_ptr_bits) ;
113+ let data = custom_element_data. address as * const T ;
106114 let extended = E :: from_web_sys_html_element_unchecked ( raw. into ( ) ) ;
107115
108116 CustomElement { data, extended }
@@ -139,36 +147,36 @@ where
139147 fn try_from ( element : DynamicElement ) -> Result < Self , Self :: Error > {
140148 let element: web_sys:: Element = element. into ( ) ;
141149
142- if let Ok ( value) = Reflect :: get ( element. as_ref ( ) , & "__arwa_custom_element_data" . into ( ) ) {
143- if !value. is_undefined ( ) {
144- let data: Uint8Array = value. unchecked_into ( ) ;
145- let target_type_num = type_id_to_u64 ( TypeId :: of :: < CustomElement < T , E > > ( ) ) ;
150+ let is_custom_element = Reflect :: has (
151+ element. as_ref ( ) ,
152+ & "__deserialize_custom_element_data" . into ( ) ,
153+ )
154+ . unwrap_or ( false ) ;
146155
147- let mut scratch = [ 0u8 ; 24 ] ;
148- let size_of_usize = mem:: size_of :: < usize > ( ) ;
149- let type_num_start = size_of_usize * 2 ;
150- let type_num_end = size_of_usize * 2 + 8 ;
156+ if is_custom_element {
157+ let raw = element. unchecked_into :: < RawCustomElement > ( ) ;
151158
152- data. copy_to ( & mut scratch[ 0 ..size_of_usize * 2 + 8 ] ) ;
159+ let mut uninit_custom_element_data = MaybeUninit :: < CustomElementData > :: uninit ( ) ;
160+ let data_ptr = uninit_custom_element_data. as_mut_ptr ( ) ;
153161
154- let type_num = u64:: from_ne_bytes (
155- scratch[ type_num_start..type_num_end]
156- . try_into ( )
157- . unwrap_throw ( ) ,
158- ) ;
162+ raw. deserialize_custom_element_data ( & wasm_bindgen:: memory ( ) , data_ptr) ;
159163
160- if type_num == target_type_num {
161- let data_ptr_bits =
162- usize:: from_ne_bytes ( scratch[ ..size_of_usize] . try_into ( ) . unwrap_throw ( ) ) ;
163- let data = <* const T >:: from_bits ( data_ptr_bits) ;
164- let extended = E :: from_web_sys_html_element_unchecked ( element. unchecked_into ( ) ) ;
164+ let custom_element_data = unsafe { uninit_custom_element_data. assume_init ( ) } ;
165+ let target_type_id = TypeId :: of :: < CustomElement < T , E > > ( ) ;
165166
166- return Ok ( CustomElement { data, extended } ) ;
167- }
167+ if custom_element_data. type_id == target_type_id {
168+ let data = custom_element_data. address as * const T ;
169+ let extended = E :: from_web_sys_html_element_unchecked ( raw. unchecked_into ( ) ) ;
170+
171+ Ok ( CustomElement { data, extended } )
172+ } else {
173+ Err ( InvalidCast :: new ( DynamicElement :: from (
174+ raw. unchecked_into :: < web_sys:: Element > ( ) ,
175+ ) ) )
168176 }
177+ } else {
178+ Err ( InvalidCast :: new ( DynamicElement :: from ( element) ) )
169179 }
170-
171- Err ( InvalidCast :: new ( DynamicElement :: from ( element) ) )
172180 }
173181}
174182
@@ -256,7 +264,6 @@ impl CustomElementRegistry {
256264 } = descriptor;
257265
258266 let type_id = TypeId :: of :: < CustomElement < T , E > > ( ) ;
259- let type_num = type_id_to_u64 ( type_id) ;
260267
261268 let constructor = move |extended : web_sys:: HtmlElement | {
262269 let extended = E :: from_web_sys_html_element_unchecked ( extended) ;
@@ -265,25 +272,31 @@ impl CustomElementRegistry {
265272
266273 let data = Box :: new ( data) as Box < dyn Any > ;
267274 let data_ptr = Box :: into_raw ( data) ;
268- let ( address_ptr, vtable_ptr) : ( usize , usize ) = unsafe { mem:: transmute ( data_ptr) } ;
269-
270- let mut scratch = [ 0u8 ; 24 ] ;
271- let size_of_usize = mem:: size_of :: < usize > ( ) ;
272- let type_num_start = size_of_usize * 2 ;
273- let type_num_end = size_of_usize * 2 + 8 ;
274-
275- scratch[ 0 ..size_of_usize] . copy_from_slice ( & address_ptr. to_ne_bytes ( ) ) ;
276- scratch[ size_of_usize..type_num_start] . copy_from_slice ( & vtable_ptr. to_ne_bytes ( ) ) ;
277- scratch[ type_num_start..type_num_end] . copy_from_slice ( & type_num. to_ne_bytes ( ) ) ;
275+ let ( address, metadata) = data_ptr. to_raw_parts ( ) ;
276+ let mut custom_element_data = CustomElementData {
277+ address,
278+ metadata,
279+ type_id,
280+ } ;
281+ let ptr = & mut custom_element_data as * mut CustomElementData ;
278282
279- let data = Uint8Array :: new_with_length ( type_num_end as u32 ) ;
283+ let serialized = serialize_custom_element_data (
284+ & wasm_bindgen:: memory ( ) ,
285+ ptr,
286+ mem:: size_of :: < CustomElementData > ( ) as u32 ,
287+ ) ;
280288
281- data. copy_from ( & scratch[ ..type_num_end] ) ;
289+ // Make sure it doesn't drop early
290+ mem:: drop ( custom_element_data) ;
282291
283- CUSTOM_ELEMENT_FINALIZATION_REGISTRY
284- . with ( |r| r. register ( extended. as_web_sys_html_element ( ) . as_ref ( ) , data. as_ref ( ) ) ) ;
292+ CUSTOM_ELEMENT_FINALIZATION_REGISTRY . with ( |r| {
293+ r. register (
294+ extended. as_web_sys_html_element ( ) . as_ref ( ) ,
295+ serialized. as_ref ( ) ,
296+ )
297+ } ) ;
285298
286- data
299+ serialized
287300 } ;
288301
289302 let constructor_boxed =
@@ -389,10 +402,14 @@ dom_exception_wrapper!(RegisterCustomElementError);
389402#[ wasm_bindgen]
390403extern "C" {
391404 #[ wasm_bindgen( extends = HtmlElement ) ]
392- pub type RawCustomElement ;
393-
394- #[ wasm_bindgen( method, getter, js_name = "__arwa_custom_element_data" ) ]
395- pub fn data ( this : & RawCustomElement ) -> Uint8Array ;
405+ type RawCustomElement ;
406+
407+ #[ wasm_bindgen( method, js_name = "__deserialize_custom_element_data" ) ]
408+ fn deserialize_custom_element_data (
409+ this : & RawCustomElement ,
410+ wasm_memory : & JsValue ,
411+ ptr : * mut CustomElementData ,
412+ ) ;
396413}
397414
398415#[ wasm_bindgen( module = "/src/html/define_custom_element.js" ) ]
@@ -408,6 +425,20 @@ extern "C" {
408425 attribute_changed_callback : & Function ,
409426 observed_attributes : & Array ,
410427 ) -> Result < JsValue , JsValue > ;
428+
429+ #[ wasm_bindgen]
430+ fn serialize_custom_element_data (
431+ wasm_memory : & JsValue ,
432+ pointer : * mut CustomElementData ,
433+ size : u32 ,
434+ ) -> Uint8Array ;
435+
436+ #[ wasm_bindgen]
437+ fn deserialize_custom_element_data (
438+ wasm_memory : & JsValue ,
439+ pointer : * mut CustomElementData ,
440+ serialized_data : & Uint8Array ,
441+ ) ;
411442}
412443
413444macro_rules! impl_extendable_element {
0 commit comments