mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-27 14:40:44 +00:00
nested state
This commit is contained in:
parent
f4689a4e27
commit
7c30d93a3d
5 changed files with 270 additions and 30 deletions
|
@ -304,7 +304,7 @@ flowchart TB
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
To help in building a Dom, native core provides four traits: State, ChildDepState, ParentDepState, and NodeDepState.
|
To help in building a Dom, native core provides four traits: State, ChildDepState, ParentDepState, and NodeDepState and a RealDom struct.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use dioxus_native_core::node_ref::*;
|
use dioxus_native_core::node_ref::*;
|
||||||
|
@ -436,6 +436,48 @@ struct ToyState {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Now that we have our state, we can put it to use in our dom. Re can update the dom with update_state to update the structure of the dom (adding, removing, and chaning properties of nodes) and then apply_mutations to update the ToyState for each of the nodes that changed.
|
||||||
|
```rust
|
||||||
|
fn main(){
|
||||||
|
fn app(cx: Scope) -> Element {
|
||||||
|
cx.render(rsx!{
|
||||||
|
div{
|
||||||
|
color: "red",
|
||||||
|
"hello world"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let vdom = VirtualDom::new(app);
|
||||||
|
let rdom: RealDom<ToyState> = RealDom::new();
|
||||||
|
|
||||||
|
let mutations = dom.rebuild();
|
||||||
|
// update the structure of the real_dom tree
|
||||||
|
let to_update = rdom.apply_mutations(vec![mutations]);
|
||||||
|
let mut ctx = AnyMap::new();
|
||||||
|
// set the font size to 3.3
|
||||||
|
ctx.insert(3.3);
|
||||||
|
// update the ToyState for nodes in the real_dom tree
|
||||||
|
let _to_rerender = rdom.update_state(&dom, to_update, ctx).unwrap();
|
||||||
|
|
||||||
|
// we need to run the vdom in a async runtime
|
||||||
|
tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()?
|
||||||
|
.block_on(async {
|
||||||
|
loop{
|
||||||
|
let wait = vdom.wait_for_work();
|
||||||
|
let mutations = vdom.work_with_deadline(|| false);
|
||||||
|
let to_update = rdom.apply_mutations(mutations);
|
||||||
|
let mut ctx = AnyMap::new();
|
||||||
|
ctx.insert(3.3);
|
||||||
|
let _to_rerender = rdom.update_state(vdom, to_update, ctx).unwrap();
|
||||||
|
|
||||||
|
// render...
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
For most platforms the layout of the Elements will stay the same. The layout_attributes module provides a way to apply html attributes to a stretch layout style.
|
For most platforms the layout of the Elements will stay the same. The layout_attributes module provides a way to apply html attributes to a stretch layout style.
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ mod sorted_slice;
|
||||||
|
|
||||||
use dioxus_native_core::state::MemberId;
|
use dioxus_native_core::state::MemberId;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
use quote::format_ident;
|
||||||
use quote::{quote, ToTokens, __private::Span};
|
use quote::{quote, ToTokens, __private::Span};
|
||||||
use sorted_slice::StrSlice;
|
use sorted_slice::StrSlice;
|
||||||
use syn::{
|
use syn::{
|
||||||
|
@ -26,7 +27,10 @@ enum DepKind {
|
||||||
Parent,
|
Parent,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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, 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();
|
||||||
impl_derive_macro(&ast)
|
impl_derive_macro(&ast)
|
||||||
|
@ -89,8 +93,51 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
|
|
||||||
let type_name_str = type_name.to_string();
|
let type_name_str = type_name.to_string();
|
||||||
|
|
||||||
|
let child_states = &state_strct.child_states;
|
||||||
|
|
||||||
|
let member_size = state_strct.state_members.len();
|
||||||
|
|
||||||
|
let child_state_ty = child_states.iter().map(|m| &m.ty);
|
||||||
|
let child_state_idents: Vec<_> = child_states.iter().map(|m| &m.ident).collect();
|
||||||
|
let sum_const_declarations = child_state_ty.clone().enumerate().map(|(i, ty)| {
|
||||||
|
let ident = format_ident!("__{}_SUM_{}", i, type_name.to_string());
|
||||||
|
let ident_minus = format_ident!("__{}_SUM_{}_minus", i, type_name.to_string());
|
||||||
|
if i == 0 {
|
||||||
|
quote!(const #ident_minus: usize = #member_size + #ty::SIZE - 1;
|
||||||
|
const #ident: usize = #member_size + #ty::SIZE;)
|
||||||
|
} else {
|
||||||
|
let prev_ident = format_ident!("__{}_SUM_{}", i - 1, type_name.to_string());
|
||||||
|
quote!(const #ident_minus: usize = #prev_ident + #ty::SIZE - 1;
|
||||||
|
const #ident: usize = #prev_ident + #ty::SIZE;)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let sum_idents: Vec<_> = std::iter::once(quote!(#member_size))
|
||||||
|
.chain((0..child_states.len()).map(|i| {
|
||||||
|
let ident = format_ident!("__{}_SUM_{}", i, type_name.to_string());
|
||||||
|
quote!(#ident)
|
||||||
|
}))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let child_state_ranges: Vec<_> = (0..child_state_ty.len())
|
||||||
|
.map(|i| {
|
||||||
|
let current = format_ident!("__{}_SUM_{}_minus", i, type_name.to_string());
|
||||||
|
let previous = if i == 0 {
|
||||||
|
quote!(#member_size)
|
||||||
|
} else {
|
||||||
|
let ident = format_ident!("__{}_SUM_{}", i - 1, type_name.to_string());
|
||||||
|
quote!(#ident)
|
||||||
|
};
|
||||||
|
quote!(#previous..=#current)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
let gen = quote! {
|
let gen = quote! {
|
||||||
|
#(
|
||||||
|
#sum_const_declarations
|
||||||
|
)*
|
||||||
impl State for #type_name{
|
impl State for #type_name{
|
||||||
|
const SIZE: usize = #member_size #( + #child_state_ty::SIZE)*;
|
||||||
|
|
||||||
fn update_node_dep_state<'a>(
|
fn update_node_dep_state<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
ty: dioxus_native_core::state::MemberId,
|
ty: dioxus_native_core::state::MemberId,
|
||||||
|
@ -99,10 +146,26 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
ctx: &anymap::AnyMap,
|
ctx: &anymap::AnyMap,
|
||||||
) -> Option<dioxus_native_core::state::NodeStatesChanged>{
|
) -> Option<dioxus_native_core::state::NodeStatesChanged>{
|
||||||
use dioxus_native_core::state::NodeDepState as _;
|
use dioxus_native_core::state::NodeDepState as _;
|
||||||
|
use dioxus_native_core::state::State as _;
|
||||||
match ty.0{
|
match ty.0{
|
||||||
#(
|
#(
|
||||||
#node_ids => #node_dep_state_fields,
|
#node_ids => #node_dep_state_fields,
|
||||||
)*
|
)*
|
||||||
|
#(
|
||||||
|
#child_state_ranges => {
|
||||||
|
self.#child_state_idents.update_node_dep_state(
|
||||||
|
ty - #sum_idents,
|
||||||
|
node,
|
||||||
|
vdom,
|
||||||
|
ctx,
|
||||||
|
).map(|mut changed|{
|
||||||
|
for id in &mut changed.node_dep{
|
||||||
|
*id += #sum_idents;
|
||||||
|
}
|
||||||
|
changed
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)*
|
||||||
_ => panic!("{:?} not in {}", ty, #type_name_str),
|
_ => panic!("{:?} not in {}", ty, #type_name_str),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,6 +183,25 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
#(
|
#(
|
||||||
#parent_ids => #parent_dep_state_fields,
|
#parent_ids => #parent_dep_state_fields,
|
||||||
)*
|
)*
|
||||||
|
#(
|
||||||
|
#child_state_ranges => {
|
||||||
|
self.#child_state_idents.update_parent_dep_state(
|
||||||
|
ty - #sum_idents,
|
||||||
|
node,
|
||||||
|
vdom,
|
||||||
|
parent.map(|p| &p.#child_state_idents),
|
||||||
|
ctx,
|
||||||
|
).map(|mut changed|{
|
||||||
|
for id in &mut changed.node_dep{
|
||||||
|
*id += #sum_idents;
|
||||||
|
}
|
||||||
|
for id in &mut changed.parent_dep{
|
||||||
|
*id += #sum_idents;
|
||||||
|
}
|
||||||
|
changed
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)*
|
||||||
_ => panic!("{:?} not in {}", ty, #type_name_str),
|
_ => panic!("{:?} not in {}", ty, #type_name_str),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,13 +211,32 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
ty: dioxus_native_core::state::MemberId,
|
ty: dioxus_native_core::state::MemberId,
|
||||||
node: &'a dioxus_core::VNode<'a>,
|
node: &'a dioxus_core::VNode<'a>,
|
||||||
vdom: &'a dioxus_core::VirtualDom,
|
vdom: &'a dioxus_core::VirtualDom,
|
||||||
children: &[&Self],
|
children: &Vec<&Self>,
|
||||||
ctx: &anymap::AnyMap,
|
ctx: &anymap::AnyMap,
|
||||||
) -> Option<dioxus_native_core::state::ChildStatesChanged>{
|
) -> Option<dioxus_native_core::state::ChildStatesChanged>{
|
||||||
use dioxus_native_core::state::ChildDepState as _;
|
use dioxus_native_core::state::ChildDepState as _;
|
||||||
match ty.0{
|
match ty.0{
|
||||||
#(
|
#(
|
||||||
#child_ids => {#child_dep_state_fields},
|
#child_ids => #child_dep_state_fields,
|
||||||
|
)*
|
||||||
|
#(
|
||||||
|
#child_state_ranges => {
|
||||||
|
self.#child_state_idents.update_child_dep_state(
|
||||||
|
ty - #sum_idents,
|
||||||
|
node,
|
||||||
|
vdom,
|
||||||
|
&children.iter().map(|p| &p.#child_state_idents).collect(),
|
||||||
|
ctx,
|
||||||
|
).map(|mut changed|{
|
||||||
|
for id in &mut changed.node_dep{
|
||||||
|
*id += #sum_idents;
|
||||||
|
}
|
||||||
|
for id in &mut changed.child_dep{
|
||||||
|
*id += #sum_idents;
|
||||||
|
}
|
||||||
|
changed
|
||||||
|
})
|
||||||
|
}
|
||||||
)*
|
)*
|
||||||
_ => panic!("{:?} not in {}", ty, #type_name_str),
|
_ => panic!("{:?} not in {}", ty, #type_name_str),
|
||||||
}
|
}
|
||||||
|
@ -146,6 +247,9 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
#(if #child_types::NODE_MASK.overlaps(mask) {
|
#(if #child_types::NODE_MASK.overlaps(mask) {
|
||||||
dep_types.push(dioxus_native_core::state::MemberId(#child_ids_clone));
|
dep_types.push(dioxus_native_core::state::MemberId(#child_ids_clone));
|
||||||
})*
|
})*
|
||||||
|
#(
|
||||||
|
dep_types.extend(self.#child_state_idents.child_dep_types(mask).into_iter().map(|id| id + #sum_idents));
|
||||||
|
)*
|
||||||
dep_types
|
dep_types
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +258,9 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
#(if #parent_types::NODE_MASK.overlaps(mask) {
|
#(if #parent_types::NODE_MASK.overlaps(mask) {
|
||||||
dep_types.push(dioxus_native_core::state::MemberId(#parent_ids_clone));
|
dep_types.push(dioxus_native_core::state::MemberId(#parent_ids_clone));
|
||||||
})*
|
})*
|
||||||
|
#(
|
||||||
|
dep_types.extend(self.#child_state_idents.parent_dep_types(mask).into_iter().map(|id| id + #sum_idents));
|
||||||
|
)*
|
||||||
dep_types
|
dep_types
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +269,9 @@ fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
|
||||||
#(if #node_types::NODE_MASK.overlaps(mask) {
|
#(if #node_types::NODE_MASK.overlaps(mask) {
|
||||||
dep_types.push(dioxus_native_core::state::MemberId(#node_ids_clone));
|
dep_types.push(dioxus_native_core::state::MemberId(#node_ids_clone));
|
||||||
})*
|
})*
|
||||||
|
#(
|
||||||
|
dep_types.extend(self.#child_state_idents.node_dep_types(mask).into_iter().map(|id| id + #sum_idents));
|
||||||
|
)*
|
||||||
dep_types
|
dep_types
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,6 +296,7 @@ impl Struct {
|
||||||
|
|
||||||
struct StateStruct<'a> {
|
struct StateStruct<'a> {
|
||||||
state_members: Vec<StateMember<'a>>,
|
state_members: Vec<StateMember<'a>>,
|
||||||
|
child_states: Vec<&'a Member>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StateStruct<'a> {
|
impl<'a> StateStruct<'a> {
|
||||||
|
@ -203,6 +314,20 @@ impl<'a> StateStruct<'a> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let child_states = strct
|
||||||
|
.members
|
||||||
|
.iter()
|
||||||
|
.zip(fields.iter())
|
||||||
|
.filter(|(_, f)| {
|
||||||
|
f.attrs.iter().any(|a| {
|
||||||
|
a.path
|
||||||
|
.get_ident()
|
||||||
|
.filter(|i| i.to_string().as_str() == "state")
|
||||||
|
.is_some()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map(|(m, _)| m);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct DepNode<'a> {
|
struct DepNode<'a> {
|
||||||
state_mem: StateMember<'a>,
|
state_mem: StateMember<'a>,
|
||||||
|
@ -350,7 +475,10 @@ impl<'a> StateStruct<'a> {
|
||||||
.flat_map(|r| r.flatten().into_iter())
|
.flat_map(|r| r.flatten().into_iter())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(Self { state_members })
|
Ok(Self {
|
||||||
|
state_members,
|
||||||
|
child_states: child_states.collect(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -484,23 +612,23 @@ impl<'a> StateMember<'a> {
|
||||||
DepKind::Node => {
|
DepKind::Node => {
|
||||||
quote! {
|
quote! {
|
||||||
dioxus_native_core::state::NodeStatesChanged{
|
dioxus_native_core::state::NodeStatesChanged{
|
||||||
node_dep: &[#(dioxus_native_core::state::MemberId(#node_dep), )*],
|
node_dep: vec![#(dioxus_native_core::state::MemberId(#node_dep), )*],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DepKind::Child => {
|
DepKind::Child => {
|
||||||
quote! {
|
quote! {
|
||||||
dioxus_native_core::state::ChildStatesChanged{
|
dioxus_native_core::state::ChildStatesChanged{
|
||||||
node_dep: &[#(dioxus_native_core::state::MemberId(#node_dep), )*],
|
node_dep: vec![#(dioxus_native_core::state::MemberId(#node_dep), )*],
|
||||||
child_dep: &[#(dioxus_native_core::state::MemberId(#child_dep), )*],
|
child_dep: vec![#(dioxus_native_core::state::MemberId(#child_dep), )*],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DepKind::Parent => {
|
DepKind::Parent => {
|
||||||
quote! {
|
quote! {
|
||||||
dioxus_native_core::state::ParentStatesChanged{
|
dioxus_native_core::state::ParentStatesChanged{
|
||||||
node_dep: &[#(dioxus_native_core::state::MemberId(#node_dep), )*],
|
node_dep: vec![#(dioxus_native_core::state::MemberId(#node_dep), )*],
|
||||||
parent_dep: &[#(dioxus_native_core::state::MemberId(#parent_dep), )*],
|
parent_dep: vec![#(dioxus_native_core::state::MemberId(#parent_dep), )*],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -515,7 +643,6 @@ impl<'a> StateMember<'a> {
|
||||||
match self.dep_kind {
|
match self.dep_kind {
|
||||||
DepKind::Node => {
|
DepKind::Node => {
|
||||||
quote!({
|
quote!({
|
||||||
// println!("node: {:?} {:?} {:?}", self.#ident, #id, #node_view.id());
|
|
||||||
if self.#ident.reduce(#node_view, &self.#dep_ident, #get_ctx){
|
if self.#ident.reduce(#node_view, &self.#dep_ident, #get_ctx){
|
||||||
Some(#states_changed)
|
Some(#states_changed)
|
||||||
} else{
|
} else{
|
||||||
|
@ -525,7 +652,6 @@ impl<'a> StateMember<'a> {
|
||||||
}
|
}
|
||||||
DepKind::Child => {
|
DepKind::Child => {
|
||||||
quote!({
|
quote!({
|
||||||
// println!("child: {:?} {:?} {:?}", self.#ident, #id, #node_view.id());
|
|
||||||
if self.#ident.reduce(#node_view, children.iter().map(|s| &s.#dep_ident), #get_ctx){
|
if self.#ident.reduce(#node_view, children.iter().map(|s| &s.#dep_ident), #get_ctx){
|
||||||
Some(#states_changed)
|
Some(#states_changed)
|
||||||
} else{
|
} else{
|
||||||
|
@ -535,7 +661,6 @@ impl<'a> StateMember<'a> {
|
||||||
}
|
}
|
||||||
DepKind::Parent => {
|
DepKind::Parent => {
|
||||||
quote!({
|
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){
|
if self.#ident.reduce(#node_view, parent.as_ref().map(|p| &p.#dep_ident), #get_ctx){
|
||||||
Some(#states_changed)
|
Some(#states_changed)
|
||||||
} else{
|
} else{
|
||||||
|
@ -548,7 +673,6 @@ impl<'a> StateMember<'a> {
|
||||||
match self.dep_kind {
|
match self.dep_kind {
|
||||||
DepKind::Node => {
|
DepKind::Node => {
|
||||||
quote!({
|
quote!({
|
||||||
// println!("node: {:?} {:?} {:?}", self.#ident, #id, #node_view.id());
|
|
||||||
if self.#ident.reduce(#node_view, &(), #get_ctx){
|
if self.#ident.reduce(#node_view, &(), #get_ctx){
|
||||||
Some(#states_changed)
|
Some(#states_changed)
|
||||||
} else{
|
} else{
|
||||||
|
@ -558,7 +682,6 @@ impl<'a> StateMember<'a> {
|
||||||
}
|
}
|
||||||
DepKind::Child => {
|
DepKind::Child => {
|
||||||
quote!({
|
quote!({
|
||||||
// println!("child: {:?} {:?} {:?}", self.#ident, #id, #node_view.id());
|
|
||||||
if self.#ident.reduce(#node_view, std::iter::empty(), #get_ctx){
|
if self.#ident.reduce(#node_view, std::iter::empty(), #get_ctx){
|
||||||
Some(#states_changed)
|
Some(#states_changed)
|
||||||
} else{
|
} else{
|
||||||
|
@ -568,7 +691,6 @@ impl<'a> StateMember<'a> {
|
||||||
}
|
}
|
||||||
DepKind::Parent => {
|
DepKind::Parent => {
|
||||||
quote!({
|
quote!({
|
||||||
println!("parent: {:?} {:?} {:?}", self.#ident, #id, #node_view.id());
|
|
||||||
if self.#ident.reduce(#node_view, Some(&()), #get_ctx){
|
if self.#ident.reduce(#node_view, Some(&()), #get_ctx){
|
||||||
Some(#states_changed)
|
Some(#states_changed)
|
||||||
} else{
|
} else{
|
||||||
|
|
|
@ -8,12 +8,36 @@ use dioxus_native_core::real_dom::*;
|
||||||
use dioxus_native_core::state::{ChildDepState, NodeDepState, 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)]
|
||||||
|
struct CallCounterStatePart1 {
|
||||||
|
#[child_dep_state(child_counter)]
|
||||||
|
child_counter: ChildDepCallCounter,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, State)]
|
||||||
|
struct CallCounterStatePart2 {
|
||||||
|
#[parent_dep_state(parent_counter)]
|
||||||
|
parent_counter: ParentDepCallCounter,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, State)]
|
||||||
|
struct CallCounterStatePart3 {
|
||||||
|
#[node_dep_state()]
|
||||||
|
node_counter: NodeDepCallCounter,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, State)]
|
#[derive(Debug, Clone, Default, State)]
|
||||||
struct CallCounterState {
|
struct CallCounterState {
|
||||||
#[child_dep_state(child_counter)]
|
#[child_dep_state(child_counter)]
|
||||||
child_counter: ChildDepCallCounter,
|
child_counter: ChildDepCallCounter,
|
||||||
|
#[state]
|
||||||
|
part2: CallCounterStatePart2,
|
||||||
#[parent_dep_state(parent_counter)]
|
#[parent_dep_state(parent_counter)]
|
||||||
parent_counter: ParentDepCallCounter,
|
parent_counter: ParentDepCallCounter,
|
||||||
|
#[state]
|
||||||
|
part1: CallCounterStatePart1,
|
||||||
|
#[state]
|
||||||
|
part3: CallCounterStatePart3,
|
||||||
#[node_dep_state()]
|
#[node_dep_state()]
|
||||||
node_counter: NodeDepCallCounter,
|
node_counter: NodeDepCallCounter,
|
||||||
}
|
}
|
||||||
|
@ -261,8 +285,11 @@ fn state_reduce_initally_called_minimally() {
|
||||||
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| {
|
||||||
|
assert_eq!(n.state.part1.child_counter.0, 1);
|
||||||
assert_eq!(n.state.child_counter.0, 1);
|
assert_eq!(n.state.child_counter.0, 1);
|
||||||
|
assert_eq!(n.state.part2.parent_counter.0, 1);
|
||||||
assert_eq!(n.state.parent_counter.0, 1);
|
assert_eq!(n.state.parent_counter.0, 1);
|
||||||
|
assert_eq!(n.state.part3.node_counter.0, 1);
|
||||||
assert_eq!(n.state.node_counter.0, 1);
|
assert_eq!(n.state.node_counter.0, 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -329,6 +356,7 @@ fn state_reduce_parent_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| {
|
||||||
|
assert_eq!(n.state.part2.parent_counter.0, 2);
|
||||||
assert_eq!(n.state.parent_counter.0, 2);
|
assert_eq!(n.state.parent_counter.0, 2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -398,6 +426,10 @@ fn state_reduce_child_called_minimally_on_update() {
|
||||||
|
|
||||||
dom.traverse_depth_first(|n| {
|
dom.traverse_depth_first(|n| {
|
||||||
println!("{:?}", n);
|
println!("{:?}", n);
|
||||||
|
assert_eq!(
|
||||||
|
n.state.part1.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 });
|
assert_eq!(n.state.child_counter.0, if n.id.0 > 4 { 1 } else { 2 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -487,3 +519,15 @@ fn dependancies_order_independant() {
|
||||||
assert_eq!(&n.state.c, &c);
|
assert_eq!(&n.state.c, &c);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default, State)]
|
||||||
|
struct DependanciesStateTest {
|
||||||
|
#[node_dep_state(c)]
|
||||||
|
b: BDepCallCounter,
|
||||||
|
#[node_dep_state()]
|
||||||
|
c: CDepCallCounter,
|
||||||
|
#[node_dep_state(b)]
|
||||||
|
a: ADepCallCounter,
|
||||||
|
#[state]
|
||||||
|
child: UnorderedDependanciesState,
|
||||||
|
}
|
||||||
|
|
|
@ -308,7 +308,7 @@ impl<S: State> RealDom<S> {
|
||||||
node.state.update_node_dep_state(id, vnode, vdom, &ctx)
|
node.state.update_node_dep_state(id, vnode, vdom, &ctx)
|
||||||
{
|
{
|
||||||
debug_assert!(members_effected.node_dep.iter().all(|i| i >= &id));
|
debug_assert!(members_effected.node_dep.iter().all(|i| i >= &id));
|
||||||
for m in members_effected.node_dep {
|
for m in &members_effected.node_dep {
|
||||||
if let Err(idx) = ids.binary_search(m) {
|
if let Err(idx) = ids.binary_search(m) {
|
||||||
ids.insert(idx, *m);
|
ids.insert(idx, *m);
|
||||||
}
|
}
|
||||||
|
@ -348,12 +348,12 @@ impl<S: State> RealDom<S> {
|
||||||
{
|
{
|
||||||
debug_assert!(members_effected.node_dep.iter().all(|i| i >= &id));
|
debug_assert!(members_effected.node_dep.iter().all(|i| i >= &id));
|
||||||
for m in members_effected.node_dep {
|
for m in members_effected.node_dep {
|
||||||
if let Err(idx) = ids.binary_search(m) {
|
if let Err(idx) = ids.binary_search(&m) {
|
||||||
ids.insert(idx, *m);
|
ids.insert(idx, m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for m in members_effected.child_dep {
|
for m in members_effected.child_dep {
|
||||||
changed.push(*m);
|
changed.push(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
|
@ -416,12 +416,12 @@ impl<S: State> RealDom<S> {
|
||||||
{
|
{
|
||||||
debug_assert!(members_effected.node_dep.iter().all(|i| i >= &id));
|
debug_assert!(members_effected.node_dep.iter().all(|i| i >= &id));
|
||||||
for m in members_effected.node_dep {
|
for m in members_effected.node_dep {
|
||||||
if let Err(idx) = ids.binary_search(m) {
|
if let Err(idx) = ids.binary_search(&m) {
|
||||||
ids.insert(idx, *m);
|
ids.insert(idx, m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for m in members_effected.parent_dep {
|
for m in members_effected.parent_dep {
|
||||||
changed.push(*m);
|
changed.push(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
use std::{cmp::Ordering, fmt::Debug};
|
use std::{
|
||||||
|
cmp::Ordering,
|
||||||
|
fmt::Debug,
|
||||||
|
ops::{Add, AddAssign, Sub, SubAssign},
|
||||||
|
};
|
||||||
|
|
||||||
use anymap::AnyMap;
|
use anymap::AnyMap;
|
||||||
use dioxus_core::VNode;
|
use dioxus_core::VNode;
|
||||||
|
@ -81,22 +85,24 @@ pub trait NodeDepState {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ChildStatesChanged {
|
pub struct ChildStatesChanged {
|
||||||
pub node_dep: &'static [MemberId],
|
pub node_dep: Vec<MemberId>,
|
||||||
pub child_dep: &'static [MemberId],
|
pub child_dep: Vec<MemberId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParentStatesChanged {
|
pub struct ParentStatesChanged {
|
||||||
pub node_dep: &'static [MemberId],
|
pub node_dep: Vec<MemberId>,
|
||||||
pub parent_dep: &'static [MemberId],
|
pub parent_dep: Vec<MemberId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NodeStatesChanged {
|
pub struct NodeStatesChanged {
|
||||||
pub node_dep: &'static [MemberId],
|
pub node_dep: Vec<MemberId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait State: Default + Clone {
|
pub trait State: Default + Clone {
|
||||||
|
const SIZE: usize;
|
||||||
|
|
||||||
fn update_node_dep_state<'a>(
|
fn update_node_dep_state<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
ty: MemberId,
|
ty: MemberId,
|
||||||
|
@ -123,7 +129,7 @@ pub trait State: Default + Clone {
|
||||||
ty: MemberId,
|
ty: MemberId,
|
||||||
node: &'a VNode<'a>,
|
node: &'a VNode<'a>,
|
||||||
vdom: &'a dioxus_core::VirtualDom,
|
vdom: &'a dioxus_core::VirtualDom,
|
||||||
children: &[&Self],
|
children: &Vec<&Self>,
|
||||||
ctx: &AnyMap,
|
ctx: &AnyMap,
|
||||||
) -> Option<ChildStatesChanged>;
|
) -> 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)
|
||||||
|
@ -165,3 +171,29 @@ impl NodeDepState for () {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct MemberId(pub usize);
|
pub struct MemberId(pub usize);
|
||||||
|
|
||||||
|
impl Sub<usize> for MemberId {
|
||||||
|
type Output = MemberId;
|
||||||
|
fn sub(self, rhs: usize) -> Self::Output {
|
||||||
|
MemberId(self.0 - rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<usize> for MemberId {
|
||||||
|
type Output = MemberId;
|
||||||
|
fn add(self, rhs: usize) -> Self::Output {
|
||||||
|
MemberId(self.0 + rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign<usize> for MemberId {
|
||||||
|
fn sub_assign(&mut self, rhs: usize) {
|
||||||
|
*self = *self - rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign<usize> for MemberId {
|
||||||
|
fn add_assign(&mut self, rhs: usize) {
|
||||||
|
*self = *self + rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue