Procházet zdrojové kódy

remove native-core-macro

Evan Almloff před 2 roky
rodič
revize
4738352955

+ 0 - 1
Cargo.toml

@@ -17,7 +17,6 @@ members = [
     "packages/rsx",
     "packages/tui",
     "packages/native-core",
-    "packages/native-core-macro",
     "packages/rsx-rosetta",
     "packages/signals",
     "docs/guide",

+ 0 - 2
packages/native-core-macro/.gitignore

@@ -1,2 +0,0 @@
-/target
-Cargo.lock

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

@@ -1,26 +0,0 @@
-[package]
-name = "dioxus-native-core-macro"
-version = "0.2.0"
-edition = "2021"
-description = "Build natively rendered apps with Dioxus"
-license = "MIT/Apache-2.0"
-repository = "https://github.com/DioxusLabs/dioxus/"
-homepage = "https://dioxuslabs.com"
-documentation = "https://dioxuslabs.com"
-keywords = ["dom", "ui", "gui", "react"]
-
-
-[lib]
-proc-macro = true
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-[dependencies]
-syn = { version = "1.0.11", features = ["extra-traits"] }
-quote = "1.0"
-dioxus-native-core = { path = "../native-core", version = "^0.2.0" }
-dioxus = { path = "../dioxus" }
-
-[dev-dependencies]
-smallvec = "1.6"
-rustc-hash = "1.1.0"
-anymap = "0.12.1"

+ 0 - 43
packages/native-core-macro/README.md

@@ -1,43 +0,0 @@
-# Dioxus Native Core Macro
-
-[![Crates.io][crates-badge]][crates-url]
-[![MIT licensed][mit-badge]][mit-url]
-[![Build Status][actions-badge]][actions-url]
-[![Discord chat][discord-badge]][discord-url]
-
-[crates-badge]: https://img.shields.io/crates/v/dioxus-native-core-macro.svg
-[crates-url]: https://crates.io/crates/dioxus-native-core-macro
-
-[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
-[mit-url]: https://github.com/dioxuslabs/dioxus/blob/master/LICENSE
-
-[actions-badge]: https://github.com/dioxuslabs/dioxus/actions/workflows/main.yml/badge.svg
-[actions-url]: https://github.com/dioxuslabs/dioxus/actions?query=workflow%3ACI+branch%3Amaster
-
-[discord-badge]: https://img.shields.io/discord/899851952891002890.svg?logo=discord&style=flat-square
-[discord-url]: https://discord.gg/XgGxMSkvUM
-
-[Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/) |
-[API Docs](https://docs.rs/dioxus-native-core-macro/latest/dioxus_native_core_macro) |
-[Chat](https://discord.gg/XgGxMSkvUM)
-
-
-## Overview
-
-`dioxus-native-core-macro` provides a handful of macros used by native-core for native renderers like TUI, Blitz, and Freya to derive their state.
-
-
-## Contributing
-
-- Report issues on our [issue tracker](https://github.com/dioxuslabs/dioxus/issues).
-- Join the discord and ask questions!
-
-## License
-This project is licensed under the [MIT license].
-
-[mit license]: https://github.com/DioxusLabs/dioxus/blob/master/LICENSE-MIT
-
-Unless you explicitly state otherwise, any contribution intentionally submitted
-for inclusion in Dioxus by you shall be licensed as MIT without any additional
-terms or conditions.

+ 0 - 134
packages/native-core-macro/src/lib.rs

@@ -1,134 +0,0 @@
-extern crate proc_macro;
-
-mod sorted_slice;
-
-use proc_macro::TokenStream;
-use quote::quote;
-use sorted_slice::StrSlice;
-use syn::{self, parse_macro_input};
-
-/// Sorts a slice of string literals at compile time.
-#[proc_macro]
-pub fn sorted_str_slice(input: TokenStream) -> TokenStream {
-    let slice: StrSlice = parse_macro_input!(input as StrSlice);
-    let strings = slice.map.values();
-    quote!([#(#strings, )*]).into()
-}
-
-/// Derive's the state from any members that implement the Pass trait
-#[proc_macro_derive(State, attributes(skip, skip_clone))]
-pub fn state_macro_derive(input: TokenStream) -> TokenStream {
-    let ast = syn::parse(input).unwrap();
-    impl_derive_macro(&ast)
-}
-
-fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
-    let custom_type = ast
-        .attrs
-        .iter()
-        .find(|a| a.path.is_ident("state"))
-        .and_then(|attr| {
-            // parse custom_type = "MyType"
-            let assignment = attr.parse_args::<syn::Expr>().unwrap();
-            if let syn::Expr::Assign(assign) = assignment {
-                let (left, right) = (&*assign.left, &*assign.right);
-                if let syn::Expr::Path(e) = left {
-                    let path = &e.path;
-                    if let Some(ident) = path.get_ident() {
-                        if ident == "custom_value" {
-                            return match right {
-                                syn::Expr::Path(e) => {
-                                    let path = &e.path;
-                                    Some(quote! {#path})
-                                }
-                                _ => None,
-                            };
-                        }
-                    }
-                }
-            }
-            None
-        })
-        .unwrap_or(quote! {()});
-    let type_name = &ast.ident;
-    let fields: Vec<_> = match &ast.data {
-        syn::Data::Struct(data) => match &data.fields {
-            syn::Fields::Named(e) => &e.named,
-            syn::Fields::Unnamed(_) => todo!("unnamed fields"),
-            syn::Fields::Unit => todo!("unit structs"),
-        }
-        .iter()
-        .collect(),
-        _ => unimplemented!(),
-    };
-
-    let types = fields
-        .iter()
-        .filter(|field| !field.attrs.iter().any(|attr| attr.path.is_ident("skip")))
-        .map(|field| &field.ty);
-
-    let gen = quote! {
-        impl dioxus_native_core::State<#custom_type> for #type_name {
-            fn create_passes() -> Box<[dioxus_native_core::TypeErasedPass<Self>]> {
-                Box::new([
-                    #(
-                        <#types as dioxus_native_core::Pass>::to_type_erased()
-                    ),*
-                ])
-            }
-        }
-    };
-
-    gen.into()
-}
-
-/// Derive's the state from any elements that have a node_dep_state, child_dep_state, parent_dep_state, or state attribute.
-#[proc_macro_derive(AnyMapLike)]
-pub fn anymap_like_macro_derive(input: TokenStream) -> TokenStream {
-    let ast = syn::parse(input).unwrap();
-    impl_anymap_like_derive_macro(&ast)
-}
-
-fn impl_anymap_like_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
-    let type_name = &ast.ident;
-    let fields: Vec<_> = match &ast.data {
-        syn::Data::Struct(data) => match &data.fields {
-            syn::Fields::Named(e) => &e.named,
-            syn::Fields::Unnamed(_) => todo!("unnamed fields"),
-            syn::Fields::Unit => todo!("unit structs"),
-        }
-        .iter()
-        .collect(),
-        _ => unimplemented!(),
-    };
-
-    let names: Vec<_> = fields
-        .iter()
-        .map(|field| field.ident.as_ref().unwrap())
-        .collect();
-    let types: Vec<_> = fields.iter().map(|field| &field.ty).collect();
-
-    let gen = quote! {
-        impl dioxus_native_core::AnyMapLike for #type_name {
-            fn get<T: std::any::Any>(&self) -> Option<&T> {
-                #(
-                    if std::any::TypeId::of::<T>() == std::any::TypeId::of::<#types>() {
-                        return unsafe { Some(&*(&self.#names as *const _ as *const T)) }
-                    }
-                )*
-                None
-            }
-
-            fn get_mut<T: std::any::Any>(&mut self) -> Option<&mut T> {
-                #(
-                    if std::any::TypeId::of::<T>() == std::any::TypeId::of::<#types>() {
-                        return unsafe { Some(&mut *(&mut self.#names as *mut _ as *mut T)) }
-                    }
-                )*
-                None
-            }
-        }
-    };
-
-    gen.into()
-}

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

@@ -1,29 +0,0 @@
-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 - 244
packages/native-core-macro/tests/called_minimally_on_build.rs

@@ -1,244 +0,0 @@
-use dioxus::prelude::*;
-use dioxus_native_core::node_ref::*;
-use dioxus_native_core::real_dom::*;
-use dioxus_native_core::state::{
-    ChildDepState, ElementBorrowable, NodeDepState, ParentDepState, State,
-};
-use dioxus_native_core::tree::*;
-use dioxus_native_core::SendAnyMap;
-use dioxus_native_core_macro::State;
-
-macro_rules! dep {
-    ( child( $name:ty, $dep:ty ) ) => {
-        impl ChildDepState for $name {
-            type Ctx = ();
-            type DepState = $dep;
-            const NODE_MASK: NodeMask = NodeMask::ALL;
-            fn reduce<'a>(
-                &mut self,
-                _: NodeView,
-                _: impl Iterator<Item = <Self::DepState as ElementBorrowable>::ElementBorrowed<'a>>,
-                _: &Self::Ctx,
-            ) -> bool
-            where
-                Self::DepState: 'a,
-            {
-                self.0 += 1;
-                true
-            }
-        }
-    };
-
-    ( parent( $name:ty, $dep:ty ) ) => {
-        impl ParentDepState for $name {
-            type Ctx = ();
-            type DepState = $dep;
-            const NODE_MASK: NodeMask = NodeMask::ALL;
-            fn reduce(
-                &mut self,
-                _: NodeView,
-                _: Option<<Self::DepState as ElementBorrowable>::ElementBorrowed<'_>>,
-                _: &Self::Ctx,
-            ) -> bool {
-                self.0 += 1;
-                true
-            }
-        }
-    };
-
-    ( node( $name:ty, $dep:ty ) ) => {
-        impl NodeDepState for $name {
-            type Ctx = ();
-            type DepState = $dep;
-            const NODE_MASK: NodeMask = NodeMask::ALL;
-            fn reduce(
-                &mut self,
-                _: NodeView,
-                _: <Self::DepState as ElementBorrowable>::ElementBorrowed<'_>,
-                _: &Self::Ctx,
-            ) -> bool {
-                self.0 += 1;
-                true
-            }
-        }
-    };
-}
-
-macro_rules! test_state{
-    ( $s:ty, child: ( $( $child:ident ),* ), node: ( $( $node:ident ),* ), parent: ( $( $parent:ident ),* ) ) => {
-        #[test]
-        fn state_reduce_initally_called_minimally() {
-            #[allow(non_snake_case)]
-            fn Base(cx: Scope) -> Element {
-                render!{
-                    div {
-                        div{
-                            div{
-                                p{}
-                            }
-                            p{
-                                "hello"
-                            }
-                            div{
-                                h1{}
-                            }
-                            p{
-                                "world"
-                            }
-                        }
-                    }
-                }
-            }
-
-            let mut vdom = VirtualDom::new(Base);
-
-            let mutations = vdom.rebuild();
-
-            let mut dom: RealDom<$s> = RealDom::new();
-
-            let (nodes_updated, _) = dom.apply_mutations(mutations);
-            let _to_rerender = dom.update_state(nodes_updated, SendAnyMap::new());
-
-            dom.traverse_depth_first(|n| {
-                $(
-                    assert_eq!(n.state.$child.0, 1);
-                )*
-                $(
-                    assert_eq!(n.state.$node.0, 1);
-                )*
-                $(
-                    assert_eq!(n.state.$parent.0, 1);
-                )*
-            });
-        }
-    }
-}
-
-mod node_depends_on_child_and_parent {
-    use super::*;
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Node(i32);
-    dep!(node(Node, (Child, Parent)));
-
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Child(i32);
-    dep!(child(Child, (Child,)));
-
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Parent(i32);
-    dep!(parent(Parent, (Parent,)));
-
-    #[derive(Debug, Clone, Default, State)]
-    struct StateTester {
-        #[node_dep_state((child, parent))]
-        node: Node,
-        #[child_dep_state(child)]
-        child: Child,
-        #[parent_dep_state(parent)]
-        parent: Parent,
-    }
-
-    test_state!(StateTester, child: (child), node: (node), parent: (parent));
-}
-
-mod child_depends_on_node_that_depends_on_parent {
-    use super::*;
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Node(i32);
-    dep!(node(Node, (Parent,)));
-
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Child(i32);
-    dep!(child(Child, (Node,)));
-
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Parent(i32);
-    dep!(parent(Parent, (Parent,)));
-
-    #[derive(Debug, Clone, Default, State)]
-    struct StateTester {
-        #[node_dep_state(parent)]
-        node: Node,
-        #[child_dep_state(node)]
-        child: Child,
-        #[parent_dep_state(parent)]
-        parent: Parent,
-    }
-
-    test_state!(StateTester, child: (child), node: (node), parent: (parent));
-}
-
-mod parent_depends_on_node_that_depends_on_child {
-    use super::*;
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Node(i32);
-    dep!(node(Node, (Child,)));
-
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Child(i32);
-    dep!(child(Child, (Child,)));
-
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Parent(i32);
-    dep!(parent(Parent, (Node,)));
-
-    #[derive(Debug, Clone, Default, State)]
-    struct StateTester {
-        #[node_dep_state(child)]
-        node: Node,
-        #[child_dep_state(child)]
-        child: Child,
-        #[parent_dep_state(node)]
-        parent: Parent,
-    }
-
-    test_state!(StateTester, child: (child), node: (node), parent: (parent));
-}
-
-mod node_depends_on_other_node_state {
-    use super::*;
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Node1(i32);
-    dep!(node(Node1, (Node2,)));
-
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Node2(i32);
-    dep!(node(Node2, ()));
-
-    #[derive(Debug, Clone, Default, State)]
-    struct StateTester {
-        #[node_dep_state((node2))]
-        node1: Node1,
-        #[node_dep_state()]
-        node2: Node2,
-    }
-
-    test_state!(StateTester, child: (), node: (node1, node2), parent: ());
-}
-
-mod node_child_and_parent_state_depends_on_self {
-    use super::*;
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Node(i32);
-    dep!(node(Node, ()));
-
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Child(i32);
-    dep!(child(Child, (Child,)));
-
-    #[derive(Debug, Clone, Default, PartialEq)]
-    struct Parent(i32);
-    dep!(parent(Parent, (Parent,)));
-
-    #[derive(Debug, Clone, Default, State)]
-    struct StateTester {
-        #[node_dep_state()]
-        node: Node,
-        #[child_dep_state(child)]
-        child: Child,
-        #[parent_dep_state(parent)]
-        parent: Parent,
-    }
-
-    test_state!(StateTester, child: (child), node: (node), parent: (parent));
-}

+ 0 - 421
packages/native-core-macro/tests/update_state.rs

@@ -1,421 +0,0 @@
-use dioxus::prelude::*;
-use dioxus_native_core::real_dom::*;
-use dioxus_native_core::state::{ChildDepState, NodeDepState, ParentDepState, State};
-use dioxus_native_core::tree::TreeView;
-use dioxus_native_core::{node_ref::*, NodeId, SendAnyMap};
-use dioxus_native_core_macro::State;
-
-#[derive(Debug, Clone, Default, State)]
-struct CallCounterState {
-    #[child_dep_state(child_counter)]
-    child_counter: ChildDepCallCounter,
-    #[parent_dep_state(parent_counter)]
-    parent_counter: ParentDepCallCounter,
-    #[node_dep_state()]
-    node_counter: NodeDepCallCounter,
-}
-
-#[derive(Debug, Clone, Default)]
-struct ChildDepCallCounter(u32);
-impl ChildDepState for ChildDepCallCounter {
-    type Ctx = ();
-    type DepState = (Self,);
-    const NODE_MASK: NodeMask = NodeMask::ALL;
-    fn reduce<'a>(
-        &mut self,
-        _: NodeView,
-        _: impl Iterator<Item = (&'a Self,)>,
-        _: &Self::Ctx,
-    ) -> bool
-    where
-        Self::DepState: 'a,
-    {
-        self.0 += 1;
-        true
-    }
-}
-
-#[derive(Debug, Clone, Default)]
-struct ParentDepCallCounter(u32);
-impl ParentDepState for ParentDepCallCounter {
-    type Ctx = ();
-    type DepState = (Self,);
-    const NODE_MASK: NodeMask = NodeMask::ALL;
-    fn reduce(&mut self, _node: NodeView, _parent: Option<(&Self,)>, _ctx: &Self::Ctx) -> bool {
-        self.0 += 1;
-        true
-    }
-}
-
-#[derive(Debug, Clone, Default)]
-struct NodeDepCallCounter(u32);
-impl NodeDepState for NodeDepCallCounter {
-    type Ctx = ();
-    type DepState = ();
-    const NODE_MASK: NodeMask = NodeMask::ALL;
-    fn reduce(&mut self, _node: NodeView, _sibling: (), _ctx: &Self::Ctx) -> bool {
-        self.0 += 1;
-        true
-    }
-}
-
-#[allow(clippy::vec_box)]
-#[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().with_tag();
-    fn reduce<'a>(
-        &mut self,
-        node: NodeView,
-        children: impl Iterator<Item = (&'a Self,)>,
-        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().with_tag();
-    fn reduce(&mut self, node: NodeView, parent: Option<(&Self,)>, 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_with_attrs(AttributeMask::All).with_tag();
-    fn reduce(&mut self, node: NodeView, _sibling: (), ctx: &Self::Ctx) -> bool {
-        assert_eq!(*ctx, 42);
-        *self = NodeStateTester(
-            node.tag().map(|s| s.to_string()),
-            node.attributes()
-                .map(|iter| {
-                    iter.map(|a| {
-                        (
-                            a.attribute.name.to_string(),
-                            a.value.as_text().unwrap().to_string(),
-                        )
-                    })
-                    .collect()
-                })
-                .unwrap_or_default(),
-        );
-        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,
-}
-
-#[test]
-fn state_initial() {
-    #[allow(non_snake_case)]
-    fn Base(cx: Scope) -> Element {
-        render! {
-            div {
-                p{
-                    color: "red"
-                }
-                h1{}
-            }
-        }
-    }
-
-    let mut vdom = VirtualDom::new(Base);
-
-    let mutations = vdom.rebuild();
-
-    let mut dom: RealDom<StateTester> = RealDom::new();
-
-    let (nodes_updated, _) = dom.apply_mutations(mutations);
-    let mut ctx = SendAnyMap::new();
-    ctx.insert(42u32);
-    let _to_rerender = dom.update_state(nodes_updated, ctx);
-
-    let root_div_id = dom.children_ids(NodeId(0)).unwrap()[0];
-    let root_div = &dom.get(root_div_id).unwrap();
-    assert_eq!(root_div.state.bubbled.0, Some("div".to_string()));
-    assert_eq!(
-        root_div.state.bubbled.1,
-        vec![
-            Box::new(BubbledUpStateTester(Some("p".to_string()), Vec::new())),
-            Box::new(BubbledUpStateTester(Some("h1".to_string()), Vec::new()))
-        ]
-    );
-    assert_eq!(root_div.state.pushed.0, Some("div".to_string()));
-    assert_eq!(
-        root_div.state.pushed.1,
-        Some(Box::new(PushedDownStateTester(
-            Some("Root".to_string()),
-            None
-        )))
-    );
-    assert_eq!(root_div.state.node.0, Some("div".to_string()));
-    assert_eq!(root_div.state.node.1, vec![]);
-
-    let child_p_id = dom.children_ids(root_div_id).unwrap()[0];
-    let child_p = &dom[child_p_id];
-    assert_eq!(child_p.state.bubbled.0, Some("p".to_string()));
-    assert_eq!(child_p.state.bubbled.1, Vec::new());
-    assert_eq!(child_p.state.pushed.0, Some("p".to_string()));
-    assert_eq!(
-        child_p.state.pushed.1,
-        Some(Box::new(PushedDownStateTester(
-            Some("div".to_string()),
-            Some(Box::new(PushedDownStateTester(
-                Some("Root".to_string()),
-                None
-            )))
-        )))
-    );
-    assert_eq!(child_p.state.node.0, Some("p".to_string()));
-    assert_eq!(
-        child_p.state.node.1,
-        vec![("color".to_string(), "red".to_string())]
-    );
-
-    let child_h1_id = dom.children_ids(root_div_id).unwrap()[1];
-    let child_h1 = &dom[child_h1_id];
-    assert_eq!(child_h1.state.bubbled.0, Some("h1".to_string()));
-    assert_eq!(child_h1.state.bubbled.1, Vec::new());
-    assert_eq!(child_h1.state.pushed.0, Some("h1".to_string()));
-    assert_eq!(
-        child_h1.state.pushed.1,
-        Some(Box::new(PushedDownStateTester(
-            Some("div".to_string()),
-            Some(Box::new(PushedDownStateTester(
-                Some("Root".to_string()),
-                None
-            )))
-        )))
-    );
-    assert_eq!(child_h1.state.node.0, Some("h1".to_string()));
-    assert_eq!(child_h1.state.node.1, vec![]);
-}
-
-#[test]
-fn state_reduce_parent_called_minimally_on_update() {
-    #[allow(non_snake_case)]
-    fn Base(cx: Scope) -> Element {
-        let width = if cx.generation() == 0 { "100%" } else { "99%" };
-        cx.render(rsx! {
-            div {
-                width: "{width}",
-                div{
-                    div{
-                        p{}
-                    }
-                    p{
-                        "hello"
-                    }
-                    div{
-                        h1{}
-                    }
-                    p{
-                        "world"
-                    }
-                }
-            }
-        })
-    }
-
-    let mut vdom = VirtualDom::new(Base);
-
-    let mut dom: RealDom<CallCounterState> = RealDom::new();
-
-    let (nodes_updated, _) = dom.apply_mutations(vdom.rebuild());
-    let _to_rerender = dom.update_state(nodes_updated, SendAnyMap::new());
-    vdom.mark_dirty(ScopeId(0));
-    let (nodes_updated, _) = dom.apply_mutations(vdom.render_immediate());
-    let _to_rerender = dom.update_state(nodes_updated, SendAnyMap::new());
-
-    let mut is_root = true;
-    dom.traverse_depth_first(|n| {
-        if is_root {
-            is_root = false;
-            assert_eq!(n.state.parent_counter.0, 1);
-        } else {
-            assert_eq!(n.state.parent_counter.0, 2);
-        }
-    });
-}
-
-#[test]
-fn state_reduce_child_called_minimally_on_update() {
-    #[allow(non_snake_case)]
-    fn Base(cx: Scope) -> Element {
-        let width = if cx.generation() == 0 { "100%" } else { "99%" };
-        cx.render(rsx! {
-            // updated: 2
-            div {
-                // updated: 2
-                div{
-                    // updated: 2
-                    div{
-                        // updated: 2
-                        p{
-                            width: "{width}",
-                        }
-                    }
-                    // updated: 1
-                    p{
-                        // updated: 1
-                        "hello"
-                    }
-                    // updated: 1
-                    div{
-                        // updated: 1
-                        h1{}
-                    }
-                    // updated: 1
-                    p{
-                        // updated: 1
-                        "world"
-                    }
-                }
-            }
-        })
-    }
-
-    let mut vdom = VirtualDom::new(Base);
-
-    let mut dom: RealDom<CallCounterState> = RealDom::new();
-
-    let (nodes_updated, _) = dom.apply_mutations(vdom.rebuild());
-    let _to_rerender = dom.update_state(nodes_updated, SendAnyMap::new());
-    vdom.mark_dirty(ScopeId(0));
-    let (nodes_updated, _) = dom.apply_mutations(vdom.render_immediate());
-    let _to_rerender = dom.update_state(nodes_updated, SendAnyMap::new());
-
-    let mut traverse_count = 0;
-    dom.traverse_depth_first(|n| {
-        assert_eq!(n.state.child_counter.0, {
-            if traverse_count > 4 {
-                1
-            } else {
-                2
-            }
-        });
-        traverse_count += 1;
-    });
-}
-
-#[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,): (&BDepCallCounter,),
-        _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,): (&CDepCallCounter,),
-        _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: (), _ctx: &Self::Ctx) -> bool {
-        self.0 += 1;
-        true
-    }
-}
-
-#[test]
-fn dependancies_order_independant() {
-    #[allow(non_snake_case)]
-    fn Base(cx: Scope) -> Element {
-        render!(div {
-            width: "100%",
-            p{
-                "hello"
-            }
-        })
-    }
-
-    let mut vdom = VirtualDom::new(Base);
-
-    let mut dom: RealDom<UnorderedDependanciesState> = RealDom::new();
-
-    let mutations = vdom.rebuild();
-    let (nodes_updated, _) = dom.apply_mutations(mutations);
-    let _to_rerender = dom.update_state(nodes_updated, SendAnyMap::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

@@ -31,5 +31,4 @@ lightningcss = "1.0.0-alpha.39"
 [dev-dependencies]
 rand = "0.8.5"
 dioxus = { path = "../dioxus", version = "^0.3.0" }
-dioxus-native-core-macro = { path = "../native-core-macro" }
 tokio = { version = "*", features = ["full"] }

+ 109 - 171
packages/native-core/src/node_ref.rs

@@ -1,47 +1,11 @@
-use std::cmp::Ordering;
-
 use dioxus_core::ElementId;
+use rustc_hash::FxHashSet;
 
 use crate::{
     node::{ElementNode, FromAnyValue, NodeData, NodeType, OwnedAttributeView},
     NodeId,
 };
 
-/// Join two sorted iterators
-pub(crate) fn union_ordered_iter<'a>(
-    s_iter: impl Iterator<Item = &'a str>,
-    o_iter: impl Iterator<Item = &'a str>,
-    new_len_guess: usize,
-) -> Vec<String> {
-    let mut s_peekable = s_iter.peekable();
-    let mut o_peekable = o_iter.peekable();
-    let mut v = Vec::with_capacity(new_len_guess);
-    while let Some(s_i) = s_peekable.peek() {
-        while let Some(o_i) = o_peekable.peek() {
-            match o_i.cmp(s_i) {
-                Ordering::Greater => {
-                    break;
-                }
-                Ordering::Less => {
-                    v.push(o_peekable.next().unwrap().to_string());
-                }
-                Ordering::Equal => {
-                    o_peekable.next();
-                    break;
-                }
-            }
-        }
-        v.push(s_peekable.next().unwrap().to_string());
-    }
-    for o_i in o_peekable {
-        v.push(o_i.to_string());
-    }
-    for w in v.windows(2) {
-        debug_assert!(w[1] > w[0]);
-    }
-    v
-}
-
 /// A view into a [VNode] with limited access.
 #[derive(Debug)]
 pub struct NodeView<'a, V: FromAnyValue = ()> {
@@ -138,124 +102,50 @@ impl<'a, V: FromAnyValue> NodeView<'a, V> {
 #[derive(PartialEq, Eq, Clone, Debug)]
 pub enum AttributeMask {
     All,
-    /// A list of attribute names that are visible, this list must be sorted
-    Dynamic(Vec<String>),
-    /// A list of attribute names that are visible, this list must be sorted
-    Static(&'static [&'static str]),
+    Some(FxHashSet<Box<str>>),
 }
 
 impl AttributeMask {
-    /// A empty attribute mask
-    pub const NONE: Self = Self::Static(&[]);
-
     fn contains_attribute(&self, attr: &str) -> bool {
         match self {
             AttributeMask::All => true,
-            AttributeMask::Dynamic(l) => l.binary_search_by_key(&attr, |s| s.as_str()).is_ok(),
-            AttributeMask::Static(l) => l.binary_search(&attr).is_ok(),
+            AttributeMask::Some(attrs) => attrs.contains(attr),
         }
     }
 
     /// Create a new dynamic attribute mask with a single attribute
     pub fn single(new: &str) -> Self {
-        Self::Dynamic(vec![new.to_string()])
-    }
-
-    /// Ensure the attribute list is sorted.
-    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"
-            ),
-            _ => (),
-        }
+        let mut set = FxHashSet::default();
+        set.insert(new.into());
+        Self::Some(set)
     }
 
     /// Combine two attribute masks
     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().map(|s| s.as_str()),
-                    o.iter().map(|s| s.as_str()),
-                    s.len() + o.len(),
-                ))
-            }
-            (AttributeMask::Static(s), AttributeMask::Dynamic(o)) => {
-                AttributeMask::Dynamic(union_ordered_iter(
-                    s.iter().copied(),
-                    o.iter().map(|s| s.as_str()),
-                    s.len() + o.len(),
-                ))
-            }
-            (AttributeMask::Dynamic(s), AttributeMask::Static(o)) => {
-                AttributeMask::Dynamic(union_ordered_iter(
-                    s.iter().map(|s| s.as_str()),
-                    o.iter().copied(),
-                    s.len() + o.len(),
-                ))
+        match (self, other) {
+            (AttributeMask::Some(s), AttributeMask::Some(o)) => {
+                AttributeMask::Some(s.intersection(o).cloned().collect())
             }
-            (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
+        }
     }
 
     /// Check if two attribute masks overlap
     fn overlaps(&self, other: &Self) -> bool {
-        fn overlaps_iter<'a>(
-            self_iter: impl Iterator<Item = &'a str>,
-            mut other_iter: impl Iterator<Item = &'a str>,
-        ) -> bool {
-            if let Some(mut other_attr) = other_iter.next() {
-                for self_attr in self_iter {
-                    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().map(|s| s.as_str()), v2.iter().map(|s| s.as_str()))
-            }
-            (AttributeMask::Dynamic(v), AttributeMask::Static(s)) => {
-                overlaps_iter(v.iter().map(|s| s.as_str()), s.iter().copied())
-            }
-            (AttributeMask::Static(s), AttributeMask::Dynamic(v)) => {
-                overlaps_iter(v.iter().map(|s| s.as_str()), s.iter().copied())
-            }
-            (AttributeMask::Static(s1), AttributeMask::Static(s2)) => {
-                overlaps_iter(s1.iter().copied(), s2.iter().copied())
+            (AttributeMask::All, AttributeMask::Some(attrs)) => !attrs.is_empty(),
+            (AttributeMask::Some(attrs), AttributeMask::All) => !attrs.is_empty(),
+            (AttributeMask::Some(attrs1), AttributeMask::Some(attrs2)) => {
+                !attrs1.is_disjoint(attrs2)
             }
+            _ => true,
         }
     }
 }
 
 impl Default for AttributeMask {
     fn default() -> Self {
-        AttributeMask::Static(&[])
+        AttributeMask::Some(FxHashSet::default())
     }
 }
 
