Jelajahi Sumber

add node dependancy

Evan Almloff 3 tahun lalu
induk
melakukan
436c6a02f7

+ 10 - 0
packages/native-core-macro/Cargo.toml

@@ -10,3 +10,13 @@ proc-macro = true
 [dependencies]
 [dependencies]
 syn = { version = "1.0.11", features = ["extra-traits"] }
 syn = { version = "1.0.11", features = ["extra-traits"] }
 quote = "1.0"
 quote = "1.0"
+dioxus-native-core = { path = "../native-core" }
+
+[dev-dependencies]
+dioxus-core = { path = "../core", version = "^0.2.0" }
+dioxus-html = { path = "../html", version = "^0.2.0" }
+dioxus-core-macro = { path = "../core-macro", version = "^0.2.0" }
+
+smallvec = "1.6"
+fxhash = "0.2"
+anymap = "0.12.1"

+ 438 - 225
packages/native-core-macro/src/lib.rs

@@ -1,38 +1,17 @@
 extern crate proc_macro;
 extern crate proc_macro;
 
 
-use std::collections::BTreeMap;
+mod sorted_slice;
 
 
+use dioxus_native_core::state::MemberId;
 use proc_macro::TokenStream;
 use proc_macro::TokenStream;
-use quote::{quote, ToTokens};
+use quote::{quote, ToTokens, __private::Span};
+use sorted_slice::StrSlice;
 use syn::{
 use syn::{
-    self, bracketed,
+    self,
     parse::{Parse, ParseStream, Result},
     parse::{Parse, ParseStream, Result},
-    parse_macro_input,
-    punctuated::Punctuated,
-    token::Paren,
-    Field, Ident, LitStr, Token, Type, TypeTuple,
+    parse_macro_input, parse_quote, Error, Field, Ident, Token, Type,
 };
 };
 
 
-struct StrSlice {
-    map: BTreeMap<String, LitStr>,
-}
-
-impl Parse for StrSlice {
-    fn parse(input: ParseStream) -> Result<Self> {
-        let content;
-        bracketed!(content in input);
-        let mut map = BTreeMap::new();
-        while let Ok(s) = content.parse::<LitStr>() {
-            map.insert(s.value(), s);
-            #[allow(unused_must_use)]
-            {
-                content.parse::<Token![,]>();
-            }
-        }
-        Ok(StrSlice { map })
-    }
-}
-
 #[proc_macro]
 #[proc_macro]
 pub fn sorted_str_slice(input: TokenStream) -> TokenStream {
 pub fn sorted_str_slice(input: TokenStream) -> TokenStream {
     let slice: StrSlice = parse_macro_input!(input as StrSlice);
     let slice: StrSlice = parse_macro_input!(input as StrSlice);
@@ -40,14 +19,13 @@ pub fn sorted_str_slice(input: TokenStream) -> TokenStream {
     quote!([#(#strings, )*]).into()
     quote!([#(#strings, )*]).into()
 }
 }
 
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Debug, Clone)]
 enum DepKind {
 enum DepKind {
     NodeDepState,
     NodeDepState,
     ChildDepState,
     ChildDepState,
     ParentDepState,
     ParentDepState,
 }
 }
 
 
-// macro that streams data from the State for any attributes that end with _
 #[proc_macro_derive(State, attributes(node_dep_state, child_dep_state, parent_dep_state))]
 #[proc_macro_derive(State, attributes(node_dep_state, child_dep_state, parent_dep_state))]
 pub fn state_macro_derive(input: TokenStream) -> TokenStream {
 pub fn state_macro_derive(input: TokenStream) -> TokenStream {
     let ast = syn::parse(input).unwrap();
     let ast = syn::parse(input).unwrap();
@@ -60,153 +38,149 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
         syn::Data::Struct(data) => match &data.fields {
         syn::Data::Struct(data) => match &data.fields {
             syn::Fields::Named(e) => &e.named,
             syn::Fields::Named(e) => &e.named,
             syn::Fields::Unnamed(_) => todo!("unnamed fields"),
             syn::Fields::Unnamed(_) => todo!("unnamed fields"),
-            syn::Fields::Unit => todo!("unit fields"),
+            syn::Fields::Unit => todo!("unit structs"),
         }
         }
         .iter()
         .iter()
         .collect(),
         .collect(),
         _ => unimplemented!(),
         _ => unimplemented!(),
     };
     };
-    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
-            .iter()
-            .filter(|f| f.dep_kind == DepKind::NodeDepState)
-            .map(|f| {
-                let ty_id = &f.type_id();
-                let reduce = &f.reduce_self();
-                quote! {
-                    else if ty == #ty_id {
-                        #reduce
+    let strct = Struct::new(type_name.clone(), &fields);
+    match StateStruct::parse(&fields, &strct) {
+        Ok(state_strct) => {
+            let node_dep_state_fields = state_strct
+                .state_members
+                .iter()
+                .filter(|f| f.dep_kind == DepKind::NodeDepState)
+                .map(|f| f.reduce_self());
+            let child_dep_state_fields = state_strct
+                .state_members
+                .iter()
+                .filter(|f| f.dep_kind == DepKind::ChildDepState)
+                .map(|f| f.reduce_self());
+            let parent_dep_state_fields = state_strct
+                .state_members
+                .iter()
+                .filter(|f| f.dep_kind == DepKind::ParentDepState)
+                .map(|f| f.reduce_self());
+
+            let node_iter = state_strct
+                .state_members
+                .iter()
+                .filter(|m| m.dep_kind == DepKind::NodeDepState);
+            let node_ids = node_iter.clone().map(|m| m.member_id.0);
+            let node_ids_clone = node_ids.clone();
+            let node_types = node_iter.map(|f| &f.mem.ty);
+
+            let child_iter = state_strct
+                .state_members
+                .iter()
+                .filter(|m| m.dep_kind == DepKind::ChildDepState);
+            let child_ids = child_iter.clone().map(|m| m.member_id.0);
+            let child_ids_clone = child_ids.clone();
+            let child_types = child_iter.map(|f| &f.mem.ty);
+
+            let parent_iter = state_strct
+                .state_members
+                .iter()
+                .filter(|m| m.dep_kind == DepKind::ParentDepState);
+            let parent_ids = parent_iter.clone().map(|m| m.member_id.0);
+            let parent_ids_clone = parent_ids.clone();
+            let parent_types = parent_iter.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<'a>(
+                        &'a mut self,
+                        ty: dioxus_native_core::state::MemberId,
+                        node: &'a dioxus_core::VNode<'a>,
+                        vdom: &'a dioxus_core::VirtualDom,
+                        ctx: &anymap::AnyMap,
+                    ) -> Option<dioxus_native_core::state::NodeStatesChanged>{
+                        use dioxus_native_core::state::NodeDepState as _;
+                        match ty.0{
+                            #(
+                                #node_ids => #node_dep_state_fields,
+                            )*
+                            _ => panic!("{:?} not in {}", ty, #type_name_str),
+                        }
                     }
                     }
-                }
-            }),
-    );
-    let child_dep_state_fields = quote::__private::TokenStream::from_iter(
-        state_strct
-            .state_members
-            .iter()
-            .filter(|f| f.dep_kind == DepKind::ChildDepState)
-            .map(|f| {
-                let ty_id = &f.type_id();
-                let reduce = &f.reduce_self();
-                quote! {
-                    else if ty == #ty_id {
-                        #reduce
+
+                    fn update_parent_dep_state<'a>(
+                        &'a mut self,
+                        ty: dioxus_native_core::state::MemberId,
+                        node: &'a dioxus_core::VNode<'a>,
+                        vdom: &'a dioxus_core::VirtualDom,
+                        parent: Option<&Self>,
+                        ctx: &anymap::AnyMap,
+                    ) -> Option<dioxus_native_core::state::ParentStatesChanged>{
+                        use dioxus_native_core::state::ParentDepState as _;
+                        match ty.0{
+                            #(
+                                #parent_ids => #parent_dep_state_fields,
+                            )*
+                            _ => panic!("{:?} not in {}", ty, #type_name_str),
+                        }
                     }
                     }
-                }
-            }),
-    );
-    let parent_dep_state_fields = quote::__private::TokenStream::from_iter(
-        state_strct
-            .state_members
-            .iter()
-            .filter(|f| f.dep_kind == DepKind::ParentDepState)
-            .map(|f| {
-                let ty_id = &f.type_id();
-                let reduce = &f.reduce_self();
-                quote! {
-                    else if ty == #ty_id {
-                        #reduce
+
+                    fn update_child_dep_state<'a>(
+                        &'a mut self,
+                        ty: dioxus_native_core::state::MemberId,
+                        node: &'a dioxus_core::VNode<'a>,
+                        vdom: &'a dioxus_core::VirtualDom,
+                        children: &[&Self],
+                        ctx: &anymap::AnyMap,
+                    ) -> Option<dioxus_native_core::state::ChildStatesChanged>{
+                        use dioxus_native_core::state::ChildDepState as _;
+                        match ty.0{
+                            #(
+                                #child_ids => {#child_dep_state_fields},
+                            )*
+                            _ => panic!("{:?} not in {}", ty, #type_name_str),
+                        }
                     }
                     }
-                }
-            }),
-    );
 
 
-    let node_types = state_strct
-        .state_members
-        .iter()
-        .filter(|f| f.dep_kind == DepKind::NodeDepState)
-        .map(|f| &f.mem.ty);
-    let child_types = state_strct
-        .state_members
-        .iter()
-        .filter(|f| f.dep_kind == DepKind::ChildDepState)
-        .map(|f| &f.mem.ty);
-    let parent_types = state_strct
-        .state_members
-        .iter()
-        .filter(|f| f.dep_kind == DepKind::ParentDepState)
-        .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<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, ctx: &anymap::AnyMap) -> bool{
-                use dioxus_native_core::state::NodeDepState as _;
-                // println!("called update_node_dep_state with ty: {:?}", ty);
-                if false {
-                    unreachable!();
-                }
-                #node_dep_state_fields
-                else{
-                    panic!("{:?} not in {}", ty, #type_name_str)
-                }
-            }
+                    fn child_dep_types(&self, mask: &dioxus_native_core::node_ref::NodeMask) -> Vec<dioxus_native_core::state::MemberId>{
+                        let mut dep_types = Vec::new();
+                        #(if #child_types::NODE_MASK.overlaps(mask) {
+                            dep_types.push(dioxus_native_core::state::MemberId(#child_ids_clone));
+                        })*
+                        dep_types
+                    }
 
 
-            fn update_parent_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, parent: Option<&Self>, ctx: &anymap::AnyMap) -> bool{
-                use dioxus_native_core::state::ParentDepState as _;
-                // println!("called update_parent_dep_state with ty: {:?}", ty);
-                if false {
-                    unreachable!();
-                }
-                #parent_dep_state_fields
-                else{
-                    panic!("{:?} not in {}", ty, #type_name_str)
-                }
-            }
+                    fn parent_dep_types(&self, mask: &dioxus_native_core::node_ref::NodeMask) -> Vec<dioxus_native_core::state::MemberId>{
+                        let mut dep_types = Vec::new();
+                        #(if #parent_types::NODE_MASK.overlaps(mask) {
+                            dep_types.push(dioxus_native_core::state::MemberId(#parent_ids_clone));
+                        })*
+                        dep_types
+                    }
 
 
-            fn update_child_dep_state<'a>(&'a mut self, ty: std::any::TypeId, node: &'a dioxus_core::VNode<'a>, vdom: &'a dioxus_core::VirtualDom, children: &[&Self], ctx: &anymap::AnyMap) -> bool{
-                use dioxus_native_core::state::ChildDepState as _;
-                // println!("called update_child_dep_state with ty: {:?}", ty);
-                if false {
-                    unreachable!()
-                }
-                #child_dep_state_fields
-                else{
-                    panic!("{:?} not in {}", ty, #type_name_str)
+                    fn node_dep_types(&self, mask: &dioxus_native_core::node_ref::NodeMask) -> Vec<dioxus_native_core::state::MemberId>{
+                        let mut dep_types = Vec::new();
+                        #(if #node_types::NODE_MASK.overlaps(mask) {
+                            dep_types.push(dioxus_native_core::state::MemberId(#node_ids_clone));
+                        })*
+                        dep_types
+                    }
                 }
                 }
-            }
-
-            fn child_dep_types(&self, mask: &dioxus_native_core::state::NodeMask) -> Vec<std::any::TypeId>{
-                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, mask: &dioxus_native_core::state::NodeMask) -> Vec<std::any::TypeId>{
-                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, mask: &dioxus_native_core::state::NodeMask) -> Vec<std::any::TypeId>{
-                let mut dep_types = Vec::new();
-                #(if #node_types::NODE_MASK.overlaps(mask) {
-                    dep_types.push(std::any::TypeId::of::<#node_types>());
-                })*
-                dep_types
-            }
+            };
+            gen.into()
         }
         }
