remove native-core-macro

This commit is contained in:
Evan Almloff committed 2023-01-22 16:41:15 -06:00
1 parent fb0c6c1b62
commit 4738352955
13 files changed
+118 -1081

No files matched your search

-2
View File
@@ -1,2 +0,0 @@
/target
Cargo.lock
-26
View File
@@ -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"
-43
View File
@@ -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.
-134
View File
@@ -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()
}
@@ -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 })
}
}
@@ -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));
}
@@ -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);
});
}