@@ -270,33 +160,33 @@ pub struct NodeMask {
 }
 
 impl NodeMask {
-    /// A node mask with no parts visible.
-    pub const NONE: Self = Self::new();
-    /// A node mask with every part visible.
-    pub const ALL: Self = Self::new_with_attrs(AttributeMask::All)
-        .with_text()
-        .with_element()
-        .with_listeners();
-
     pub fn from_node(node: &NodeType) -> Self {
         match node {
-            NodeType::Text { .. } => Self::new().with_text(),
+            NodeType::Text { .. } => NodeMaskBuilder::new().with_text().build(),
             NodeType::Element(ElementNode {
                 tag: _,
                 namespace: _,
                 attributes,
                 listeners,
-            }) => {
-                let mut mask = Self::new_with_attrs(AttributeMask::Dynamic(
-                    attributes.keys().map(|key| key.name.clone()).collect(),
-                ))
-                .with_element();
-                if !listeners.is_empty() {
-                    mask = mask.with_listeners();
-                }
-                mask
-            }
-            NodeType::Placeholder => Self::new().with_element(),
+            }) => Self {
+                attritutes: AttributeMask::Some(
+                    attributes
+                        .keys()
+                        .map(|key| key.name.as_str().into())
+                        .collect(),
+                ),
+                namespace: true,
+                tag: true,
+                text: false,
+                listeners: !listeners.is_empty(),
+            },
+            NodeType::Placeholder => Self {
+                attritutes: AttributeMask::default(),
+                tag: true,
+                namespace: true,
+                text: false,
+                listeners: false,
+            },
         }
     }
 