-    };
-    gen.into()
+        Err(e) => e.into_compile_error().into(),
+    }
 }
 }
 
 
 struct Struct {
 struct Struct {
+    name: Ident,
     members: Vec<Member>,
     members: Vec<Member>,
 }
 }
 
 
 impl Struct {
 impl Struct {
-    fn parse(fields: &[&Field]) -> Self {
+    fn new(name: Ident, fields: &[&Field]) -> Self {
         let members = fields.iter().filter_map(|f| Member::parse(f)).collect();
         let members = fields.iter().filter_map(|f| Member::parse(f)).collect();
-        Self { members }
+        Self { name, members }
     }
     }
 }
 }
 
 
@@ -215,57 +189,198 @@ struct StateStruct<'a> {
 }
 }
 
 
 impl<'a> StateStruct<'a> {
 impl<'a> StateStruct<'a> {
-    fn parse(fields: &[&'a Field], strct: &'a Struct) -> Self {
-        let state_members = strct
+    fn parse(fields: &[&'a Field], strct: &'a Struct) -> Result<Self> {
+        let mut parse_err = Ok(());
+        let state_members: Vec<_> = strct
             .members
             .members
             .iter()
             .iter()
             .zip(fields.iter())
             .zip(fields.iter())
-            .filter_map(|(m, f)| StateMember::parse(f, m, &strct))
+            .filter_map(|(m, f)| match StateMember::parse(f, m, &strct) {
+                Ok(m) => m,
+                Err(err) => {
+                    parse_err = Err(err);
+                    None
+                }
+            })
             .collect();
             .collect();
+        parse_err?;
+
+        #[derive(Debug, Clone)]
+        struct DepNode<'a> {
+            state_mem: StateMember<'a>,
+            depandants: Vec<Box<DepNode<'a>>>,
+        }
+        impl<'a> DepNode<'a> {
+            fn new(state_mem: StateMember<'a>) -> Self {
+                Self {
+                    state_mem,
+                    depandants: Vec::new(),
+                }
+            }
+
+            /// flattens the node in pre order
+            fn flatten(self) -> Vec<StateMember<'a>> {
+                let DepNode {
+                    state_mem,
+                    depandants,
+                } = self;
+                let mut flat = vec![state_mem];
+                for d in depandants {
+                    flat.append(&mut d.flatten());
+                }
+                flat
+            }
+
+            fn set_ids(&mut self, current_id: &mut usize) {
+                self.state_mem.member_id = dioxus_native_core::state::MemberId(*current_id);
+                // if the node depends on itself, we need to add the dependency seperately
+                if let Some(dep) = self.state_mem.dep_mem {
+                    if dep == self.state_mem.mem {
+                        self.state_mem
+                            .dependants
+                            .push((MemberId(*current_id), self.state_mem.dep_kind.clone()));
+                    }
+                }
+                *current_id += 1;
+                for d in &mut self.depandants {
+                    self.state_mem
+                        .dependants
+                        .push((MemberId(*current_id), d.state_mem.dep_kind.clone()));
+                    d.set_ids(current_id);
+                }
+            }
+
+            fn contains_member(&self, member: &Member) -> bool {
+                if self.state_mem.mem == member {
+                    true
+                } else {
+                    self.depandants.iter().any(|d| d.contains_member(member))
+                }
+            }
 
 
-        // todo: sort members
+            // check if there are any mixed child/parent dependancies
+            fn check(&self) -> Option<Error> {
+                self.kind().err()
+            }
+
+            fn kind(&self) -> Result<&DepKind> {
+                fn reduce_kind<'a>(dk1: &'a DepKind, dk2: &'a DepKind) -> Result<&'a DepKind> {
+                    match (dk1, dk2) {
+                        (DepKind::ChildDepState, DepKind::ParentDepState)
+                        | (DepKind::ParentDepState, DepKind::ChildDepState) => Err(Error::new(
+                            Span::call_site(),
+                            "There is a ChildDepState that depends on a ParentDepState",
+                        )),
+                        // node dep state takes the lowest priority
+                        (DepKind::NodeDepState, important) | (important, DepKind::NodeDepState) => {
+                            Ok(important)
+                        }
+                        // they are the same
+                        (fst, _) => Ok(fst),
+                    }
+                }
+                reduce_kind(
+                    self.depandants
+                        .iter()
+                        .try_fold(&DepKind::NodeDepState, |dk1, dk2| {
+                            reduce_kind(dk1, dk2.kind()?)
+                        })?,
+                    &self.state_mem.dep_kind,
+                )
+            }
 
 
-        Self { state_members }
+            fn insert_dependant(&mut self, other: DepNode<'a>) -> bool {
+                let dep = other.state_mem.dep_mem.unwrap();
+                if self.contains_member(dep) {
+                    if self.state_mem.mem == dep {
+                        self.depandants.push(Box::new(other));
+                        true
+                    } else {
+                        self.depandants
+                            .iter_mut()
+                            .find(|d| d.contains_member(dep))
+                            .unwrap()
+                            .insert_dependant(other)
+                    }
+                } else {
+                    false
+                }
+            }
+        }
+
+        // members need to be sorted so that members are updated after the members they depend on
+        let mut roots: Vec<DepNode> = vec![];
+        for m in state_members.into_iter() {
+            if let Some(dep) = m.dep_mem {
+                let root_depends_on = roots
+                    .iter()
+                    .filter_map(|m| m.state_mem.dep_mem)
+                    .any(|d| m.mem == d);
+
+                if let Some(r) = roots.iter_mut().find(|r| r.contains_member(dep)) {
+                    let new = DepNode::new(m);
+                    if root_depends_on {
+                        return Err(Error::new(
+                            new.state_mem.mem.ident.span(),
+                            format!("{} has a circular dependancy", new.state_mem.mem.ident),
+                        ));
+                    }
+                    // return Err(Error::new(new.state_mem.mem.ident.span(), "stuff"));
+                    r.insert_dependant(new);
+                    continue;
+                }
+            }
+            let mut new = DepNode::new(m);
+            let mut i = 0;
+            while i < roots.len() {
+                if roots[i].state_mem.dep_mem == Some(new.state_mem.mem) {
+                    let child = roots.remove(i);
+                    new.insert_dependant(child);
+                } else {
+                    i += 1;
+                }
+            }
+            roots.push(new);
+        }
+        let mut current_id = 0;
+        for r in &mut roots {
+            r.set_ids(&mut current_id);
+        }
+        if let Some(err) = roots.iter().find_map(DepNode::check) {
+            Err(err)
+        } else {
+            let state_members: Vec<_> = roots
+                .into_iter()
+                .map(|r| r.flatten().into_iter())
+                .flatten()
+                .collect();
+
+            Ok(Self { state_members })
+        }
     }
     }
 }
 }
 
 
-struct DepTypes {
+struct Dependancy {
     ctx_ty: Option<Type>,
     ctx_ty: Option<Type>,
-    dep_ty: Option<Type>,
+    dep: Option<Ident>,
 }
 }
 
 
-impl Parse for DepTypes {
+impl Parse for Dependancy {
     fn parse(input: ParseStream) -> Result<Self> {
     fn parse(input: ParseStream) -> Result<Self> {
-        let dep_ty = input.parse().ok();
+        let dep = input
+            .parse()
+            .ok()
+            .filter(|i: &Ident| format!("{}", i) != "NONE");
         let comma: Option<Token![,]> = input.parse().ok();
         let comma: Option<Token![,]> = input.parse().ok();
         let ctx_ty = input.parse().ok();
         let ctx_ty = input.parse().ok();
         Ok(Self {
         Ok(Self {
             ctx_ty: comma.and(ctx_ty),
             ctx_ty: comma.and(ctx_ty),
-            dep_ty,
+            dep,
         })
         })
     }
     }
 }
 }
 
 
-struct NodeDepTypes {
-    ctx_ty: Option<Type>,
-}
-
-impl Parse for NodeDepTypes {
-    fn parse(input: ParseStream) -> Result<Self> {
-        let ctx_ty = input.parse().ok();
-        Ok(Self { ctx_ty })
-    }
-}
-
-impl From<NodeDepTypes> for DepTypes {
-    fn from(node_dep_types: NodeDepTypes) -> Self {
-        Self {
-            ctx_ty: node_dep_types.ctx_ty,
-            dep_ty: None,
-        }
-    }
-}
-
+#[derive(PartialEq, Debug)]
 struct Member {
 struct Member {
     ty: Type,
     ty: Type,
     ident: Ident,
     ident: Ident,
@@ -280,16 +395,25 @@ impl Member {
     }
     }
 }
 }
 
 
+#[derive(Debug, Clone)]
 struct StateMember<'a> {
 struct StateMember<'a> {
     mem: &'a Member,
     mem: &'a Member,
     dep_kind: DepKind,
     dep_kind: DepKind,
     dep_mem: Option<&'a Member>,
     dep_mem: Option<&'a Member>,
     ctx_ty: Option<Type>,
     ctx_ty: Option<Type>,
