From 1870d6e65e227aa97b43d9b94a0d523fa3924696 Mon Sep 17 00:00:00 2001 From: Daniel Bulant Date: Wed, 1 Nov 2023 21:08:33 +0100 Subject: [PATCH] working reactivity in components --- mangades/src/component_demo_syntax.rs | 6 +- mangades/src/main.rs | 6 +- rusalka-macro/src/lib.rs | 137 ++++++++++++++++++++++++-- rusalka/src/nodes/primitives.rs | 1 - 4 files changed, 138 insertions(+), 12 deletions(-) diff --git a/mangades/src/component_demo_syntax.rs b/mangades/src/component_demo_syntax.rs index dd65d18..44f1f78 100644 --- a/mangades/src/component_demo_syntax.rs +++ b/mangades/src/component_demo_syntax.rs @@ -2,7 +2,7 @@ use rusalka_macro::make_component; use std::default::Default; use mangui::{SharedNode, nodes::Style, taffy::prelude::Size, femtovg::{Paint, Color}, nodes::layout::Layout}; -use rusalka::nodes::primitives::{Rectangle, RectangleAttributes}; +use rusalka::nodes::primitives::{Rectangle, RectangleAttributes, PartialRectangleAttributes}; make_component!( ComponentDemo, @@ -16,7 +16,7 @@ make_component!( test_: bool = false } Reactive { - dbg!($test_); + // dbg!($test_); } Component { @layout { @@ -28,11 +28,9 @@ make_component!( match event.event { mangui::events::InnerEvent::MouseDown(_) => { $test_ = true; - println!("Mouse down"); }, mangui::events::InnerEvent::MouseUp(_) => { $test_ = false; - println!("Mouse up"); }, _ => {} } diff --git a/mangades/src/main.rs b/mangades/src/main.rs index 9cc5f5a..2aaaa63 100644 --- a/mangades/src/main.rs +++ b/mangades/src/main.rs @@ -45,7 +45,11 @@ fn main() { })); let groot: SharedNode = Arc::new(RwLock::new(root)); - let cdemo: Arc> = Arc::new_cyclic(|cself| Mutex::new(component_demo_syntax::ComponentDemo::new(component_demo_syntax::ComponentDemoAttributes { radius: 10. }, cself.clone()))); + let cdemo: Arc> = Arc::new_cyclic(|cself| + Mutex::new(component_demo_syntax::ComponentDemo::new(component_demo_syntax::ComponentDemoAttributes { + radius: 15. + }, cself.clone())) + ); cdemo.lock().unwrap().mount(&groot, None); mangui::run_event_loop(MainEntry { diff --git a/rusalka-macro/src/lib.rs b/rusalka-macro/src/lib.rs index 0ce75af..0681f7c 100644 --- a/rusalka-macro/src/lib.rs +++ b/rusalka-macro/src/lib.rs @@ -39,13 +39,14 @@ struct ComponentUsed { parent: Option, component_type: ComponentType, event_listeners: Vec, - reactive_props: HashMap + reactive_props: HashMap } #[derive(Debug)] struct ReactiveBlock { variables: Vec, - contents: TokenStream + contents: TokenStream, + prop_ident: Option } #[proc_macro] @@ -202,7 +203,8 @@ pub fn make_component(item: TokenStream) -> TokenStream { let (variables, contents) = replace_variables(group.stream()); reactive_blocks.push(ReactiveBlock { variables, - contents + contents, + prop_ident: None }); }, "Component" => { @@ -606,8 +608,8 @@ pub fn make_component(item: TokenStream) -> TokenStream { set_stream_inner.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Bracket, to_update_stream)))); - set_stream_inner.extend(TokenStream::from(quote!(|= 1 <<))); - set_stream_inner.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(i % 32)))); + set_stream_inner.extend(TokenStream::from(quote!(|= ))); + set_stream_inner.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(1 << i % 32)))); set_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, set_stream_inner)))); @@ -807,6 +809,87 @@ pub fn make_component(item: TokenStream) -> TokenStream { update_stream.extend(Some(TokenTree::Group(inner_group))); } + let mut component_index = 0; + 'block: for component in &components_used { + for (prop, block) in &component.reactive_props { + let mut keys: Vec = vec![0; all_variables.len() / 32 + 1]; + for variable in &block.variables { + let index = all_variables.iter().position(|x| x.name.to_string() == variable.to_string()); + if let None = index { + eprintln!("Warning: variable {} not found in component {}", variable, name); + continue 'block; + } + let index = index.unwrap(); + let array_offset = index / 32; + let num_offset = index % 32; + *keys.get_mut(array_offset).unwrap() |= 1 << num_offset; + } + update_stream.extend(TokenStream::from(quote!(if))); + + let mut i = 0; + for key in keys { + if i > 0 { + update_stream.extend(TokenStream::from(quote!(||))); + } + update_stream.extend(TokenStream::from(quote!(bitmap))); + let mut ifgroup_stream = TokenStream::new(); + // update_stream.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(key)))); + ifgroup_stream.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(i)))); + update_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Bracket, ifgroup_stream)))); + update_stream.extend(TokenStream::from(quote!(&))); + update_stream.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(key)))); + update_stream.extend(TokenStream::from(quote!(!= 0))); + i += 1; + } + + let mut inner_stream = TokenStream::new(); + + match component.component_type { + ComponentType::Node => { + inner_stream.extend(TokenStream::from(quote!(self.))); + inner_stream.extend(Some(TokenTree::Ident(Ident::new(&format!("comp{}", component_index), Span::call_site())))); + inner_stream.extend(TokenStream::from(quote!(.write().unwrap().))); + inner_stream.extend(Some(TokenTree::Ident(block.prop_ident.clone().unwrap()))); + inner_stream.extend(TokenStream::from(quote!( = ))); + inner_stream.extend(replace_variables(block.contents.clone()).1); + }, + ComponentType::RealComponent => { + inner_stream.extend(TokenStream::from(quote!(self.))); + inner_stream.extend(Some(TokenTree::Ident(Ident::new(&format!("comp{}", component_index), Span::call_site())))); + inner_stream.extend(TokenStream::from(quote!(.lock().unwrap().set))); + + let mut component_set_stream = TokenStream::new(); + + component_set_stream.extend(Some(TokenTree::Ident(block.prop_ident.clone().unwrap()))); + component_set_stream.extend(TokenStream::from(quote!(: Option::Some))); + + let component_set_some_stream = replace_variables(block.contents.clone()).1; + + let mut component_set_group = Group::new(proc_macro::Delimiter::Parenthesis, component_set_some_stream); + component_set_stream.extend(Some(TokenTree::Group(component_set_group))); + + component_set_stream.extend(TokenStream::from(quote!(, ..Default::default()))); + + let component_set_group = Group::new(proc_macro::Delimiter::Brace, component_set_stream); + let mut component_set_outer_stream = TokenStream::new(); + + let name = component.name.clone().to_string(); + + component_set_outer_stream.extend(Some(TokenTree::Ident(Ident::new(&format!("Partial{}Attributes", name), Span::call_site())))); + + component_set_outer_stream.extend(Some(TokenTree::Group(component_set_group))); + let component_set_outer_group = Group::new(proc_macro::Delimiter::Parenthesis, component_set_outer_stream); + + inner_stream.extend(Some(TokenTree::Group(component_set_outer_group))); + } + } + + let inner_group = Group::new(proc_macro::Delimiter::Brace, inner_stream); + update_stream.extend(Some(TokenTree::Group(inner_group))); + } + component_index += 1; + } + let update_group = Group::new(proc_macro::Delimiter::Brace, update_stream); component_impl_stream.extend(Some(TokenTree::Group(update_group))); @@ -1051,12 +1134,54 @@ fn parse_components(name: Ident, group: Group, next: usize, parent: Option panic!("Expected group after |param|") }; - let this_component = components_found.get_mut(next).unwrap(); + let this_component = components_found.get_mut(0).unwrap(); this_component.event_listeners.push(EventListener { callback: fn_group, identifier: fn_param }); }, + TokenTree::Ident(ident) => { + let ident_str = ident.to_string(); + self_stream.extend(Some(TokenTree::Ident(ident.clone()))); + let nexttoken = group.next(); + match nexttoken { + None => {}, + Some(token) => match token { + TokenTree::Punct(punct) if punct.as_char() == ':' => { + self_stream.extend(Some(TokenTree::Punct(punct))); + // likely reactive property + let mut property_stream = TokenStream::new(); + while let Some(token) = group.next() { + match token { + TokenTree::Punct(punct) => { + let char = punct.as_char(); + property_stream.extend(Some(TokenTree::Punct(punct))); + if char == ',' { + break; + } + }, + _ => { + property_stream.extend(Some(token)); + } + } + } + let (reactive_variables, property_stream) = replace_variables(property_stream); + if reactive_variables.len() > 0 { + let this_component = components_found.get_mut(0).unwrap(); + this_component.reactive_props.insert(ident_str, ReactiveBlock { + variables: reactive_variables, + contents: property_stream.clone(), + prop_ident: Some(ident) + }); + } + self_stream.extend(property_stream); + }, + _ => { + self_stream.extend(Some(token)); + } + } + } + }, any => { // skip until next ',', writing to self_stream self_stream.extend(Some(any)); diff --git a/rusalka/src/nodes/primitives.rs b/rusalka/src/nodes/primitives.rs index 76d3ede..90cf17b 100644 --- a/rusalka/src/nodes/primitives.rs +++ b/rusalka/src/nodes/primitives.rs @@ -63,7 +63,6 @@ impl Component for Rectangle { let mut to_update = [0; Self::UPDATE_LENGTH]; if let Some(radius) = attrs.radius { self.attrs.radius = radius; - dbg!("Radius set", radius); to_update[0] |= 1; } if to_update.into_iter().reduce(|a,b| a+b).unwrap() != 0 {