add node dependancy
This commit is contained in:
1 parent
0fb9aed273
commit
436c6a02f7
18 files changed
+1312
-575
No files matched your search
@@ -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 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_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 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),
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
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 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 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
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
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
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
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
|
||||
}
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
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 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 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 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?;
|
||||
|
||||
// todo: sort members
|
||||
#[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(),
|
||||
}
|
||||
}
|
||||
|
||||
Self { state_members }
|
||||
}
|
||||
}
|
||||
/// 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
|
||||
}
|
||||
|
||||
struct DepTypes {
|
||||
ctx_ty: Option<Type>,
|
||||
dep_ty: Option<Type>,
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for DepTypes {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let dep_ty = input.parse().ok();
|
||||
let comma: Option<Token![,]> = input.parse().ok();
|
||||
let ctx_ty = input.parse().ok();
|
||||
Ok(Self {
|
||||
ctx_ty: comma.and(ctx_ty),
|
||||
dep_ty,
|
||||
})
|
||||
}
|
||||
}
|
||||
fn contains_member(&self, member: &Member) -> bool {
|
||||
if self.state_mem.mem == member {
|
||||
true
|
||||
} else {
|
||||
self.depandants.iter().any(|d| d.contains_member(member))
|
||||
}
|
||||
}
|
||||
|
||||
struct NodeDepTypes {
|
||||
ctx_ty: Option<Type>,
|
||||
}
|
||||
// check if there are any mixed child/parent dependancies
|
||||
fn check(&self) -> Option<Error> {
|
||||
self.kind().err()
|
||||
}
|
||||
|
||||
impl Parse for NodeDepTypes {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let ctx_ty = input.parse().ok();
|
||||
Ok(Self { ctx_ty })
|
||||
}
|
||||
}
|
||||
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,
|
||||
)
|
||||
}
|
||||
|
||||
impl From<NodeDepTypes> for DepTypes {
|
||||
fn from(node_dep_types: NodeDepTypes) -> Self {
|
||||
Self {
|
||||
ctx_ty: node_dep_types.ctx_ty,
|
||||
dep_ty: None,
|
||||
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 Dependancy {
|
||||
ctx_ty: Option<Type>,
|
||||
dep: Option<Ident>,
|
||||
}
|
||||
|
||||
impl Parse for Dependancy {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
extern crate proc_macro;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use syn::{
|
||||
self, bracketed,
|
||||
parse::{Parse, ParseStream, Result},
|
||||
LitStr, Token,
|
||||
};
|
||||
pub struct StrSlice {
|
||||
pub map: BTreeMap<String, LitStr>,
|
||||
}
|
||||
|
||||
impl Parse for StrSlice {
|
||||
fn parse(input: ParseStream) -> Result<Self> {
|
||||
let content;
|
||||
bracketed!(content in input);
|
||||
let mut map = BTreeMap::new();
|
||||
while let Ok(s) = content.parse::<LitStr>() {
|
||||
map.insert(s.value(), s);
|
||||
#[allow(unused_must_use)]
|
||||
{
|
||||
content.parse::<Token![,]>();
|
||||
}
|
||||
}
|
||||
Ok(StrSlice { map })
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user