+    dependants: Vec<(dioxus_native_core::state::MemberId, DepKind)>,
+    // This is just the index of the final order of the struct it is used to communicate which parts need updated and what order to update them in.
+    member_id: dioxus_native_core::state::MemberId,
 }
 }
 
 
 impl<'a> StateMember<'a> {
 impl<'a> StateMember<'a> {
-    fn parse(field: &Field, mem: &'a Member, parent: &'a Struct) -> Option<StateMember<'a>> {
-        field.attrs.iter().find_map(|a| {
+    fn parse(
+        field: &Field,
+        mem: &'a Member,
+        parent: &'a Struct,
+    ) -> Result<Option<StateMember<'a>>> {
+        let mut err = Ok(());
+        let member = field.attrs.iter().find_map(|a| {
             let dep_kind = a
             let dep_kind = a
                 .path
                 .path
                 .get_ident()
                 .get_ident()
@@ -300,34 +424,44 @@ impl<'a> StateMember<'a> {
                     _ => None,
                     _ => None,
                 })
                 })
                 .flatten()?;
                 .flatten()?;
-            let deps: DepTypes = match dep_kind {
-                DepKind::NodeDepState => a.parse_args::<NodeDepTypes>().ok()?.into(),
-                _ => a.parse_args().ok()?,
-            };
-
-            Some(Self {
-                mem,
-                dep_kind,
-                dep_mem: deps
-                    .dep_ty
-                    .map(|ty| parent.members.iter().find(|m| m.ty == ty))
-                    .flatten(),
-                ctx_ty: deps.ctx_ty,
-            })
-        })
+            match a.parse_args::<Dependancy>() {
+                Ok(dependancy) => {
+                    let dep_mem = if let Some(name) = &dependancy.dep {
+                        if let Some(found) = parent.members.iter().find(|m| &m.ident == name) {
+                            Some(found)
+                        } else {
+                            err = Err(Error::new(
+                                name.span(),
+                                format!("{} not found in {}", name, parent.name),
+                            ));
+                            None
+                        }
+                    } else {
+                        None
+                    };
+                    Some(Self {
+                        mem,
+                        dep_kind,
+                        dep_mem,
+                        ctx_ty: dependancy.ctx_ty,
+                        dependants: Vec::new(),
+                        member_id: dioxus_native_core::state::MemberId(0),
+                    })
+                }
+                Err(e) => {
+                    err = Err(e);
+                    None
+                }
+            }
+        });
+        err?;
+        Ok(member)
     }
     }
 
 
     fn reduce_self(&self) -> quote::__private::TokenStream {
     fn reduce_self(&self) -> quote::__private::TokenStream {
         let ident = &self.mem.ident;
         let ident = &self.mem.ident;
         let get_ctx = if let Some(ctx_ty) = &self.ctx_ty {
         let get_ctx = if let Some(ctx_ty) = &self.ctx_ty {
-            if ctx_ty
-                == &Type::Tuple(TypeTuple {
-                    paren_token: Paren {
-                        span: quote::__private::Span::call_site(),
-                    },
-                    elems: Punctuated::new(),
-                })
-            {
+            if ctx_ty == &parse_quote!(()) {
                 quote! {&()}
                 quote! {&()}
             } else {
             } else {
                 let msg = ctx_ty.to_token_stream().to_string() + " not found in context";
                 let msg = ctx_ty.to_token_stream().to_string() + " not found in context";
@@ -336,40 +470,119 @@ impl<'a> StateMember<'a> {
         } else {
         } else {
             quote! {&()}
             quote! {&()}
         };
         };
+        let states_changed = {
+            let child_dep = self
+                .dependants
+                .iter()
+                .filter(|(_, kind)| kind == &DepKind::ChildDepState)
+                .map(|(id, _)| id.0);
+            let parent_dep = self
+                .dependants
+                .iter()
+                .filter(|(_, kind)| kind == &DepKind::ParentDepState)
+                .map(|(id, _)| id.0);
+            let node_dep = self
+                .dependants
+                .iter()
+                .filter(|(_, kind)| kind == &DepKind::NodeDepState)
+                .map(|(id, _)| id.0);
+            match self.dep_kind {
+                DepKind::NodeDepState => {
+                    quote! {
+                        dioxus_native_core::state::NodeStatesChanged{
+                            node_dep: &[#(dioxus_native_core::state::MemberId(#node_dep), )*],
+                        }
+                    }
+                }
+                DepKind::ChildDepState => {
+                    quote! {
+                        dioxus_native_core::state::ChildStatesChanged{
+                            node_dep: &[#(dioxus_native_core::state::MemberId(#node_dep), )*],
+                            child_dep: &[#(dioxus_native_core::state::MemberId(#child_dep), )*],
+                        }
+                    }
+                }
+                DepKind::ParentDepState => {
+                    quote! {
+                        dioxus_native_core::state::ParentStatesChanged{
+                            node_dep: &[#(dioxus_native_core::state::MemberId(#node_dep), )*],
+                            parent_dep: &[#(dioxus_native_core::state::MemberId(#parent_dep), )*],
+                        }
+                    }
+                }
+            }
+        };
+
         let ty = &self.mem.ty;
         let ty = &self.mem.ty;
-        let node_view = quote!(NodeView::new(node, #ty::NODE_MASK, vdom));
+        let node_view =
+            quote!(dioxus_native_core::node_ref::NodeView::new(node, #ty::NODE_MASK, vdom));
+        let id = self.member_id.0;
         if let Some(dep_ident) = &self.dep_mem.map(|m| &m.ident) {
         if let Some(dep_ident) = &self.dep_mem.map(|m| &m.ident) {
             match self.dep_kind {
             match self.dep_kind {
                 DepKind::NodeDepState => {
                 DepKind::NodeDepState => {
-                    quote!(self.#ident.reduce(#node_view, #get_ctx))
+                    quote!({
+                        // println!("node: {:?} {:?} {:?}", self.#ident, #id, #node_view.id());
+                        if self.#ident.reduce(#node_view, &self.#dep_ident, #get_ctx){
+                            Some(#states_changed)
+                        } else{
+                            None
+                        }
+                    })
                 }
                 }
                 DepKind::ChildDepState => {
                 DepKind::ChildDepState => {
-                    quote!(self.#ident.reduce(#node_view, children.iter().map(|s| &s.#dep_ident), #get_ctx))
+                    quote!({
+                        // println!("child: {:?} {:?} {:?}", self.#ident, #id, #node_view.id());
+                        if self.#ident.reduce(#node_view, children.iter().map(|s| &s.#dep_ident), #get_ctx){
+                            Some(#states_changed)
+                        } else{
+                            None
+                        }
+                    })
                 }
                 }
                 DepKind::ParentDepState => {
                 DepKind::ParentDepState => {
-                    quote!(self.#ident.reduce(#node_view, parent.as_ref().map(|p| &p.#dep_ident), #get_ctx))
+                    quote!({
+                        // println!("parent: {:?} {:?} {:?}", self.#ident, #id, #node_view.id());
+                        if self.#ident.reduce(#node_view, parent.as_ref().map(|p| &p.#dep_ident), #get_ctx){
+                            Some(#states_changed)
+                        } else{
+                            None
+                        }
+                    })
                 }
                 }
             }
             }
         } else {
         } else {
             match self.dep_kind {
             match self.dep_kind {
                 DepKind::NodeDepState => {
                 DepKind::NodeDepState => {
-                    quote!(self.#ident.reduce(#node_view, #get_ctx))
+                    quote!({
+                        // println!("node: {:?} {:?} {:?}", self.#ident, #id, #node_view.id());
+                        if self.#ident.reduce(#node_view, &(), #get_ctx){
+                            Some(#states_changed)
+                        } else{
+                            None
+                        }
+                    })
                 }
                 }
                 DepKind::ChildDepState => {
                 DepKind::ChildDepState => {
-                    quote!(self.#ident.reduce(#node_view, &(), #get_ctx))
+                    quote!({
+                        // println!("child: {:?} {:?} {:?}", self.#ident, #id, #node_view.id());
+                        if self.#ident.reduce(#node_view, std::iter::empty(), #get_ctx){
+                            Some(#states_changed)
+                        } else{
+                            None
+                        }
+                    })
                 }
                 }
                 DepKind::ParentDepState => {
                 DepKind::ParentDepState => {
-                    quote!(self.#ident.reduce(#node_view, Some(&()), #get_ctx))
+                    quote!({
+                        println!("parent: {:?} {:?} {:?}", self.#ident, #id, #node_view.id());
+                        if self.#ident.reduce(#node_view, Some(&()), #get_ctx){
+                            Some(#states_changed)
+                        } else{
+                            None
+                        }
+                    })
                 }
                 }
             }
             }
         }
         }
     }
     }
-
-    fn type_id(&self) -> quote::__private::TokenStream {
-        let ty = &self.mem.ty;
-        quote!({
-            let type_id = std::any::TypeId::of::<#ty>();
-            type_id
-        })
-    }
 }
 }

+ 28 - 0
packages/native-core-macro/src/sorted_slice.rs

@@ -0,0 +1,28 @@
+extern crate proc_macro;
+
+use std::collections::BTreeMap;
+
+use syn::{
+    self, bracketed,
+    parse::{Parse, ParseStream, Result},
+    LitStr, Token,
+};
+pub struct StrSlice {
+    pub map: BTreeMap<String, LitStr>,
+}
+
+impl Parse for StrSlice {
+    fn parse(input: ParseStream) -> Result<Self> {
+        let content;
+        bracketed!(content in input);
+        let mut map = BTreeMap::new();
+        while let Ok(s) = content.parse::<LitStr>() {
+            map.insert(s.value(), s);
+            #[allow(unused_must_use)]
+            {
+                content.parse::<Token![,]>();
+            }
+        }
+        Ok(StrSlice { map })
+    }
+}

+ 0 - 0
packages/native-core/tests/change_nodes.rs → packages/native-core-macro/tests/change_nodes.rs


+ 1 - 1
packages/native-core/tests/initial_build.rs → packages/native-core-macro/tests/initial_build.rs

@@ -8,7 +8,7 @@ use dioxus_native_core::real_dom::RealDom;
 use dioxus_native_core::state::State;
 use dioxus_native_core::state::State;
 use dioxus_native_core_macro::State;
 use dioxus_native_core_macro::State;
 
 
-#[derive(State, Default, Clone)]
+#[derive(Default, Clone, State)]
 struct Empty {}
 struct Empty {}
 
 
 #[test]
 #[test]

+ 74 - 0
packages/native-core-macro/tests/parse.rs

@@ -0,0 +1,74 @@
+use dioxus_native_core::node_ref::*;
+use dioxus_native_core::state::*;
+use dioxus_native_core_macro::*;
+
+#[derive(State, Default, Clone)]
+#[allow(dead_code)]
+struct Z {
+    // depends on text, the C component of it's parent and a u16 context
+    #[parent_dep_state(c, u16)]
+    d: D,
+    // depends on just attributes and no context
+    #[node_dep_state()]
+    a: A,
+    // depends on the B component of children and i32 context
+    #[child_dep_state(b, i32)]
+    b: B,
+    // depends on the C component of it's parent and a u8 context
+    #[parent_dep_state(c, u8)]
+    c: C,
+    // this will remain uneffected on updates
+    n: i32,
+}
+
+use dioxus_native_core::state::NodeDepState;
+
+#[derive(Default, Clone, Debug)]
+struct A;
+impl NodeDepState for A {
+    type Ctx = ();
+    type DepState = ();
+    const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::All, false, false, false);
+    fn reduce(&mut self, _: NodeView, _: &Self::DepState, _: &()) -> bool {
+        todo!()
+    }
+}
+
+#[derive(Default, Clone, Debug)]
+struct B;
+impl ChildDepState for B {
+    type Ctx = i32;
+    type DepState = Self;
+    fn reduce<'a>(
+        &mut self,
+        _: NodeView,
+        _: impl Iterator<Item = &'a Self::DepState>,
+        _: &i32,
+    ) -> bool
+    where
+        Self::DepState: 'a,
+    {
+        todo!()
+    }
+}
+
+#[derive(Default, Clone, Debug)]
+struct C;
+impl ParentDepState for C {
+    type Ctx = u8;
+    type DepState = Self;
+    fn reduce(&mut self, _: NodeView, _: Option<&Self::DepState>, _: &u8) -> bool {
+        todo!()
+    }
+}
+
+#[derive(Default, Clone, Debug)]
+struct D;
+impl ParentDepState for D {
+    type Ctx = u16;
+    type DepState = C;
+    const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::NONE, false, false, true);
+    fn reduce(&mut self, _: NodeView, _: Option<&Self::DepState>, _: &u16) -> bool {
+        todo!()
+    }
+}

+ 70 - 0
packages/native-core-macro/tests/test.rs

@@ -0,0 +1,70 @@
+use dioxus_native_core::node_ref::*;
+use dioxus_native_core::state::{ChildDepState, NodeDepState, ParentDepState, State};
+use dioxus_native_core_macro::State;
+#[derive(Debug, Clone, PartialEq, Default)]
+struct BubbledUpStateTester(Option<String>, Vec<Box<BubbledUpStateTester>>);
+impl ChildDepState for BubbledUpStateTester {
+    type Ctx = u32;
+    type DepState = Self;
+    const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::NONE, true, false, false);
+    fn reduce<'a>(
+        &mut self,
+        node: NodeView,
+        children: impl Iterator<Item = &'a Self::DepState>,
+        ctx: &Self::Ctx,
+    ) -> bool
+    where
+        Self::DepState: 'a,
+    {
+        assert_eq!(*ctx, 42);
+        *self = BubbledUpStateTester(
+            node.tag().map(|s| s.to_string()),
+            children.into_iter().map(|c| Box::new(c.clone())).collect(),
+        );
+        true
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Default)]
+struct PushedDownStateTester(Option<String>, Option<Box<PushedDownStateTester>>);
+impl ParentDepState for PushedDownStateTester {
+    type Ctx = u32;
+    type DepState = Self;
+    const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::NONE, true, false, false);
+    fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, ctx: &Self::Ctx) -> bool {
+        assert_eq!(*ctx, 42);
+        *self = PushedDownStateTester(
+            node.tag().map(|s| s.to_string()),
+            parent.map(|c| Box::new(c.clone())),
+        );
+        true
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Default)]
+struct NodeStateTester(Option<String>, Vec<(String, String)>);
+impl NodeDepState for NodeStateTester {
+    type Ctx = u32;
+    type DepState = ();
+    const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::All, true, false, false);
+    fn reduce(&mut self, node: NodeView, _sibling: &Self::DepState, ctx: &Self::Ctx) -> bool {
+        assert_eq!(*ctx, 42);
+        *self = NodeStateTester(
+            node.tag().map(|s| s.to_string()),
+            node.attributes()
+                .map(|a| (a.name.to_string(), a.value.to_string()))
+                .collect(),
+        );
+        true
+    }
+}
+
+#[derive(State, Clone, Default, Debug)]
+struct StateTester {
+    #[child_dep_state(bubbled, u32)]
+    bubbled: BubbledUpStateTester,
+    #[parent_dep_state(pushed, u32)]
+    pushed: PushedDownStateTester,
+    #[node_dep_state(NONE, u32)]
+    node: NodeStateTester,
+}

+ 119 - 32
packages/native-core/tests/update_state.rs → packages/native-core-macro/tests/update_state.rs

@@ -3,17 +3,16 @@ use dioxus_core::VNode;
 use dioxus_core::*;
 use dioxus_core::*;
 use dioxus_core_macro::*;
 use dioxus_core_macro::*;
 use dioxus_html as dioxus_elements;
 use dioxus_html as dioxus_elements;
+use dioxus_native_core::node_ref::*;
 use dioxus_native_core::real_dom::*;
 use dioxus_native_core::real_dom::*;
-use dioxus_native_core::state::{
-    AttributeMask, ChildDepState, NodeDepState, NodeMask, NodeView, ParentDepState, State,
-};
+use dioxus_native_core::state::{ChildDepState, NodeDepState, ParentDepState, State};
 use dioxus_native_core_macro::State;
 use dioxus_native_core_macro::State;
 
 
 #[derive(Debug, Clone, Default, State)]
 #[derive(Debug, Clone, Default, State)]
 struct CallCounterState {
 struct CallCounterState {
-    #[child_dep_state(ChildDepCallCounter)]
+    #[child_dep_state(child_counter)]
     child_counter: ChildDepCallCounter,
     child_counter: ChildDepCallCounter,
-    #[parent_dep_state(ParentDepCallCounter)]
+    #[parent_dep_state(parent_counter)]
     parent_counter: ParentDepCallCounter,
     parent_counter: ParentDepCallCounter,
     #[node_dep_state()]
     #[node_dep_state()]
     node_counter: NodeDepCallCounter,
     node_counter: NodeDepCallCounter,
@@ -60,8 +59,9 @@ impl ParentDepState for ParentDepCallCounter {
 struct NodeDepCallCounter(u32);
 struct NodeDepCallCounter(u32);
 impl NodeDepState for NodeDepCallCounter {
 impl NodeDepState for NodeDepCallCounter {
     type Ctx = ();
     type Ctx = ();
+    type DepState = ();
     const NODE_MASK: NodeMask = NodeMask::ALL;
     const NODE_MASK: NodeMask = NodeMask::ALL;
-    fn reduce(&mut self, _node: NodeView, _ctx: &Self::Ctx) -> bool {
+    fn reduce(&mut self, _node: NodeView, _sibling: &Self::DepState, _ctx: &Self::Ctx) -> bool {
         self.0 += 1;
         self.0 += 1;
         true
         true
     }
     }
@@ -107,22 +107,13 @@ impl ParentDepState for PushedDownStateTester {
     }
     }
 }
 }
 
 
-#[derive(State, Clone, Default, Debug)]
-struct StateTester {
-    #[child_dep_state(BubbledUpStateTester, u32)]
-    bubbled: BubbledUpStateTester,
-    #[parent_dep_state(PushedDownStateTester, u32)]
-    pushed: PushedDownStateTester,
-    #[node_dep_state(u32)]
-    node: NodeStateTester,
-}
-
 #[derive(Debug, Clone, PartialEq, Default)]
 #[derive(Debug, Clone, PartialEq, Default)]
 struct NodeStateTester(Option<String>, Vec<(String, String)>);
 struct NodeStateTester(Option<String>, Vec<(String, String)>);
 impl NodeDepState for NodeStateTester {
 impl NodeDepState for NodeStateTester {
     type Ctx = u32;
     type Ctx = u32;
+    type DepState = ();
     const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::All, true, false, false);
     const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::All, true, false, false);
-    fn reduce(&mut self, node: NodeView, ctx: &Self::Ctx) -> bool {
+    fn reduce(&mut self, node: NodeView, _sibling: &Self::DepState, ctx: &Self::Ctx) -> bool {
         assert_eq!(*ctx, 42);
         assert_eq!(*ctx, 42);
         *self = NodeStateTester(
         *self = NodeStateTester(
             node.tag().map(|s| s.to_string()),
             node.tag().map(|s| s.to_string()),
@@ -134,6 +125,16 @@ impl NodeDepState for NodeStateTester {
     }
     }
 }
 }
 
 
+#[derive(State, Clone, Default, Debug)]
+struct StateTester {
+    #[child_dep_state(bubbled, u32)]
+    bubbled: BubbledUpStateTester,
+    #[parent_dep_state(pushed, u32)]
+    pushed: PushedDownStateTester,
+    #[node_dep_state(NONE, u32)]
+    node: NodeStateTester,
+}
+
 #[test]
 #[test]
 fn state_initial() {
 fn state_initial() {
     #[allow(non_snake_case)]
     #[allow(non_snake_case)]
@@ -172,7 +173,10 @@ fn state_initial() {
         ]
         ]
     );
     );
     assert_eq!(root_div.state.pushed.0, Some("div".to_string()));
     assert_eq!(root_div.state.pushed.0, Some("div".to_string()));
-    assert_eq!(root_div.state.pushed.1, None);
+    assert_eq!(
+        root_div.state.pushed.1,
+        Some(Box::new(PushedDownStateTester(None, None)))
+    );
     assert_eq!(root_div.state.node.0, Some("div".to_string()));
     assert_eq!(root_div.state.node.0, Some("div".to_string()));
     assert_eq!(root_div.state.node.1, vec![]);
     assert_eq!(root_div.state.node.1, vec![]);
 
 
@@ -184,7 +188,7 @@ fn state_initial() {
         child_p.state.pushed.1,
         child_p.state.pushed.1,
         Some(Box::new(PushedDownStateTester(
         Some(Box::new(PushedDownStateTester(
             Some("div".to_string()),
             Some("div".to_string()),
-            None
+            Some(Box::new(PushedDownStateTester(None, None)))
         )))
         )))
     );
     );
     assert_eq!(child_p.state.node.0, Some("p".to_string()));
     assert_eq!(child_p.state.node.0, Some("p".to_string()));
@@ -201,7 +205,7 @@ fn state_initial() {
         child_h1.state.pushed.1,
         child_h1.state.pushed.1,
         Some(Box::new(PushedDownStateTester(
         Some(Box::new(PushedDownStateTester(
             Some("div".to_string()),
             Some("div".to_string()),
-            None
+            Some(Box::new(PushedDownStateTester(None, None)))
         )))
         )))
     );
     );
     assert_eq!(child_h1.state.node.0, Some("h1".to_string()));
     assert_eq!(child_h1.state.node.0, Some("h1".to_string()));
@@ -256,10 +260,6 @@ fn state_reduce_initally_called_minimally() {
     let nodes_updated = dom.apply_mutations(vec![mutations]);
     let nodes_updated = dom.apply_mutations(vec![mutations]);
     let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new());
     let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new());
 
 
-    dom.traverse_depth_first(|n| {
-        println!("{:#?}", n.state);
-    });
-
     dom.traverse_depth_first(|n| {
     dom.traverse_depth_first(|n| {
         assert_eq!(n.state.child_counter.0, 1);
         assert_eq!(n.state.child_counter.0, 1);
         assert_eq!(n.state.parent_counter.0, 1);
         assert_eq!(n.state.parent_counter.0, 1);
@@ -268,7 +268,7 @@ fn state_reduce_initally_called_minimally() {
 }
 }
 
 
 #[test]
 #[test]
-fn state_reduce_down_called_minimally_on_update() {
+fn state_reduce_parent_called_minimally_on_update() {
     #[allow(non_snake_case)]
     #[allow(non_snake_case)]
     fn Base(cx: Scope) -> Element {
     fn Base(cx: Scope) -> Element {
         rsx!(cx, div {
         rsx!(cx, div {
@@ -329,21 +329,20 @@ fn state_reduce_down_called_minimally_on_update() {
     let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new());
     let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new());
 
 
     dom.traverse_depth_first(|n| {
     dom.traverse_depth_first(|n| {
-        // println!("{:?}", n.state);
         assert_eq!(n.state.parent_counter.0, 2);
         assert_eq!(n.state.parent_counter.0, 2);
     });
     });
-    // panic!()
 }
 }
 
 
 #[test]
 #[test]
-fn state_reduce_up_called_minimally_on_update() {
+fn state_reduce_child_called_minimally_on_update() {
     #[allow(non_snake_case)]
     #[allow(non_snake_case)]
     fn Base(cx: Scope) -> Element {
     fn Base(cx: Scope) -> Element {
         rsx!(cx, div {
         rsx!(cx, div {
-            width: "100%",
             div{
             div{
                 div{
                 div{
-                    p{}
+                    p{
+                        width: "100%",
+                    }
                 }
                 }
                 p{
                 p{
                     "hello"
                     "hello"
@@ -362,10 +361,11 @@ fn state_reduce_up_called_minimally_on_update() {
 
 
     let mutations = vdom.create_vnodes(rsx! {
     let mutations = vdom.create_vnodes(rsx! {
         div {
         div {
-            width: "100%",
             div{
             div{
                 div{
                 div{
-                    p{}
+                    p{
+                        width: "100%",
+                    }
                 }
                 }
                 p{
                 p{
                     "hello"
                     "hello"
@@ -397,6 +397,93 @@ fn state_reduce_up_called_minimally_on_update() {
     let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new());
     let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new());
 
 
     dom.traverse_depth_first(|n| {
     dom.traverse_depth_first(|n| {
+        println!("{:?}", n);
         assert_eq!(n.state.child_counter.0, if n.id.0 > 4 { 1 } else { 2 });
         assert_eq!(n.state.child_counter.0, if n.id.0 > 4 { 1 } else { 2 });
     });
     });
 }
 }
+
+#[derive(Debug, Clone, Default, State)]
+struct UnorderedDependanciesState {
+    #[node_dep_state(c)]
+    b: BDepCallCounter,
+    #[node_dep_state()]
+    c: CDepCallCounter,
+    #[node_dep_state(b)]
+    a: ADepCallCounter,
+}
+
+#[derive(Debug, Clone, Default, PartialEq)]
+struct ADepCallCounter(usize, BDepCallCounter);
+impl NodeDepState for ADepCallCounter {
+    type Ctx = ();
+    type DepState = BDepCallCounter;
+    const NODE_MASK: NodeMask = NodeMask::NONE;
+    fn reduce(&mut self, _node: NodeView, sibling: &Self::DepState, _ctx: &Self::Ctx) -> bool {
+        self.0 += 1;
+        self.1 = sibling.clone();
+        true
+    }
+}
+
+#[derive(Debug, Clone, Default, PartialEq)]
+struct BDepCallCounter(usize, CDepCallCounter);
+impl NodeDepState for BDepCallCounter {
+    type Ctx = ();
+    type DepState = CDepCallCounter;
+    const NODE_MASK: NodeMask = NodeMask::NONE;
+    fn reduce(&mut self, _node: NodeView, sibling: &Self::DepState, _ctx: &Self::Ctx) -> bool {
+        self.0 += 1;
+        self.1 = sibling.clone();
+        true
+    }
+}
+
+#[derive(Debug, Clone, Default, PartialEq)]
+struct CDepCallCounter(usize);
+impl NodeDepState for CDepCallCounter {
+    type Ctx = ();
+    type DepState = ();
+    const NODE_MASK: NodeMask = NodeMask::ALL;
+    fn reduce(&mut self, _node: NodeView, _sibling: &Self::DepState, _ctx: &Self::Ctx) -> bool {
+        self.0 += 1;
+        true
+    }
+}
+
+#[test]
+fn dependancies_order_independant() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        rsx!(cx, div {
+            width: "100%",
+            p{
+                "hello"
+            }
+        })
+    }
+
+    let vdom = VirtualDom::new(Base);
+
+    let mutations = vdom.create_vnodes(rsx! {
+        div {
+            width: "100%",
+            p{
+                "hello"
+            }
+        }
+    });
+
+    let mut dom: RealDom<UnorderedDependanciesState> = RealDom::new();
+
+    let nodes_updated = dom.apply_mutations(vec![mutations]);
+    let _to_rerender = dom.update_state(&vdom, nodes_updated, AnyMap::new());
+
+    let c = CDepCallCounter(1);
+    let b = BDepCallCounter(1, c.clone());
+    let a = ADepCallCounter(1, b.clone());
+    dom.traverse_depth_first(|n| {
+        assert_eq!(&n.state.a, &a);
+        assert_eq!(&n.state.b, &b);
+        assert_eq!(&n.state.c, &c);
+    });
+}

+ 0 - 1
packages/native-core/Cargo.toml

@@ -10,7 +10,6 @@ homepage = "https://dioxuslabs.com"
 dioxus-core = { path = "../core", version = "^0.2.0" }
 dioxus-core = { path = "../core", version = "^0.2.0" }
 dioxus-html = { path = "../html", version = "^0.2.0" }
 dioxus-html = { path = "../html", version = "^0.2.0" }
 dioxus-core-macro = { path = "../core-macro", version = "^0.2.0" }
 dioxus-core-macro = { path = "../core-macro", version = "^0.2.0" }
-dioxus-native-core-macro = { path = "../native-core-macro", version = "^0.2.0" }
 
 
 stretch2 = { git = "https://github.com/DioxusLabs/stretch" }
 stretch2 = { git = "https://github.com/DioxusLabs/stretch" }
 smallvec = "1.6"
 smallvec = "1.6"

+ 1 - 1
packages/native-core/src/lib.rs

@@ -1,4 +1,4 @@
 pub mod layout_attributes;
 pub mod layout_attributes;
+pub mod node_ref;
 pub mod real_dom;
 pub mod real_dom;
 pub mod state;
 pub mod state;
-pub use dioxus_native_core_macro;

+ 212 - 0
packages/native-core/src/node_ref.rs

@@ -0,0 +1,212 @@
+use dioxus_core::*;
+
+use crate::state::union_ordered_iter;
+
+#[derive(Debug)]
+pub struct NodeView<'a> {
+    inner: &'a VNode<'a>,
+    mask: NodeMask,
+}
+impl<'a> NodeView<'a> {
+    pub fn new(mut vnode: &'a VNode<'a>, view: NodeMask, vdom: &'a VirtualDom) -> Self {
+        if let VNode::Component(sc) = vnode {
+            let scope = vdom.get_scope(sc.scope.get().unwrap()).unwrap();
+            vnode = scope.root_node();
+        }
+        Self {
+            inner: vnode,
+            mask: view,
+        }
+    }
+
+    pub fn id(&self) -> ElementId {
+        self.inner.mounted_id()
+    }
+
+    pub fn tag(&self) -> Option<&'a str> {
+        self.mask.tag.then(|| self.el().map(|el| el.tag)).flatten()
+    }
+
+    pub fn namespace(&self) -> Option<&'a str> {
+        self.mask
+            .namespace
+            .then(|| self.el().map(|el| el.namespace).flatten())
+            .flatten()
+    }
+
+    pub fn attributes(&self) -> impl Iterator<Item = &Attribute<'a>> {
+        self.el()
+            .map(|el| el.attributes)
+            .unwrap_or_default()
+            .iter()
+            .filter(|a| self.mask.attritutes.contains_attribute(&a.name))
+    }
+
+    pub fn text(&self) -> Option<&str> {
+        self.mask
+            .text
+            .then(|| self.txt().map(|txt| txt.text))
+            .flatten()
+    }
+
+    fn el(&self) -> Option<&'a VElement<'a>> {
+        if let VNode::Element(el) = &self.inner {
+            Some(el)
+        } else {
+            None
+        }
+    }
+
+    fn txt(&self) -> Option<&'a VText<'a>> {
+        if let VNode::Text(txt) = &self.inner {
+            Some(txt)
+        } else {
+            None
+        }
+    }
+}
+
+#[derive(PartialEq, Clone, Debug)]
+pub enum AttributeMask {
+    All,
+    Dynamic(Vec<&'static str>),
+    Static(&'static [&'static str]),
+}
+
+impl AttributeMask {
+    pub const NONE: Self = Self::Static(&[]);
+
+    fn contains_attribute(&self, attr: &'static str) -> bool {
+        match self {
+            AttributeMask::All => true,
+            AttributeMask::Dynamic(l) => l.binary_search(&attr).is_ok(),
+            AttributeMask::Static(l) => l.binary_search(&attr).is_ok(),
+        }
+    }
+
+    pub fn single(new: &'static str) -> Self {
+        Self::Dynamic(vec![new])
+    }
+
+    pub fn verify(&self) {
+        match &self {
+            AttributeMask::Static(attrs) => debug_assert!(
+                attrs.windows(2).all(|w| w[0] < w[1]),
+                "attritutes must be increasing"
+            ),
+            AttributeMask::Dynamic(attrs) => debug_assert!(
+                attrs.windows(2).all(|w| w[0] < w[1]),
+                "attritutes must be increasing"
+            ),
+            _ => (),
+        }
+    }
+
+    pub fn union(&self, other: &Self) -> Self {
+        let new = match (self, other) {
+            (AttributeMask::Dynamic(s), AttributeMask::Dynamic(o)) => AttributeMask::Dynamic(
+                union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
+            ),
+            (AttributeMask::Static(s), AttributeMask::Dynamic(o)) => AttributeMask::Dynamic(
+                union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
+            ),
+            (AttributeMask::Dynamic(s), AttributeMask::Static(o)) => AttributeMask::Dynamic(
+                union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
+            ),
+            (AttributeMask::Static(s), AttributeMask::Static(o)) => AttributeMask::Dynamic(
+                union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
+            ),
+            _ => AttributeMask::All,
+        };
+        new.verify();
+        new
+    }
+
+    fn overlaps(&self, other: &Self) -> bool {
+        fn overlaps_iter(
+            mut self_iter: impl Iterator<Item = &'static str>,
+            mut other_iter: impl Iterator<Item = &'static str>,
+        ) -> bool {
+            if let Some(mut other_attr) = other_iter.next() {
+                while let Some(self_attr) = self_iter.next() {
+                    while other_attr < self_attr {
+                        if let Some(attr) = other_iter.next() {
+                            other_attr = attr;
+                        } else {
+                            return false;
+                        }
+                    }
+                    if other_attr == self_attr {
+                        return true;
+                    }
+                }
+            }
+            false
+        }
+        match (self, other) {
+            (AttributeMask::All, AttributeMask::All) => true,
+            (AttributeMask::All, AttributeMask::Dynamic(v)) => !v.is_empty(),
+            (AttributeMask::All, AttributeMask::Static(s)) => !s.is_empty(),
+            (AttributeMask::Dynamic(v), AttributeMask::All) => !v.is_empty(),
+            (AttributeMask::Static(s), AttributeMask::All) => !s.is_empty(),
+            (AttributeMask::Dynamic(v1), AttributeMask::Dynamic(v2)) => {
+                overlaps_iter(v1.iter().copied(), v2.iter().copied())
+            }
+            (AttributeMask::Dynamic(v), AttributeMask::Static(s)) => {
+                overlaps_iter(v.iter().copied(), s.iter().copied())
+            }
+            (AttributeMask::Static(s), AttributeMask::Dynamic(v)) => {
+                overlaps_iter(v.iter().copied(), s.iter().copied())
+            }
+            (AttributeMask::Static(s1), AttributeMask::Static(s2)) => {
+                overlaps_iter(s1.iter().copied(), s2.iter().copied())
+            }
+        }
+    }
+}
+
+impl Default for AttributeMask {
+    fn default() -> Self {
+        AttributeMask::Static(&[])
+    }
+}
+
+#[derive(Default, PartialEq, Clone, Debug)]
+pub struct NodeMask {
+    // must be sorted
+    attritutes: AttributeMask,
+    tag: bool,
+    namespace: bool,
+    text: bool,
+}
+
+impl NodeMask {
+    pub const NONE: Self = Self::new(AttributeMask::Static(&[]), false, false, false);
+    pub const ALL: Self = Self::new(AttributeMask::All, true, true, true);
+
+    /// attritutes must be sorted!
+    pub const fn new(attritutes: AttributeMask, tag: bool, namespace: bool, text: bool) -> Self {
+        Self {
+            attritutes,
+            tag,
+            namespace,
+            text,
+        }
+    }
+
+    pub fn overlaps(&self, other: &Self) -> bool {
+        (self.tag && other.tag)
+            || (self.namespace && other.namespace)
+            || self.attritutes.overlaps(&other.attritutes)
+            || (self.text && other.text)
+    }
+
+    pub fn union(&self, other: &Self) -> Self {
+        Self {
+            attritutes: self.attritutes.union(&other.attritutes),
+            tag: self.tag | other.tag,
+            namespace: self.namespace | other.namespace,
+            text: self.text | other.text,
+        }
+    }
+}

+ 57 - 16
packages/native-core/src/real_dom.rs

@@ -1,14 +1,17 @@
 use anymap::AnyMap;
 use anymap::AnyMap;
 use fxhash::{FxHashMap, FxHashSet};
 use fxhash::{FxHashMap, FxHashSet};
 use std::{
 use std::{
-    any::TypeId,
     collections::VecDeque,
     collections::VecDeque,
     ops::{Index, IndexMut},
     ops::{Index, IndexMut},
 };
 };
 
 
 use dioxus_core::{ElementId, Mutations, VNode, VirtualDom};
 use dioxus_core::{ElementId, Mutations, VNode, VirtualDom};
 
 
-use crate::state::{union_ordered_iter, AttributeMask, NodeMask, State};
+use crate::state::{union_ordered_iter, State};
+use crate::{
+    node_ref::{AttributeMask, NodeMask},
+    state::MemberId,
+};
 
 
 /// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
 /// A Dom that can sync with the VirtualDom mutations intended for use in lazy renderers.
 /// The render state passes from parent to children and or accumulates state from children to parents.
 /// The render state passes from parent to children and or accumulates state from children to parents.
@@ -211,7 +214,7 @@ impl<S: State> RealDom<S> {
         #[derive(PartialEq, Clone, Debug)]
         #[derive(PartialEq, Clone, Debug)]
         enum StatesToCheck {
         enum StatesToCheck {
             All,
             All,
-            Some(Vec<TypeId>),
+            Some(Vec<MemberId>),
         }
         }
         impl StatesToCheck {
         impl StatesToCheck {
             fn union(&self, other: &Self) -> Self {
             fn union(&self, other: &Self) -> Self {
@@ -294,14 +297,28 @@ impl<S: State> RealDom<S> {
         for node_ref in &nodes_updated {
         for node_ref in &nodes_updated {
             let mut changed = false;
             let mut changed = false;
             let node = &mut self[node_ref.id];
             let node = &mut self[node_ref.id];
-            let ids = match &node_ref.to_check {
+            let mut ids = match &node_ref.to_check {
                 StatesToCheck::All => node.state.node_dep_types(&node_ref.node_mask),
                 StatesToCheck::All => node.state.node_dep_types(&node_ref.node_mask),
+                // this should only be triggered from the current node, so all members will need to be checked
                 StatesToCheck::Some(_) => unreachable!(),
                 StatesToCheck::Some(_) => unreachable!(),
             };
             };
-            for ty in ids {
+            let mut i = 0;
+            while i < ids.len() {
+                let id = ids[i];
                 let node = &mut self[node_ref.id];
                 let node = &mut self[node_ref.id];
                 let vnode = node.element(vdom);
                 let vnode = node.element(vdom);
-                changed |= node.state.update_node_dep_state(ty, vnode, vdom, &ctx);
+                if let Some(members_effected) =
+                    node.state.update_node_dep_state(id, vnode, vdom, &ctx)
+                {
+                    debug_assert!(members_effected.node_dep.iter().all(|i| i >= &id));
+                    for m in members_effected.node_dep {
+                        if let Err(idx) = ids.binary_search(m) {
+                            ids.insert(idx, *m);
+                        }
+                    }
+                    changed = true;
+                }
+                i += 1;
             }
             }
             if changed {
             if changed {
                 to_rerender.insert(node_ref.id);
                 to_rerender.insert(node_ref.id);
@@ -319,19 +336,30 @@ impl<S: State> RealDom<S> {
             } = node_ref;
             } = node_ref;
             let (node, children) = self.get_node_children_mut(id).unwrap();
             let (node, children) = self.get_node_children_mut(id).unwrap();
             let children_state: Vec<_> = children.iter().map(|c| &c.state).collect();
             let children_state: Vec<_> = children.iter().map(|c| &c.state).collect();
-            let ids = match to_check {
+            let mut ids = match to_check {
                 StatesToCheck::All => node.state.child_dep_types(&node_mask),
                 StatesToCheck::All => node.state.child_dep_types(&node_mask),
                 StatesToCheck::Some(ids) => ids,
                 StatesToCheck::Some(ids) => ids,
             };
             };
             let mut changed = Vec::new();
             let mut changed = Vec::new();
-            for ty in ids {
+            let mut i = 0;
+            while i < ids.len() {
+                let id = ids[i];
                 let vnode = node.element(vdom);
                 let vnode = node.element(vdom);
-                if node
-                    .state
-                    .update_child_dep_state(ty, vnode, vdom, &children_state, &ctx)
+                if let Some(members_effected) =
+                    node.state
+                        .update_child_dep_state(id, vnode, vdom, &children_state, &ctx)
                 {
                 {
-                    changed.push(ty);
+                    debug_assert!(members_effected.node_dep.iter().all(|i| i >= &id));
+                    for m in members_effected.node_dep {
+                        if let Err(idx) = ids.binary_search(m) {
+                            ids.insert(idx, *m);
+                        }
+                    }
+                    for m in members_effected.child_dep {
+                        changed.push(*m);
+                    }
                 }
                 }
+                i += 1;
             }
             }
             if let Some(parent_id) = node.parent {
             if let Some(parent_id) = node.parent {
                 if !changed.is_empty() {
                 if !changed.is_empty() {
@@ -374,19 +402,32 @@ impl<S: State> RealDom<S> {
                 to_check,
                 to_check,
             } = node_ref;
             } = node_ref;
             let node = &self[id];
             let node = &self[id];
-            let ids = match to_check {
+            let mut ids = match to_check {
                 StatesToCheck::All => node.state.parent_dep_types(&node_mask),
                 StatesToCheck::All => node.state.parent_dep_types(&node_mask),
                 StatesToCheck::Some(ids) => ids,
                 StatesToCheck::Some(ids) => ids,
             };
             };
             let mut changed = Vec::new();
             let mut changed = Vec::new();
             let (node, parent) = self.get_node_parent_mut(id).unwrap();
             let (node, parent) = self.get_node_parent_mut(id).unwrap();
-            for ty in ids {
+            let mut i = 0;
+            while i < ids.len() {
+                let id = ids[i];
                 let vnode = node.element(vdom);
                 let vnode = node.element(vdom);
                 let parent = parent.as_deref();
                 let parent = parent.as_deref();
                 let state = &mut node.state;
                 let state = &mut node.state;
-                if state.update_parent_dep_state(ty, vnode, vdom, parent.map(|n| &n.state), &ctx) {
-                    changed.push(ty);
+                if let Some(members_effected) =
+                    state.update_parent_dep_state(id, vnode, vdom, parent.map(|n| &n.state), &ctx)
+                {
+                    debug_assert!(members_effected.node_dep.iter().all(|i| i >= &id));
+                    for m in members_effected.node_dep {
+                        if let Err(idx) = ids.binary_search(m) {
+                            ids.insert(idx, *m);
+                        }
+                    }
+                    for m in members_effected.parent_dep {
+                        changed.push(*m);
+                    }
                 }
                 }
+                i += 1;
             }
             }
 
 
             to_rerender.insert(id);
             to_rerender.insert(id);

+ 71 - 223
packages/native-core/src/state.rs

@@ -1,7 +1,9 @@
-use std::{any::TypeId, fmt::Debug};
+use std::fmt::Debug;
 
 
 use anymap::AnyMap;
 use anymap::AnyMap;
-use dioxus_core::{Attribute, ElementId, VElement, VNode, VText, VirtualDom};
+use dioxus_core::VNode;
+
+use crate::node_ref::{NodeMask, NodeView};
 
 
 pub(crate) fn union_ordered_iter<T: Ord + Debug>(
 pub(crate) fn union_ordered_iter<T: Ord + Debug>(
     s_iter: impl Iterator<Item = T>,
     s_iter: impl Iterator<Item = T>,
@@ -34,215 +36,6 @@ pub(crate) fn union_ordered_iter<T: Ord + Debug>(
     v
     v
 }
 }
 
 
-#[derive(Debug)]
-pub struct NodeView<'a> {
-    inner: &'a VNode<'a>,
-    mask: NodeMask,
-}
-impl<'a> NodeView<'a> {
-    pub fn new(mut vnode: &'a VNode<'a>, view: NodeMask, vdom: &'a VirtualDom) -> Self {
-        if let VNode::Component(sc) = vnode {
-            let scope = vdom.get_scope(sc.scope.get().unwrap()).unwrap();
-            vnode = scope.root_node();
-        }
-        Self {
-            inner: vnode,
-            mask: view,
-        }
-    }
-
-    pub fn id(&self) -> ElementId {
-        self.inner.mounted_id()
-    }
-
-    pub fn tag(&self) -> Option<&'a str> {
-        self.mask.tag.then(|| self.el().map(|el| el.tag)).flatten()
-    }
-
-    pub fn namespace(&self) -> Option<&'a str> {
-        self.mask
-            .namespace
-            .then(|| self.el().map(|el| el.namespace).flatten())
-            .flatten()
-    }
-
-    pub fn attributes(&self) -> impl Iterator<Item = &Attribute<'a>> {
-        self.el()
-            .map(|el| el.attributes)
-            .unwrap_or_default()
-            .iter()
-            .filter(|a| self.mask.attritutes.contains_attribute(&a.name))
-    }
-
-    pub fn text(&self) -> Option<&str> {
-        self.mask
-            .text
-            .then(|| self.txt().map(|txt| txt.text))
-            .flatten()
-    }
-
-    fn el(&self) -> Option<&'a VElement<'a>> {
-        if let VNode::Element(el) = &self.inner {
-            Some(el)
-        } else {
-            None
-        }
-    }
-
-    fn txt(&self) -> Option<&'a VText<'a>> {
-        if let VNode::Text(txt) = &self.inner {
-            Some(txt)
-        } else {
-            None
-        }
-    }
-}
-
-#[derive(PartialEq, Clone, Debug)]
-pub enum AttributeMask {
-    All,
-    Dynamic(Vec<&'static str>),
-    Static(&'static [&'static str]),
-}
-
-impl AttributeMask {
-    pub const NONE: Self = Self::Static(&[]);
-
-    fn contains_attribute(&self, attr: &'static str) -> bool {
-        match self {
-            AttributeMask::All => true,
-            AttributeMask::Dynamic(l) => l.binary_search(&attr).is_ok(),
-            AttributeMask::Static(l) => l.binary_search(&attr).is_ok(),
-        }
-    }
-
-    pub fn single(new: &'static str) -> Self {
-        Self::Dynamic(vec![new])
-    }
-
-    pub fn verify(&self) {
-        match &self {
-            AttributeMask::Static(attrs) => debug_assert!(
-                attrs.windows(2).all(|w| w[0] < w[1]),
-                "attritutes must be increasing"
-            ),
-            AttributeMask::Dynamic(attrs) => debug_assert!(
-                attrs.windows(2).all(|w| w[0] < w[1]),
-                "attritutes must be increasing"
-            ),
-            _ => (),
-        }
-    }
-
-    pub fn union(&self, other: &Self) -> Self {
-        let new = match (self, other) {
-            (AttributeMask::Dynamic(s), AttributeMask::Dynamic(o)) => AttributeMask::Dynamic(
-                union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
-            ),
-            (AttributeMask::Static(s), AttributeMask::Dynamic(o)) => AttributeMask::Dynamic(
-                union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
-            ),
-            (AttributeMask::Dynamic(s), AttributeMask::Static(o)) => AttributeMask::Dynamic(
-                union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
-            ),
-            (AttributeMask::Static(s), AttributeMask::Static(o)) => AttributeMask::Dynamic(
-                union_ordered_iter(s.iter().copied(), o.iter().copied(), s.len() + o.len()),
-            ),
-            _ => AttributeMask::All,
-        };
-        new.verify();
-        new
-    }
-
-    fn overlaps(&self, other: &Self) -> bool {
-        fn overlaps_iter(
-            mut self_iter: impl Iterator<Item = &'static str>,
-            mut other_iter: impl Iterator<Item = &'static str>,
-        ) -> bool {
-            if let Some(mut other_attr) = other_iter.next() {
-                while let Some(self_attr) = self_iter.next() {
-                    while other_attr < self_attr {
-                        if let Some(attr) = other_iter.next() {
-                            other_attr = attr;
-                        } else {
-                            return false;
-                        }
-                    }
-                    if other_attr == self_attr {
-                        return true;
-                    }
-                }
-            }
-            false
-        }
-        match (self, other) {
-            (AttributeMask::All, AttributeMask::All) => true,
-            (AttributeMask::All, AttributeMask::Dynamic(v)) => !v.is_empty(),
-            (AttributeMask::All, AttributeMask::Static(s)) => !s.is_empty(),
-            (AttributeMask::Dynamic(v), AttributeMask::All) => !v.is_empty(),
-            (AttributeMask::Static(s), AttributeMask::All) => !s.is_empty(),
-            (AttributeMask::Dynamic(v1), AttributeMask::Dynamic(v2)) => {
-                overlaps_iter(v1.iter().copied(), v2.iter().copied())
-            }
-            (AttributeMask::Dynamic(v), AttributeMask::Static(s)) => {
-                overlaps_iter(v.iter().copied(), s.iter().copied())
-            }
-            (AttributeMask::Static(s), AttributeMask::Dynamic(v)) => {
-                overlaps_iter(v.iter().copied(), s.iter().copied())
-            }
-            (AttributeMask::Static(s1), AttributeMask::Static(s2)) => {
-                overlaps_iter(s1.iter().copied(), s2.iter().copied())
-            }
-        }
-    }
-}
-
-impl Default for AttributeMask {
-    fn default() -> Self {
-        AttributeMask::Static(&[])
-    }
-}
-
-#[derive(Default, PartialEq, Clone, Debug)]
-pub struct NodeMask {
-    // must be sorted
-    attritutes: AttributeMask,
-    tag: bool,
-    namespace: bool,
-    text: bool,
-}
-
-impl NodeMask {
-    pub const NONE: Self = Self::new(AttributeMask::Static(&[]), false, false, false);
-    pub const ALL: Self = Self::new(AttributeMask::All, true, true, true);
-
-    /// attritutes must be sorted!
-    pub const fn new(attritutes: AttributeMask, tag: bool, namespace: bool, text: bool) -> Self {
-        Self {
-            attritutes,
-            tag,
-            namespace,
-            text,
-        }
-    }
-
-    pub fn overlaps(&self, other: &Self) -> bool {
-        (self.tag && other.tag)
-            || (self.namespace && other.namespace)
-            || self.attritutes.overlaps(&other.attritutes)
-            || (self.text && other.text)
-    }
-
-    pub fn union(&self, other: &Self) -> Self {
-        Self {
-            attritutes: self.attritutes.union(&other.attritutes),
-            tag: self.tag | other.tag,
-            namespace: self.namespace | other.namespace,
-            text: self.text | other.text,
-        }
-    }
-}
-
 /// This state is derived from children. For example a node's size could be derived from the size of children.
 /// This state is derived from children. For example a node's size could be derived from the size of children.
 /// Called when the current node's node properties are modified, a child's [BubbledUpState] is modified or a child is removed.
 /// Called when the current node's node properties are modified, a child's [BubbledUpState] is modified or a child is removed.
 /// Called at most once per update.
 /// Called at most once per update.
@@ -250,7 +43,8 @@ pub trait ChildDepState {
     /// The context is passed to the [PushedDownState::reduce] when it is pushed down.
     /// The context is passed to the [PushedDownState::reduce] when it is pushed down.
     /// This is sometimes nessisary for lifetime purposes.
     /// This is sometimes nessisary for lifetime purposes.
     type Ctx;
     type Ctx;
-    type DepState: ChildDepState;
+    /// This must be either a [ChildDepState] or [NodeDepState]
+    type DepState;
     const NODE_MASK: NodeMask = NodeMask::NONE;
     const NODE_MASK: NodeMask = NodeMask::NONE;
     fn reduce<'a>(
     fn reduce<'a>(
         &mut self,
         &mut self,
@@ -269,7 +63,8 @@ pub trait ParentDepState {
     /// The context is passed to the [PushedDownState::reduce] when it is pushed down.
     /// The context is passed to the [PushedDownState::reduce] when it is pushed down.
     /// This is sometimes nessisary for lifetime purposes.
     /// This is sometimes nessisary for lifetime purposes.
     type Ctx;
     type Ctx;
-    type DepState: ParentDepState;
+    /// This must be either a [ParentDepState] or [NodeDepState]
+    type DepState;
     const NODE_MASK: NodeMask = NodeMask::NONE;
     const NODE_MASK: NodeMask = NodeMask::NONE;
     fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, ctx: &Self::Ctx) -> bool;
     fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, ctx: &Self::Ctx) -> bool;
 }
 }
@@ -279,40 +74,93 @@ pub trait ParentDepState {
 /// Called at most once per update.
 /// Called at most once per update.
 pub trait NodeDepState {
 pub trait NodeDepState {
     type Ctx;
     type Ctx;
+    type DepState: NodeDepState;
     const NODE_MASK: NodeMask = NodeMask::NONE;
     const NODE_MASK: NodeMask = NodeMask::NONE;
-    fn reduce(&mut self, node: NodeView, ctx: &Self::Ctx) -> bool;
+    fn reduce(&mut self, node: NodeView, sibling: &Self::DepState, ctx: &Self::Ctx) -> bool;
+}
+
+#[derive(Debug)]
+pub struct ChildStatesChanged {
+    pub node_dep: &'static [MemberId],
+    pub child_dep: &'static [MemberId],
+}
+
+#[derive(Debug)]
+pub struct ParentStatesChanged {
+    pub node_dep: &'static [MemberId],
+    pub parent_dep: &'static [MemberId],
+}
+
+#[derive(Debug)]
+pub struct NodeStatesChanged {
+    pub node_dep: &'static [MemberId],
 }
 }
 
 
 pub trait State: Default + Clone {
 pub trait State: Default + Clone {
     fn update_node_dep_state<'a>(
     fn update_node_dep_state<'a>(
         &'a mut self,
         &'a mut self,
-        ty: TypeId,
+        ty: MemberId,
         node: &'a VNode<'a>,
         node: &'a VNode<'a>,
         vdom: &'a dioxus_core::VirtualDom,
         vdom: &'a dioxus_core::VirtualDom,
         ctx: &AnyMap,
         ctx: &AnyMap,
-    ) -> bool;
+    ) -> Option<NodeStatesChanged>;
     /// This must be a valid resolution order. (no nodes updated before a state they rely on)
     /// This must be a valid resolution order. (no nodes updated before a state they rely on)
-    fn child_dep_types(&self, mask: &NodeMask) -> Vec<TypeId>;
+    fn child_dep_types(&self, mask: &NodeMask) -> Vec<MemberId>;
 
 
     fn update_parent_dep_state<'a>(
     fn update_parent_dep_state<'a>(
         &'a mut self,
         &'a mut self,
-        ty: TypeId,
+        ty: MemberId,
         node: &'a VNode<'a>,
         node: &'a VNode<'a>,
         vdom: &'a dioxus_core::VirtualDom,
         vdom: &'a dioxus_core::VirtualDom,
         parent: Option<&Self>,
         parent: Option<&Self>,
         ctx: &AnyMap,
         ctx: &AnyMap,
-    ) -> bool;
+    ) -> Option<ParentStatesChanged>;
     /// This must be a valid resolution order. (no nodes updated before a state they rely on)
     /// This must be a valid resolution order. (no nodes updated before a state they rely on)
-    fn parent_dep_types(&self, mask: &NodeMask) -> Vec<TypeId>;
+    fn parent_dep_types(&self, mask: &NodeMask) -> Vec<MemberId>;
 
 
     fn update_child_dep_state<'a>(
     fn update_child_dep_state<'a>(
         &'a mut self,
         &'a mut self,
-        ty: TypeId,
+        ty: MemberId,
         node: &'a VNode<'a>,
         node: &'a VNode<'a>,
         vdom: &'a dioxus_core::VirtualDom,
         vdom: &'a dioxus_core::VirtualDom,
         children: &[&Self],
         children: &[&Self],
         ctx: &AnyMap,
         ctx: &AnyMap,
-    ) -> bool;
+    ) -> Option<ChildStatesChanged>;
     /// This must be a valid resolution order. (no nodes updated before a state they rely on)
     /// This must be a valid resolution order. (no nodes updated before a state they rely on)
-    fn node_dep_types(&self, mask: &NodeMask) -> Vec<TypeId>;
+    fn node_dep_types(&self, mask: &NodeMask) -> Vec<MemberId>;
 }
 }
+
+impl ChildDepState for () {
+    type Ctx = ();
+    type DepState = ();
+    fn reduce<'a>(
+        &mut self,
+        _: NodeView,
+        _: impl Iterator<Item = &'a Self::DepState>,
+        _: &Self::Ctx,
+    ) -> bool
+    where
+        Self::DepState: 'a,
+    {
+        false
+    }
+}
+
+impl ParentDepState for () {
+    type Ctx = ();
+    type DepState = ();
+    fn reduce(&mut self, _: NodeView, _: Option<&Self::DepState>, _: &Self::Ctx) -> bool {
+        false
+    }
+}
+
+impl NodeDepState for () {
+    type Ctx = ();
+    type DepState = ();
+    fn reduce(&mut self, _: NodeView, _sibling: &Self::DepState, _: &Self::Ctx) -> bool {
+        false
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct MemberId(pub usize);

+ 0 - 59
packages/native-core/tests/parse.rs

@@ -1,59 +0,0 @@
-use dioxus_native_core::state::*;
-use dioxus_native_core_macro::*;
-
-#[derive(State, Default, Clone)]
-struct Z {
-    // depends on just attributes and no context
-    #[node_dep_state()]
-    x: A,
-    // depends on attributes, the B component of children and i32 context
-    #[child_dep_state(B, i32)]
-    y: B,
-    // depends on attributes, the C component of it's parent and a u8 context
-    #[parent_dep_state(C, u8)]
-    z: C,
-}
-
-use dioxus_native_core::state::NodeDepState;
-
-#[derive(Default, Clone)]
-struct A;
-impl NodeDepState for A {
-    type Ctx = ();
-    fn reduce(&mut self, _: NodeView, _: &()) -> bool {
-        todo!()
-    }
-}
-
-#[derive(Default, Clone)]
-struct B;
-impl ChildDepState for B {
-    type Ctx = i32;
-    type DepState = Self;
-    fn reduce<'a>(
-        &mut self,
-        _: dioxus_native_core::state::NodeView,
-        _: impl Iterator<Item = &'a Self::DepState>,
-        _: &i32,
-    ) -> bool
-    where
-        Self::DepState: 'a,
-    {
-        todo!()
-    }
-}
-
-#[derive(Default, Clone)]
-struct C;
-impl ParentDepState for C {
-    type Ctx = u8;
-    type DepState = Self;
-    fn reduce(
-        &mut self,
-        _: dioxus_native_core::state::NodeView,
-        _: Option<&Self::DepState>,
-        _: &u8,
-    ) -> bool {
-        todo!()
-    }
-}

+ 1 - 0
packages/tui/Cargo.toml

@@ -16,6 +16,7 @@ license = "MIT/Apache-2.0"
 dioxus-core = { path = "../core", version = "^0.2.0" }
 dioxus-core = { path = "../core", version = "^0.2.0" }
 dioxus-html = { path = "../html", version = "^0.2.0" }
 dioxus-html = { path = "../html", version = "^0.2.0" }
 dioxus-native-core = { path = "../native-core", version = "^0.2.0" }
 dioxus-native-core = { path = "../native-core", version = "^0.2.0" }
+dioxus-native-core-macro = { path = "../native-core-macro", version = "^0.2.0" }
 
 
 tui = "0.17.0"
 tui = "0.17.0"
 crossterm = "0.23.0"
 crossterm = "0.23.0"

+ 3 - 2
packages/tui/src/layout.rs

@@ -2,9 +2,10 @@ use std::cell::RefCell;
 use std::rc::Rc;
 use std::rc::Rc;
 
 
 use dioxus_core::*;
 use dioxus_core::*;
-use dioxus_native_core::dioxus_native_core_macro::sorted_str_slice;
 use dioxus_native_core::layout_attributes::apply_layout_attributes;
 use dioxus_native_core::layout_attributes::apply_layout_attributes;
-use dioxus_native_core::state::{AttributeMask, ChildDepState, NodeMask, NodeView};
+use dioxus_native_core::node_ref::{AttributeMask, NodeMask, NodeView};
+use dioxus_native_core::state::ChildDepState;
+use dioxus_native_core_macro::sorted_str_slice;
 use stretch2::prelude::*;
 use stretch2::prelude::*;
 
 
 #[derive(Debug, Clone, Copy, PartialEq)]
 #[derive(Debug, Clone, Copy, PartialEq)]

+ 4 - 3
packages/tui/src/lib.rs

@@ -7,7 +7,8 @@ use crossterm::{
 };
 };
 use dioxus_core::exports::futures_channel::mpsc::unbounded;
 use dioxus_core::exports::futures_channel::mpsc::unbounded;
 use dioxus_core::*;
 use dioxus_core::*;
-use dioxus_native_core::{dioxus_native_core_macro::State, real_dom::RealDom, state::*};
+use dioxus_native_core::{real_dom::RealDom, state::*};
+use dioxus_native_core_macro::State;
 use futures::{
 use futures::{
     channel::mpsc::{UnboundedReceiver, UnboundedSender},
     channel::mpsc::{UnboundedReceiver, UnboundedSender},
     pin_mut, StreamExt,
     pin_mut, StreamExt,
@@ -36,10 +37,10 @@ type Node = dioxus_native_core::real_dom::Node<NodeState>;
 
 
 #[derive(Debug, Clone, State, Default)]
 #[derive(Debug, Clone, State, Default)]
 struct NodeState {
 struct NodeState {
-    #[child_dep_state(StretchLayout, RefCell<Stretch>)]
+    #[child_dep_state(layout, RefCell<Stretch>)]
     layout: StretchLayout,
     layout: StretchLayout,
     // depends on attributes, the C component of it's parent and a u8 context
     // depends on attributes, the C component of it's parent and a u8 context
-    #[parent_dep_state(StyleModifier)]
+    #[parent_dep_state(style)]
     style: StyleModifier,
     style: StyleModifier,
 }
 }
 
 

+ 213 - 2
packages/tui/src/style_attributes.rs

@@ -32,8 +32,10 @@
 use dioxus_core::Attribute;
 use dioxus_core::Attribute;
 use dioxus_native_core::{
 use dioxus_native_core::{
     layout_attributes::{parse_value, UnitSystem},
     layout_attributes::{parse_value, UnitSystem},
-    state::{AttributeMask, NodeMask, NodeView, ParentDepState},
+    node_ref::{AttributeMask, NodeMask, NodeView},
+    state::ParentDepState,
 };
 };
+use dioxus_native_core_macro::sorted_str_slice;
 
 
 use crate::style::{RinkColor, RinkStyle};
 use crate::style::{RinkColor, RinkStyle};
 
 
@@ -47,7 +49,8 @@ impl ParentDepState for StyleModifier {
     type Ctx = ();
     type Ctx = ();
     type DepState = Self;
     type DepState = Self;
     // todo: seperate each attribute into it's own class
     // todo: seperate each attribute into it's own class
-    const NODE_MASK: NodeMask = NodeMask::new(AttributeMask::All, true, true, false);
+    const NODE_MASK: NodeMask =
+        NodeMask::new(AttributeMask::Static(SORTED_STYLE_ATTRS), true, true, false);
 
 
     fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, _: &Self::Ctx) -> bool {
     fn reduce(&mut self, node: NodeView, parent: Option<&Self::DepState>, _: &Self::Ctx) -> bool {
         let mut new = StyleModifier::default();
         let mut new = StyleModifier::default();
@@ -586,3 +589,211 @@ fn apply_text(name: &str, value: &str, style: &mut StyleModifier) {
 fn apply_transition(_name: &str, _value: &str, _style: &mut StyleModifier) {
 fn apply_transition(_name: &str, _value: &str, _style: &mut StyleModifier) {
     todo!()
     todo!()
 }
 }
+
+const SORTED_STYLE_ATTRS: &'static [&'static str] = &sorted_str_slice!([
+    "animation",
+    "animation-delay",
+    "animation-direction",
+    "animation-duration",
+    "animation-fill-mode",
+    "animation-iteration-count",
+    "animation-name",
+    "animation-play-state",
+    "animation-timing-function",
+    "backface-visibility",
+    "background",
+    "background-attachment",
+    "background-clip",
+    "background-color",
+    "background-image",
+    "background-origin",
+    "background-position",
+    "background-repeat",
+    "background-size",
+    "border",
+    "border-bottom",
+    "border-bottom-color",
+    "border-bottom-left-radius",
+    "border-bottom-right-radius",
+    "border-bottom-style",
+    "border-bottom-width",
+    "border-collapse",
+    "border-color",
+    "border-image",
+    "border-image-outset",
+    "border-image-repeat",
+    "border-image-slice",
+    "border-image-source",
+    "border-image-width",
+    "border-left",
+    "border-left-color",
+    "border-left-style",
+    "border-left-width",
+    "border-radius",
+    "border-right",
+    "border-right-color",
+    "border-right-style",
+    "border-right-width",
+    "border-spacing",
+    "border-style",
+    "border-top",
+    "border-top-color",
+    "border-top-left-radius",
+    "border-top-right-radius",
+    "border-top-style",
+    "border-top-width",
+    "border-width",
+    "bottom",
+    "box-shadow",
+    "box-sizing",
+    "caption-side",
+    "clear",
+    "clip",
+    "color",
+    "columns",
+    "content",
+    "counter-increment",
+    "counter-reset",
+    "cursor",
+    "empty-cells",
+    "float",
+    "font",
+    "font-family",
+    "font-size",
+    "font-size-adjust",
+    "font-stretch",
+    "font-style",
+    "font-variant",
+    "font-weight",
+    "letter-spacing",
+    "line-height",
+    "list-style",
+    "list-style-image",
+    "list-style-position",
+    "list-style-type",
+    "opacity",
+    "order",
+    "outline",
+    "outline-color",
+    "outline-offset",
+    "outline-style",
+    "outline-width",
+    "page-break-after",
+    "page-break-before",
+    "page-break-inside",
+    "perspective",
+    "perspective-origin",
+    "pointer-events",
+    "quotes",
+    "resize",
+    "tab-size",
+    "table-layout",
+    "text-align",
+    "text-align-last",
+    "text-decoration",
+    "text-decoration-color",
+    "text-decoration-line",
+    "text-decoration-style",
+    "text-indent",
+    "text-justify",
+    "text-overflow",
+    "text-shadow",
+    "text-transform",
+    "transition",
+    "transition-delay",
+    "transition-duration",
+    "transition-property",
+    "transition-timing-function",
+    "visibility",
+    "white-space",
+    "background-color",
+    "background",
+    "background-attachment",
+    "background-clip",
+    "background-image",
+    "background-origin",
+    "background-position",
+    "background-repeat",
+    "background-size",
+    "dotted",
+    "dashed",
+    "solid",
+    "double",
+    "groove",
+    "ridge",
+    "inset",
+    "outset",
+    "none",
+    "hidden",
+    "border",
+    "border-bottom",
+    "border-bottom-color",
+    "border-bottom-left-radius",
+    "border-bottom-right-radius",
+    "border-bottom-style",
+    "border-bottom-width",
+    "border-collapse",
+    "border-color",
+    "            ",
+    "        ",
+    "border-image",
+    "border-image-outset",
+    "border-image-repeat",
+    "border-image-slice",
+    "border-image-source",
+    "border-image-width",
+    "border-left",
+    "border-left-color",
+    "border-left-style",
+    "border-left-width",
+    "border-radius",
+    "        ",
+    "border-right",
+    "border-right-color",
+    "border-right-style",
+    "border-right-width",
+    "border-spacing",
+    "border-style",
+    "border-top",
+    "border-top-color",
+    "border-top-left-radius",
+    "border-top-right-radius",
+    "border-top-style",
+    "border-top-width",
+    "border-width",
+    "           ",
+    "animation",
+    "animation-delay",
+    "animation-direction",
+    "animation-duration",
+    "animation-fill-mode",
+    "animation-itera ",
+    "animation-name",
+    "animation-play-state",
+    "animation-timing-function",
+    "font",
+    "font-family",
+    "font-size",
+    "font-size-adjust",
+    "font-stretch",
+    "font-style",
+    "italic",
+    "oblique",
+    "font-variant",
+    "font-weight",
+    "bold",
+    "normal",
+    "text-align",
+    "text-align-last",
+    "text-decoration",
+    "text-decoration-line",
+    "line-through",
+    "underline",
+    "text-decoration-color",
+    "text-decoration-style",
+    "text-indent",
+    "text-justify",
+    "text-overflow",
+    "text-shadow",
+    "text-transform"
+]);