@@ -31,6 +31,8 @@ use quickjs_runtime::jsutils::JsError;
3131use quickjs_runtime:: quickjsrealmadapter:: QuickJsRealmAdapter ;
3232use quickjs_runtime:: quickjsvalueadapter:: QuickJsValueAdapter ;
3333use std:: cell:: RefCell ;
34+ use std:: collections:: HashMap ;
35+ use std:: hash:: { Hash , Hasher } ;
3436
3537// https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
3638// https://developer.mozilla.org/en-US/docs/Web/API/Element
@@ -216,8 +218,35 @@ struct StyleObj {
216218 element : NodeRef ,
217219}
218220
221+ #[ derive( Clone ) ]
222+ struct NodeRefWrapper ( NodeRef ) ;
223+
224+ impl Hash for NodeRefWrapper {
225+ fn hash < H : Hasher > ( & self , state : & mut H ) {
226+ let ptr = std:: rc:: Rc :: as_ptr ( & self . 0 . 0 ) ;
227+ ptr. hash ( state) ;
228+ }
229+ }
230+
231+ impl PartialEq for NodeRefWrapper {
232+ fn eq ( & self , other : & Self ) -> bool {
233+ let one: & NodeRef = & self . 0 ;
234+ let two: & NodeRef = & other. 0 ;
235+ one. eq ( two)
236+ }
237+ }
238+
239+ impl Eq for NodeRefWrapper { }
240+
241+ impl NodeRefWrapper {
242+ fn clone_node ( & self ) -> NodeRef {
243+ self . 0 . clone ( )
244+ }
245+ }
246+
219247thread_local ! {
220248 static NODES : RefCell <AutoIdMap <NodeRef >> = RefCell :: new( AutoIdMap :: new( ) ) ;
249+ static NODE_VALUE_BY_NODEREF : RefCell <HashMap <NodeRefWrapper , QuickJsValueAdapter >> = RefCell :: new( HashMap :: new( ) ) ;
221250 static NODELISTS : RefCell <AutoIdMap <NodeList >> = RefCell :: new( AutoIdMap :: new( ) ) ;
222251 static ELEMENTLISTS : RefCell <AutoIdMap <ElementList >> = RefCell :: new( AutoIdMap :: new( ) ) ;
223252 static SELECTELEMENTLISTS : RefCell <AutoIdMap <SelectElementList >> = RefCell :: new( AutoIdMap :: new( ) ) ;
@@ -285,11 +314,34 @@ fn register_node(
285314 // remove on finalize (dont decrement refcount :))
286315 // reuse here to create a new JsValueAdapter (and then increment refcount)
287316
288- let id = NODES . with ( |rc| {
289- let map = & mut * rc. borrow_mut ( ) ;
290- map. insert ( node)
291- } ) ;
292- realm. instantiate_proxy_with_id ( & [ "greco" , "htmldom" ] , "Node" , id)
317+ let node_ref_wrapper = NodeRefWrapper ( node) ;
318+
319+ NODE_VALUE_BY_NODEREF . with ( |rc| {
320+ let node_ref_map = & mut * rc. borrow_mut ( ) ;
321+ if let Some ( value) = node_ref_map. get ( & node_ref_wrapper) {
322+ Ok ( value. clone ( ) )
323+ } else {
324+ let id = NODES . with ( |rc| {
325+ let map = & mut * rc. borrow_mut ( ) ;
326+ map. insert ( node_ref_wrapper. clone_node ( ) )
327+ } ) ;
328+
329+ let mut node_value_adapter =
330+ realm. instantiate_proxy_with_id ( & [ "greco" , "htmldom" ] , "Node" , id) ?;
331+
332+ let value_without_incr = QuickJsValueAdapter :: new (
333+ realm. context ,
334+ * node_value_adapter. borrow_value_mut ( ) ,
335+ false ,
336+ false ,
337+ "register_node clone" ,
338+ ) ;
339+
340+ node_ref_map. insert ( node_ref_wrapper, value_without_incr) ;
341+
342+ Ok ( node_value_adapter)
343+ }
344+ } )
293345}
294346
295347fn register_node_list (
@@ -406,10 +458,15 @@ fn init_node_proxy(realm: &QuickJsRealmAdapter) -> Result<QuickJsValueAdapter, J
406458 . name ( "Node" )
407459 . event_target ( )
408460 . finalizer ( |_rt, _realm, id| {
409- NODES . with ( |rc| {
461+ let node = NODES . with ( |rc| {
410462 let map = & mut rc. borrow_mut ( ) ;
411- map. remove ( & id) ;
412- } )
463+ map. remove ( & id)
464+ } ) ;
465+ let node_ref_wrapper = NodeRefWrapper ( node) ;
466+ NODE_VALUE_BY_NODEREF . with ( |rc| {
467+ let map = & mut * rc. borrow_mut ( ) ;
468+ map. remove ( & node_ref_wrapper) ;
469+ } ) ;
413470 } )
414471 . getter ( "dataset" , |_rt, realm, id| {
415472 with_node ( id, |node| {
@@ -1557,26 +1614,25 @@ pub mod tests {
15571614 use crate :: init_greco_rt;
15581615 use futures:: executor:: block_on;
15591616 use quickjs_runtime:: builder:: QuickJsRuntimeBuilder ;
1617+ use std:: collections:: HashMap ;
15601618
15611619 use quickjs_runtime:: jsutils:: Script ;
15621620 use quickjs_runtime:: values:: JsValueFacade ;
15631621
15641622 #[ test]
15651623 fn test ( ) {
1566- /*
1567- panic::set_hook(Box::new(|panic_info| {
1568- let backtrace = Backtrace::new();
1569- log::error!(
1570- "thread panic occurred: {}\nbacktrace: {:?}",
1571- panic_info,
1572- backtrace
1573- );
1574- }));
1575-
1576- simple_logging::log_to_file("grecort.log", LevelFilter::max())
1577- .ok()
1578- .expect("could not init logger");
1579- */
1624+ std:: panic:: set_hook ( Box :: new ( |panic_info| {
1625+ let backtrace = backtrace:: Backtrace :: new ( ) ;
1626+ log:: error!(
1627+ "thread panic occurred: {}\n backtrace: {:?}" ,
1628+ panic_info,
1629+ backtrace
1630+ ) ;
1631+ } ) ) ;
1632+
1633+ simple_logging:: log_to_file ( "grecort.log" , log:: LevelFilter :: max ( ) )
1634+ . ok ( )
1635+ . expect ( "could not init logger" ) ;
15801636
15811637 let rtb = QuickJsRuntimeBuilder :: new ( ) ;
15821638 let rt = init_greco_rt ( rtb) . build ( ) ;
@@ -1590,6 +1646,10 @@ pub mod tests {
15901646 let res = "";
15911647
15921648 let helloNode = doc.getElementById("helloId");
1649+ let helloNode2 = doc.getElementById("helloId").firstChild.parentElement;
1650+
1651+ console.log("i want true! ", helloNode === helloNode2);
1652+
15931653 helloNode.textContent = "hi there";
15941654
15951655 const svg = doc.createElementNS("http://www.w3.org/2000/svg", "svg");
@@ -1679,5 +1739,17 @@ pub mod tests {
16791739 }
16801740 }
16811741 }
1742+
1743+ let l = crate :: modules:: htmldom:: NODE_VALUE_BY_NODEREF . with ( |rc| {
1744+ let map = & * rc. borrow ( ) ;
1745+ map. len ( )
1746+ } ) ;
1747+ assert_eq ! ( l, 0 ) ;
1748+
1749+ let l = crate :: modules:: htmldom:: NODES . with ( |rc| {
1750+ let map = & * rc. borrow ( ) ;
1751+ map. len ( )
1752+ } ) ;
1753+ assert_eq ! ( l, 0 ) ;
16821754 }
16831755}
0 commit comments