diff --git a/packages/native-core-macro/src/lib.rs b/packages/native-core-macro/src/lib.rs index 883c12b2e..740c214ba 100644 --- a/packages/native-core-macro/src/lib.rs +++ b/packages/native-core-macro/src/lib.rs @@ -36,6 +36,7 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream { }; let strct = Struct::parse(&fields); let state_strct = StateStruct::parse(&fields, &strct); + let node_dep_state_fields = quote::__private::TokenStream::from_iter( state_strct .state_members @@ -86,67 +87,77 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream { .state_members .iter() .filter(|f| f.dep_kind == DepKind::NodeDepState) - .map(|f| f.type_id()); + .map(|f| &f.mem.ty); let child_types = state_strct .state_members .iter() .filter(|f| f.dep_kind == DepKind::ChildDepState) - .map(|f| f.type_id()); + .map(|f| &f.mem.ty); let parent_types = state_strct .state_members .iter() .filter(|f| f.dep_kind == DepKind::ParentDepState) - .map(|f| f.type_id()); + .map(|f| &f.mem.ty); let type_name_str = type_name.to_string(); let gen = quote! { impl State for #type_name{ - fn update_node_dep_state(&mut self, ty: std::any::TypeId, node: dioxus_native_core::real_dom_new_api::NodeRef, ctx: &anymap::AnyMap){ + fn update_node_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VElement<'a>, ctx: &anymap::AnyMap) -> bool{ use dioxus_native_core::real_dom_new_api::NodeDepState; - if false {} + if false { + unreachable!(); + } #node_dep_state_fields else{ - panic!("{:?} not in {}", ty, #type_name_str); + panic!("{:?} not in {}", ty, #type_name_str) } } - fn update_parent_dep_state(&mut self, ty: std::any::TypeId, node: dioxus_native_core::real_dom_new_api::NodeRef, parent: &Self, ctx: &anymap::AnyMap){ + fn update_parent_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VElement<'a>, parent: &Self, ctx: &anymap::AnyMap) -> bool{ use dioxus_native_core::real_dom_new_api::ParentDepState; - if false {} + if false { + unreachable!(); + } #parent_dep_state_fields else{ - panic!("{:?} not in {}", ty, #type_name_str); + panic!("{:?} not in {}", ty, #type_name_str) } } - fn update_child_dep_state(&mut self, ty: std::any::TypeId, node: dioxus_native_core::real_dom_new_api::NodeRef, children: Vec<&Self>, ctx: &anymap::AnyMap){ + fn update_child_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VElement<'a>, children: Vec<&Self>, ctx: &anymap::AnyMap) -> bool{ use dioxus_native_core::real_dom_new_api::ChildDepState; - if false {} + if false { + unreachable!() + } #child_dep_state_fields else{ - panic!("{:?} not in {}", ty, #type_name_str); + panic!("{:?} not in {}", ty, #type_name_str) } } - fn child_dep_types(&self) -> Vec{ - // todo: order should depend on order of dependencies - vec![ - #(#child_types,)* - ] + fn child_dep_types(&self, mask: &dioxus_native_core::real_dom_new_api::NodeMask) -> Vec{ + let mut dep_types = Vec::new(); + #(if #child_types::NODE_MASK.overlaps(mask) { + dep_types.push(std::any::TypeId::of::<#child_types>()); + })* + dep_types } - fn parent_dep_types(&self) -> Vec{ - // todo: order should depend on order of dependencies - vec![ - #(#parent_types,)* - ] + fn parent_dep_types(&self, mask: &dioxus_native_core::real_dom_new_api::NodeMask) -> Vec{ + let mut dep_types = Vec::new(); + #(if #parent_types::NODE_MASK.overlaps(mask) { + dep_types.push(std::any::TypeId::of::<#parent_types>()); + })* + dep_types } - fn node_dep_types(&self) -> Vec{ - vec![ - #(#node_types,)* - ] + fn node_dep_types(&self, mask: &dioxus_native_core::real_dom_new_api::NodeMask) -> Vec{ + let mut dep_types = Vec::new(); + #(if #node_types::NODE_MASK.overlaps(mask) { + dep_types.push(std::any::TypeId::of::<#node_types>()); + })* + dep_types } } }; @@ -176,6 +187,9 @@ impl<'a> StateStruct<'a> { .zip(fields.iter()) .filter_map(|(m, f)| StateMember::parse(f, m, &strct)) .collect(); + + // todo: sort members + Self { state_members } } } @@ -251,28 +265,30 @@ impl<'a> StateMember<'a> { } else { quote! {&()} }; + let ty = &self.mem.ty; + let node_view = quote!(NodeView::new(node, #ty::NODE_MASK)); if let Some(dep_ident) = &self.dep_mem.map(|m| &m.ident) { match self.dep_kind { DepKind::NodeDepState => { - quote!(self.#ident.reduce(node, #get_ctx);) + quote!(self.#ident.reduce(#node_view, #get_ctx)) } DepKind::ChildDepState => { - quote!(self.#ident.reduce(node, children.iter().map(|s| &s.#dep_ident).collect(), #get_ctx);) + quote!(self.#ident.reduce(#node_view, children.iter().map(|s| &s.#dep_ident).collect(), #get_ctx)) } DepKind::ParentDepState => { - quote!(self.#ident.reduce(node, &parent.#dep_ident, #get_ctx);) + quote!(self.#ident.reduce(#node_view, &parent.#dep_ident, #get_ctx)) } } } else { match self.dep_kind { DepKind::NodeDepState => { - quote!(self.#ident.reduce(node, #get_ctx);) + quote!(self.#ident.reduce(#node_view, #get_ctx)) } DepKind::ChildDepState => { - quote!(self.#ident.reduce(node, &(), #get_ctx);) + quote!(self.#ident.reduce(#node_view, &(), #get_ctx)) } DepKind::ParentDepState => { - quote!(self.#ident.reduce(node, &(), #get_ctx);) + quote!(self.#ident.reduce(#node_view, &(), #get_ctx)) } } } diff --git a/packages/native-core/src/real_dom_new_api.rs b/packages/native-core/src/real_dom_new_api.rs index 7740a97d4..269364c81 100644 --- a/packages/native-core/src/real_dom_new_api.rs +++ b/packages/native-core/src/real_dom_new_api.rs @@ -3,56 +3,141 @@ use std::any::TypeId; use anymap::AnyMap; use dioxus_core::{Attribute, VElement}; -#[repr(transparent)] -pub struct NodeRef<'a>(&'a VElement<'a>); -impl<'a> NodeRef<'a> { - pub fn new(velement: &'a VElement<'a>) -> Self { - Self(velement) +pub struct NodeView<'a> { + inner: &'a VElement<'a>, + view: NodeMask, +} +impl<'a> NodeView<'a> { + pub fn new(velement: &'a VElement<'a>, view: NodeMask) -> Self { + Self { + inner: velement, + view: view, + } } - pub fn tag(&self) -> &'a str { - self.0.tag + pub fn tag(&self) -> Option<&'a str> { + if self.view.tag { + Some(self.inner.tag) + } else { + None + } } pub fn namespace(&self) -> Option<&'a str> { - self.0.namespace + if self.view.namespace { + self.inner.namespace + } else { + None + } } - pub fn attributes(&self) -> &'a [Attribute<'a>] { - self.0.attributes + pub fn attributes(&self) -> impl Iterator> { + self.inner + .attributes + .iter() + .filter(|a| self.view.attritutes.contains(&a.name)) } } -pub trait ChildDepState: PartialEq { +#[derive(Default)] +pub struct NodeMask { + // must be sorted + attritutes: &'static [&'static str], + tag: bool, + namespace: bool, +} + +impl NodeMask { + /// attritutes must be sorted! + pub const fn new(attritutes: &'static [&'static str], tag: bool, namespace: bool) -> Self { + Self { + attritutes, + tag, + namespace, + } + } + + pub fn verify(&self) { + debug_assert!( + self.attritutes.windows(2).all(|w| w[0] < w[1]), + "attritutes must be increasing" + ); + } + + pub fn overlaps(&self, other: &Self) -> bool { + (self.tag && other.tag) + || (self.namespace && other.namespace) + || self.attritutes_overlap(other) + } + + fn attritutes_overlap(&self, other: &Self) -> bool { + let mut self_attrs = self.attritutes.iter(); + let mut other_attrs = other.attritutes.iter(); + if let Some(mut other_attr) = other_attrs.next() { + while let Some(self_attr) = self_attrs.next() { + while other_attr < self_attr { + if let Some(attr) = other_attrs.next() { + other_attr = attr; + } else { + return false; + } + } + if other_attr == self_attr { + return true; + } + } + } + false + } +} + +pub trait ChildDepState { type Ctx; type DepState: ChildDepState; - fn reduce(&mut self, node: NodeRef, children: Vec<&Self::DepState>, ctx: &Self::Ctx); + const NODE_MASK: NodeMask = NodeMask::new(&[], false, false); + fn reduce(&mut self, node: NodeView, children: Vec<&Self::DepState>, ctx: &Self::Ctx) -> bool; } -pub trait ParentDepState: PartialEq { +pub trait ParentDepState { type Ctx; type DepState: ParentDepState; - fn reduce(&mut self, node: NodeRef, parent: &Self::DepState, ctx: &Self::Ctx); + const NODE_MASK: NodeMask = NodeMask::new(&[], false, false); + fn reduce(&mut self, node: NodeView, parent: &Self::DepState, ctx: &Self::Ctx) -> bool; } -pub trait NodeDepState: PartialEq { +pub trait NodeDepState { type Ctx; - fn reduce(&mut self, node: NodeRef, ctx: &Self::Ctx); + const NODE_MASK: NodeMask = NodeMask::new(&[], false, false); + fn reduce(&mut self, node: NodeView, ctx: &Self::Ctx) -> bool; } pub trait State { - fn update_node_dep_state(&mut self, ty: TypeId, node: NodeRef, ctx: &AnyMap); - fn child_dep_types(&self) -> Vec; - - fn update_parent_dep_state(&mut self, ty: TypeId, node: NodeRef, parent: &Self, ctx: &AnyMap); - fn parent_dep_types(&self) -> Vec; - - fn update_child_dep_state( - &mut self, + fn update_node_dep_state<'a>( + &'a mut self, ty: TypeId, - node: NodeRef, + node: &'a VElement<'a>, + ctx: &AnyMap, + ) -> bool; + /// This must be a valid resolution order. (no nodes updated before a state they rely on) + fn child_dep_types(&self, mask: &NodeMask) -> Vec; + + fn update_parent_dep_state<'a>( + &'a mut self, + ty: TypeId, + node: &'a VElement<'a>, + parent: &Self, + ctx: &AnyMap, + ) -> bool; + /// This must be a valid resolution order. (no nodes updated before a state they rely on) + fn parent_dep_types(&self, mask: &NodeMask) -> Vec; + + fn update_child_dep_state<'a>( + &'a mut self, + ty: TypeId, + node: &'a VElement<'a>, children: Vec<&Self>, ctx: &AnyMap, - ); - fn node_dep_types(&self) -> Vec; + ) -> bool; + /// This must be a valid resolution order. (no nodes updated before a state they rely on) + fn node_dep_types(&self, mask: &NodeMask) -> Vec; } diff --git a/packages/native-core/tests/parse.rs b/packages/native-core/tests/parse.rs index c22e897df..8f680bf88 100644 --- a/packages/native-core/tests/parse.rs +++ b/packages/native-core/tests/parse.rs @@ -26,7 +26,7 @@ use dioxus_native_core::real_dom_new_api::NodeDepState; struct A; impl NodeDepState for A { type Ctx = (); - fn reduce(&mut self, _: NodeRef, _: &()) { + fn reduce(&mut self, _: NodeView, _: &()) -> bool { todo!() } } @@ -38,10 +38,10 @@ impl ChildDepState for B { type DepState = Self; fn reduce( &mut self, - _: dioxus_native_core::real_dom_new_api::NodeRef, + _: dioxus_native_core::real_dom_new_api::NodeView, _: Vec<&Self::DepState>, _: &i32, - ) { + ) -> bool { todo!() } } @@ -53,10 +53,10 @@ impl ParentDepState for C { type DepState = Self; fn reduce( &mut self, - _: dioxus_native_core::real_dom_new_api::NodeRef, + _: dioxus_native_core::real_dom_new_api::NodeView, _: &Self::DepState, _: &u8, - ) { + ) -> bool { todo!() } }