1- use napi:: { CallContext , JsNumber , JsObject , JsUndefined , JsUnknown , JsFunction , Property , Ref , Result , Env } ;
1+ use napi:: { CallContext , sys , JsNumber , JsObject , NapiRaw , NapiValue , JsUndefined , JsUnknown , JsFunction , Property , Ref , Result , Env } ;
22use std:: cell:: RefCell ;
33use parcel_css:: stylesheet:: StyleSheet ;
44use std:: rc:: Rc ;
@@ -7,6 +7,11 @@ use crate::rule;
77// TODO: this is probably not safe.
88static mut CLASS : RefCell < Option < Ref < ( ) > > > = RefCell :: new ( None ) ;
99
10+ struct CSSRuleList {
11+ stylesheet : Rc < RefCell < StyleSheet > > ,
12+ rules : Vec < sys:: napi_ref >
13+ }
14+
1015#[ js_function( 0 ) ]
1116fn constructor ( ctx : CallContext ) -> Result < JsUndefined > {
1217 ctx. env . get_undefined ( )
@@ -15,17 +20,42 @@ fn constructor(ctx: CallContext) -> Result<JsUndefined> {
1520#[ js_function( 0 ) ]
1621fn get_length ( ctx : CallContext ) -> Result < JsNumber > {
1722 let this: JsObject = ctx. this_unchecked ( ) ;
18- let stylesheet : & mut Rc < RefCell < StyleSheet > > = ctx. env . unwrap ( & this) ?;
19- ctx. env . create_uint32 ( stylesheet. borrow ( ) . rules . 0 . len ( ) as u32 )
23+ let list : & mut CSSRuleList = ctx. env . unwrap ( & this) ?;
24+ ctx. env . create_uint32 ( list . stylesheet . borrow ( ) . rules . 0 . len ( ) as u32 )
2025}
2126
2227#[ js_function( 1 ) ]
2328fn item ( ctx : CallContext ) -> Result < JsObject > {
2429 let this: JsObject = ctx. this_unchecked ( ) ;
25- let index = ctx. get :: < JsNumber > ( 0 ) ?. get_uint32 ( ) ?;
26- let stylesheet: & mut Rc < RefCell < StyleSheet > > = ctx. env . unwrap ( & this) ?;
27- let r = stylesheet. borrow ( ) . rules . 0 [ index as usize ] . clone ( ) ;
28- rule:: create ( ctx. env , r)
30+ let index = ctx. get :: < JsNumber > ( 0 ) ?. get_uint32 ( ) ? as usize ;
31+ let list: & mut CSSRuleList = ctx. env . unwrap ( & this) ?;
32+
33+ // See if we already have a JS object created for this rule to preserve referential equality.
34+ // e.g. rules.item(0) === rules.item(0)
35+ // This drops down to low level C bindings for napi because there is currently no way
36+ // to create a weak reference in napi-rs.
37+ match & list. rules . get ( index) {
38+ Some ( r) if !r. is_null ( ) => {
39+ let mut js_value = std:: ptr:: null_mut ( ) ;
40+ unsafe {
41+ sys:: napi_get_reference_value ( ctx. env . raw ( ) , * * r, & mut js_value) ;
42+ if !js_value. is_null ( ) {
43+ return JsObject :: from_raw ( ctx. env . raw ( ) , js_value)
44+ }
45+ } ;
46+ }
47+ _ => { }
48+ } ;
49+
50+ let r = list. stylesheet . borrow ( ) . rules . 0 [ index] . clone ( ) ;
51+ let obj = rule:: create ( ctx. env , r) ?;
52+ while list. rules . len ( ) <= index {
53+ list. rules . push ( std:: ptr:: null_mut ( ) ) ;
54+ }
55+ unsafe {
56+ sys:: napi_create_reference ( ctx. env . raw ( ) , obj. raw ( ) , 0 , & mut list. rules [ index] ) ;
57+ } ;
58+ Ok ( obj)
2959}
3060
3161pub fn init ( exports : & mut JsObject , env : Env ) -> Result < ( ) > {
@@ -41,11 +71,11 @@ pub fn init(exports: &mut JsObject, env: Env) -> Result<()> {
4171 Ok ( ( ) )
4272}
4373
44- pub fn create ( env : & Env , list : Rc < RefCell < StyleSheet > > ) -> Result < JsObject > {
74+ pub fn create ( env : & Env , stylesheet : Rc < RefCell < StyleSheet > > ) -> Result < JsObject > {
4575 let r = unsafe { CLASS . borrow ( ) } ;
4676 let r = r. as_ref ( ) . unwrap ( ) ;
4777 let c: JsFunction = env. get_reference_value ( & r) ?;
4878 let mut instance = c. new :: < JsUnknown > ( & [ ] ) ?;
49- env. wrap ( & mut instance, list ) ?;
79+ env. wrap ( & mut instance, CSSRuleList { stylesheet , rules : Vec :: new ( ) } ) ?;
5080 Ok ( instance)
5181}
0 commit comments