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