@@ -320,8 +210,65 @@ impl NodeMask {
         }
     }
 
+    /// Allow the mask to view the given attributes
+    pub fn add_attributes(&mut self, attributes: AttributeMask) {
+        self.attritutes = self.attritutes.union(&attributes);
+    }
+
+    /// Set the mask to view the tag
+    pub fn set_tag(&mut self) {
+        self.tag = true;
+    }
+
+    /// Set the mask to view the namespace
+    pub fn set_namespace(&mut self) {
+        self.namespace = true;
+    }
+
+    /// Set the mask to view the text
+    pub fn set_text(&mut self) {
+        self.text = true;
+    }
+
+    /// Set the mask to view the listeners
+    pub fn set_listeners(&mut self) {
+        self.listeners = true;
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Debug)]
+pub enum AttributeMaskBuilder {
+    All,
+    Some(&'static [&'static str]),
+}
+
+impl Default for AttributeMaskBuilder {
+    fn default() -> Self {
+        AttributeMaskBuilder::Some(&[])
+    }
+}
+
+/// A mask that limits what parts of a node a dependency can see.
+#[derive(Default, PartialEq, Eq, Clone, Debug)]
+pub struct NodeMaskBuilder {
+    attritutes: AttributeMaskBuilder,
+    tag: bool,
+    namespace: bool,
+    text: bool,
+    listeners: bool,
+}
+
+impl NodeMaskBuilder {
+    /// A node mask with no parts visible.
+    pub const NONE: Self = Self::new();
+    /// A node mask with every part visible.
+    pub const ALL: Self = Self::new_with_attrs(AttributeMaskBuilder::All)
+        .with_text()
+        .with_element()
+        .with_listeners();
+
     /// Create a new node mask with the given attributes
-    pub const fn new_with_attrs(attritutes: AttributeMask) -> Self {
+    pub const fn new_with_attrs(attritutes: AttributeMaskBuilder) -> Self {
         Self {
             attritutes,
             tag: false,
@@ -333,7 +280,7 @@ impl NodeMask {
 
     /// Create a empty node mask
     pub const fn new() -> Self {
-        Self::new_with_attrs(AttributeMask::NONE)
+        Self::new_with_attrs(AttributeMaskBuilder::Some(&[]))
     }
 
     /// Allow the mask to view the tag
@@ -342,22 +289,12 @@ impl NodeMask {
         self
     }
 
-    /// Set the mask to view the tag
-    pub fn set_tag(&mut self) {
-        self.tag = true;
-    }
-
     /// Allow the mask to view the namespace
     pub const fn with_namespace(mut self) -> Self {
         self.namespace = true;
         self
     }
 
-    /// Set the mask to view the namespace
-    pub fn set_namespace(&mut self) {
-        self.namespace = true;
-    }
-
     /// Allow the mask to view the namespace and tag
     pub const fn with_element(self) -> Self {
         self.with_namespace().with_tag()
@@ -369,24 +306,25 @@ impl NodeMask {
         self
     }
 
-    /// Set the mask to view the text
-    pub fn set_text(&mut self) {
-        self.text = true;
-    }
-
     /// Allow the mask to view the listeners
     pub const fn with_listeners(mut self) -> Self {
         self.listeners = true;
         self
     }
 
-    /// Set the mask to view the listeners
-    pub fn set_listeners(&mut self) {
-        self.listeners = true;
-    }
-
-    /// Allow the mask to view the given attributes
-    pub fn add_attributes(&mut self, attributes: AttributeMask) {
-        self.attritutes = self.attritutes.union(&attributes);
+    /// Build the mask
+    pub fn build(self) -> NodeMask {
+        NodeMask {
+            attritutes: match self.attritutes {
+                AttributeMaskBuilder::All => AttributeMask::All,
+                AttributeMaskBuilder::Some(attrs) => {
+                    AttributeMask::Some(attrs.iter().map(|s| (*s).into()).collect())
+                }
+            },
+            tag: self.tag,
+            namespace: self.namespace,
+            text: self.text,
+            listeners: self.listeners,
+        }
     }
 }

+ 5 - 4
packages/native-core/src/passes.rs

@@ -7,7 +7,7 @@ use std::marker::PhantomData;
 use std::sync::Arc;
 
 use crate::node::{FromAnyValue, NodeData};
-use crate::node_ref::NodeView;
+use crate::node_ref::{NodeMaskBuilder, NodeView};
 use crate::real_dom::RealDom;
 use crate::tree::TreeStateView;
 use crate::{FxDashMap, FxDashSet, SendAnyMap};
@@ -116,7 +116,7 @@ pub trait Pass<V: FromAnyValue + Send = ()>: Any {
     type ChildDependencies: Dependancy;
     /// This is a tuple of (T: Any, ..)
     type NodeDependencies: Dependancy;
-    const NODE_MASK: NodeMask;
+    const NODE_MASK: NodeMaskBuilder;
 
     fn pass<'a>(
         &mut self,
@@ -158,13 +158,14 @@ pub trait Pass<V: FromAnyValue + Send = ()>: Any {
         Self: Sized,
     {
         Self::validate();
+        let node_mask = Self::NODE_MASK.build();
         TypeErasedPass {
             this_type_id: TypeId::of::<Self>(),
             combined_dependancy_type_ids: Self::all_dependanices().iter().copied().collect(),
             parent_dependant: !Self::parent_type_ids().is_empty(),
             child_dependant: !Self::child_type_ids().is_empty(),
             dependants: FxHashSet::default(),
-            mask: Self::NODE_MASK,
+            mask: node_mask,
             pass_direction: Self::pass_direction(),
             pass: Box::new(
                 |node_id: NodeId, tree: &mut TreeStateView, context: &SendAnyMap| {
@@ -181,7 +182,7 @@ pub trait Pass<V: FromAnyValue + Send = ()>: Any {
                     let myself = unsafe { &mut *node_raw };
 
                     myself.pass(
-                        NodeView::new(node_data, Self::NODE_MASK),
+                        NodeView::new(node_data, Self::NODE_MASK.build()),
                         node,
                         parent,
                         children,

+ 4 - 4
packages/native-core/src/real_dom.rs

@@ -7,7 +7,7 @@ use std::collections::VecDeque;
 use crate::node::{
     ElementNode, FromAnyValue, NodeData, NodeType, OwnedAttributeDiscription, OwnedAttributeValue,
 };
-use crate::node_ref::{AttributeMask, NodeMask};
+use crate::node_ref::{AttributeMask, NodeMask, NodeMaskBuilder};
 use crate::passes::{resolve_passes, DirtyNodeStates, TypeErasedPass};
 use crate::tree::{EntryBuilder, NodeId, Tree};
 use crate::{FxDashSet, SendAnyMap};
@@ -64,7 +64,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
 
         let mut nodes_updated = FxHashMap::default();
         let root_id = NodeId(0);
-        nodes_updated.insert(root_id, NodeMask::ALL);
+        nodes_updated.insert(root_id, NodeMaskBuilder::ALL.build());
 
         RealDom {
             tree,
@@ -389,7 +389,7 @@ impl<V: FromAnyValue + Send + Sync> RealDom<V> {
     pub fn get_mut(&mut self, id: NodeId) -> Option<NodeMut<'_, V>> {
         self.tree.contains(id).then(|| NodeMut {
             id,
-            dirty: NodeMask::new(),
+            dirty: NodeMask::default(),
             dom: self,
         })
     }
@@ -616,7 +616,7 @@ impl<'a, V: FromAnyValue + Send> NodeMut<'a, V> {
 
     pub fn set_type(&mut self, new: NodeType<V>) {
         self.node_data_mut().node_type = new;
-        self.dirty = NodeMask::ALL;
+        self.dirty = NodeMaskBuilder::ALL.build();
     }
 
     pub fn read<T: Any>(&self) -> Option<&T> {

+ 0 - 1
packages/tui/Cargo.toml

@@ -17,7 +17,6 @@ dioxus = { path = "../dioxus", version = "^0.3.0" }
 dioxus-core = { path = "../core", version = "^0.3.0" }
 dioxus-html = { path = "../html", version = "^0.3.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"
 crossterm = "0.23.0"