switch to signals, start working on slots

This commit is contained in:
Daniel Bulant 2024-02-25 21:33:01 +01:00
parent 455fad5269
commit d3cc64375a
12 changed files with 619 additions and 516 deletions

85
Cargo.lock generated
View file

@ -163,9 +163,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.15.0"
version = "3.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f"
checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b"
[[package]]
name = "bytemuck"
@ -213,11 +213,10 @@ dependencies = [
[[package]]
name = "cc"
version = "1.0.83"
version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc"
dependencies = [
"jobserver",
"libc",
]
@ -858,9 +857,9 @@ checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "hermit-abi"
version = "0.3.6"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd"
checksum = "379dada1584ad501b383485dd706b8afb7a70fcbc7f4da7d780638a5a6124a60"
[[package]]
name = "http"
@ -1022,15 +1021,6 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "jobserver"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
dependencies = [
"libc",
]
[[package]]
name = "jpeg-decoder"
version = "0.3.1"
@ -1124,9 +1114,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "lru"
version = "0.12.2"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db2c024b41519440580066ba82aab04092b333e09066a5eb86c7c4890df31f22"
checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc"
[[package]]
name = "mangades"
@ -1362,9 +1352,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.100"
version = "0.9.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae94056a791d0e1217d18b6cbdccb02c61e3054fc69893607f4067e3bb0b1fd1"
checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff"
dependencies = [
"cc",
"libc",
@ -1640,6 +1630,7 @@ dependencies = [
name = "rusalka-macro"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
]
@ -1906,12 +1897,12 @@ dependencies = [
[[package]]
name = "socket2"
version = "0.5.5"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871"
dependencies = [
"libc",
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
@ -2558,7 +2549,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.0",
"windows-targets 0.52.3",
]
[[package]]
@ -2593,17 +2584,17 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.52.0"
version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f"
dependencies = [
"windows_aarch64_gnullvm 0.52.0",
"windows_aarch64_msvc 0.52.0",
"windows_i686_gnu 0.52.0",
"windows_i686_msvc 0.52.0",
"windows_x86_64_gnu 0.52.0",
"windows_x86_64_gnullvm 0.52.0",
"windows_x86_64_msvc 0.52.0",
"windows_aarch64_gnullvm 0.52.3",
"windows_aarch64_msvc 0.52.3",
"windows_i686_gnu 0.52.3",
"windows_i686_msvc 0.52.3",
"windows_x86_64_gnu 0.52.3",
"windows_x86_64_gnullvm 0.52.3",
"windows_x86_64_msvc 0.52.3",
]
[[package]]
@ -2620,9 +2611,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6"
[[package]]
name = "windows_aarch64_msvc"
@ -2638,9 +2629,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f"
[[package]]
name = "windows_i686_gnu"
@ -2656,9 +2647,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb"
[[package]]
name = "windows_i686_msvc"
@ -2674,9 +2665,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58"
[[package]]
name = "windows_x86_64_gnu"
@ -2692,9 +2683,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614"
[[package]]
name = "windows_x86_64_gnullvm"
@ -2710,9 +2701,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c"
[[package]]
name = "windows_x86_64_msvc"
@ -2728,9 +2719,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
version = "0.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6"
[[package]]
name = "winit"

View file

@ -5,12 +5,9 @@ use mangui::nodes::TaffyStyle;
use mangui::taffy::Display::Block;
use mangui::taffy::{FlexDirection, LengthPercentage, Rect};
use rusalka::nodes::primitives::{Rectangle, RectangleAttributes, PartialRectangleAttributes};
make_component!(
ComponentDemo,
MainLogic {
let _radius = attrs.radius;
let imgpath = std::path::PathBuf::from("./demo/large/bx117324-97mHyfJGwpBq.jpg");
let imgflags = ImageFlags::empty();
let width = 230.;
@ -23,13 +20,11 @@ make_component!(
test_: bool = false
}
Reactive {
// dbg!($test_);
println!("reactive block");
println!("test_ = {}", $test_);
}
Component {
@layout {
@Rectangle {
radius: if $test_ { attrs.radius } else { 0. }
}
@layout {
@text {
text: String::from("Hello, World 🌎! And there's more text in here, as a single line"),

View file

@ -4,6 +4,7 @@ use mangui::{self, nodes::layout::Layout, SharedNode, MainEntry};
mod component_demo_syntax;
mod anilist;
mod slot_demo;
use rusalka::component::Component;

266
mangades/src/slot_demo.rs Normal file
View file

@ -0,0 +1,266 @@
use std::sync::{Arc, Mutex, RwLock};
use mangui::nodes::layout::Layout;
use mangui::nodes::primitives::Rectangle;
use rusalka::component::Slot;
use rusalka::store::{DerefGuardExt, ReadableStore, Signal, StoreUnsubscribe, Writable, WritableStore};
pub struct SlotAcceptDemo {
comp0: rusalka::SharedNodeComponent<Layout>,
comp1: Mutex<Option<Slot>>,
selfref: rusalka::WeakSharedComponent<Self>,
attrs: ReactiveSlotAcceptDemoAttributes,
}
type SlotArgs = ();
type DSlot = Option<Mutex<Box<dyn FnMut(SlotArgs) -> Slot>>>;
#[derive(Default)]
pub struct SlotAcceptDemoAttributes {
pub __default_slot: DSlot
}
pub struct ReactiveSlotAcceptDemoAttributes {
__default_slot: DSlot
}
#[derive(Default)]
pub struct PartialSlotAcceptDemoAttributes {
pub __default_slot: Option<DSlot>
}
impl From<SlotAcceptDemoAttributes> for PartialSlotAcceptDemoAttributes {
fn from(attrs: SlotAcceptDemoAttributes) -> Self {
Self { __default_slot: Some(attrs.__default_slot) }
}
}
impl From<SlotAcceptDemoAttributes> for ReactiveSlotAcceptDemoAttributes {
fn from(attrs: SlotAcceptDemoAttributes) -> Self {
Self { __default_slot: attrs.__default_slot }
}
}
impl rusalka::component::Component for SlotAcceptDemo {
type ComponentAttrs = SlotAcceptDemoAttributes;
type ReactiveComponentAttrs = ReactiveSlotAcceptDemoAttributes;
type PartialComponentAttrs = PartialSlotAcceptDemoAttributes;
const UPDATE_LENGTH: usize = 1;
fn new(
attrs: Self::ComponentAttrs,
selfref: rusalka::WeakSharedComponent<Self>,
) -> Self {
let this = Self {
comp0: std::sync::Arc::new(
std::sync::RwLock::new(Layout { ..Default::default() }),
),
comp1: Mutex::new(None),
attrs: attrs.into(),
selfref
};
this
}
fn set(&mut self, attrs: Self::PartialComponentAttrs) {
}
fn get(&self) -> &Self::ReactiveComponentAttrs {
&self.attrs
}
fn mount(
&self,
parent: &mangui::SharedNode,
before: Option<&mangui::SharedNode>,
) {
rusalka::nodes::insert(parent, &{ self.comp0.clone() }, before);
match &self.attrs.__default_slot {
Some(slot) => {
*self.comp1.lock().unwrap() = Some(slot.lock().unwrap()(()));
(*self.comp1.lock().unwrap().as_mut().unwrap().mount)(parent, before);
}
None => {}
}
}
fn unmount(&self) {
rusalka::nodes::detach(&{ self.comp0.clone() });
match &self.attrs.__default_slot {
Some(slot) => {
(*self.comp1.lock().unwrap().as_mut().unwrap().unmount)();
*self.comp1.lock().unwrap() = None;
}
None => {}
}
}
}
struct SlotDemoSlot1 {
comp0: rusalka::SharedNodeComponent<Rectangle>,
sub0: Box<dyn StoreUnsubscribe>
}
pub struct SlotDemo {
comp0: rusalka::SharedNodeComponent<Layout>,
comp1: rusalka::SharedComponent<SlotAcceptDemo>,
test_: std::sync::Arc<std::sync::Mutex<rusalka::store::Writable<bool>>>,
sub0: Box<dyn StoreUnsubscribe>,
selfref: rusalka::WeakSharedComponent<Self>,
attrs: ReactiveSlotDemoAttributes,
}
#[derive(Default)]
pub struct SlotDemoAttributes {
pub test: f32
}
pub struct ReactiveSlotDemoAttributes {
pub test: Arc<Mutex<Writable<f32>>>
}
#[derive(Default)]
pub struct PartialSlotDemoAttributes {
pub test: Option<f32>
}
impl From<SlotDemoAttributes> for PartialSlotDemoAttributes {
fn from(attrs: SlotDemoAttributes) -> Self {
Self { test: Some(attrs.test) }
}
}
impl From<ReactiveSlotDemoAttributes> for SlotDemoAttributes {
fn from(attrs: ReactiveSlotDemoAttributes) -> Self {
Self { test: *attrs.test.lock().unwrap().get() }
}
}
impl From<&ReactiveSlotDemoAttributes> for SlotDemoAttributes {
fn from(attrs: &ReactiveSlotDemoAttributes) -> Self {
Self { test: *attrs.test.lock().unwrap().get() }
}
}
impl From<SlotDemoAttributes> for ReactiveSlotDemoAttributes {
fn from(attrs: SlotDemoAttributes) -> Self {
Self { test: Arc::new(Mutex::new(Writable::new(attrs.test))) }
}
}
impl rusalka::component::Component for SlotDemo {
type ComponentAttrs = SlotDemoAttributes;
type ReactiveComponentAttrs = ReactiveSlotDemoAttributes;
type PartialComponentAttrs = PartialSlotDemoAttributes;
const UPDATE_LENGTH: usize = 1;
fn new(
attrs: Self::ComponentAttrs,
selfref: rusalka::WeakSharedComponent<Self>,
) -> Self {
let attrs: Self::ReactiveComponentAttrs = attrs.into();
let test_: std::sync::Arc<
std::sync::Mutex<rusalka::store::Writable<bool>>,
> = std::sync::Arc::new(
std::sync::Mutex::new(rusalka::store::Writable::new(false)),
);
let test = attrs.test.clone();
let this = Self {
comp0: std::sync::Arc::new(
std::sync::RwLock::new(Layout { ..Default::default() }),
),
comp1: std::sync::Arc::new_cyclic(|cselfref2| std::sync::Mutex::new(
SlotAcceptDemo::new(
SlotAcceptDemoAttributes {
__default_slot: Some(Mutex::new(Box::new(move |_| {
let comp0: Arc<Mutex<Option<SlotDemoSlot1>>> = Arc::new(Mutex::new(None));
Slot {
mount: {
let comp0 = comp0.clone();
let test = test.clone();
Box::new(move |parent, before| {
if let None = comp0.lock().unwrap().as_ref() {
let slot = Some(
SlotDemoSlot1 {
comp0: std::sync::Arc::new(
std::sync::RwLock::new(Rectangle { radius: *test.clone().lock().unwrap().get(), ..Default::default() }),
),
sub0: {
let comp0 = comp0.clone();
let test = test.clone();
[test.clone().lock().unwrap()].subscribe(Box::new(move || {
let comp1 = comp0.clone();
let test1 = test.clone();
let mut comp1l = comp1.lock().unwrap();
if let Some(comp1) = comp1l.as_mut() {
comp1.comp0.write().unwrap().radius = *test1.lock().unwrap().get();
}
}))
},
}
);
*comp0.lock().unwrap() = slot;
}
rusalka::nodes::insert(parent, &{ comp0.lock().as_ref().unwrap().as_ref().unwrap().comp0.clone() }, before);
})
},
unmount: {
let comp0 = comp0.clone();
Box::new(move || {
let comp0 = comp0.clone();
if let Some(comp0) = comp0.lock().unwrap().as_mut() {
rusalka::nodes::detach(&{ comp0.comp0.clone() });
}
*comp0.lock().unwrap() = None;
})
},
}
})))
},
cselfref2.clone(),
),
)),
sub0: {
let test = test_.clone();
[test.clone().lock().unwrap()].subscribe(Box::new(move || {
let test = test.clone();
dbg!(test.lock().unwrap().get());
}))
},
attrs,
selfref,
test_
};
let selfref = this.selfref.clone();
this.comp0
.write()
.unwrap()
.events
.add_handler(
Box::new(move |event| {
let selfref = selfref.upgrade().unwrap();
let mut this = selfref.lock().unwrap();
let attrs = &this.attrs;
let test_ = &this.test_;
match event.event {
mangui::events::InnerEvent::MouseDown(_) => {
**test_.lock().unwrap().guard() = true;
}
mangui::events::InnerEvent::MouseUp(_) => {
**test_.lock().unwrap().guard() = false;
}
_ => {}
}
}),
);
this
}
fn set(&mut self, attrs: Self::PartialComponentAttrs) {
if let Some(test) = attrs.test {
**self.attrs.test.lock().unwrap().guard() = test;
// self.attrs.test.lock().unwrap().set(test);
}
}
fn get(&self) -> &Self::ReactiveComponentAttrs {
&self.attrs
}
fn mount(
&self,
parent: &mangui::SharedNode,
before: Option<&mangui::SharedNode>,
) {
rusalka::nodes::insert(parent, &{ self.comp0.clone() }, before);
}
fn unmount(&self) {
rusalka::nodes::detach(&{ self.comp0.clone() });
}
}

View file

@ -8,6 +8,7 @@ authors.workspace = true
[dependencies]
quote = "1.0"
proc-macro2 = "1.0.78"
[lib]
proc-macro = true

View file

@ -1,7 +1,7 @@
use proc_macro2::{Ident, TokenStream, TokenTree, Span, Group, Delimiter};
use std::collections::HashMap;
use proc_macro::{TokenStream, TokenTree, Ident, Group, Span, Literal};
use quote::quote;
use quote::{format_ident, quote, ToTokens};
#[derive(Debug, Clone)]
struct Attribute {
@ -51,7 +51,8 @@ struct ReactiveBlock {
#[proc_macro]
/// If you have syntax errors because of attributes, wrap the default value in parentheses.
pub fn make_component(item: TokenStream) -> TokenStream {
pub fn make_component(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
let item = TokenStream::from(item);
let mut last_identifier = None;
let mut item = item.into_iter();
let name = item.next().unwrap();
@ -201,11 +202,13 @@ pub fn make_component(item: TokenStream) -> TokenStream {
},
"Reactive" => {
let (variables, contents) = replace_variables(group.stream());
reactive_blocks.push(ReactiveBlock {
variables,
contents,
prop_ident: None
});
if !contents.is_empty() && !variables.is_empty() {
reactive_blocks.push(ReactiveBlock {
variables,
contents,
prop_ident: None
});
}
},
"Component" => {
// Example syntax:
@ -268,25 +271,28 @@ pub fn make_component(item: TokenStream) -> TokenStream {
let mut output = TokenStream::new();
// Component struct
output.extend(quote!(
use rusalka::store::DerefGuardExt;
use rusalka::store::WritableStore;
use rusalka::store::Signal;
));
output.extend(TokenStream::from(quote!(pub struct)));
output.extend(quote!(pub struct));
output.extend(Some(TokenTree::Ident(name_ident.clone())));
let mut component_struct_stream = TokenStream::new();
let mut i = 0;
for component in &components_used {
for (i, component) in components_used.iter().enumerate() {
let ident = Ident::new(&format!("comp{}", i), component.name.span());
let mut midstream = TokenStream::from(quote!(: rusalka::));
let mut midstream = quote!(: rusalka::);
match component.component_type {
ComponentType::RealComponent => {
midstream.extend(TokenStream::from(quote!(SharedComponent<)));
midstream.extend(quote!(SharedComponent<));
},
ComponentType::Node => {
midstream.extend(TokenStream::from(quote!(SharedNodeComponent<)));
midstream.extend(quote!(SharedNodeComponent<));
}
}
@ -295,15 +301,22 @@ pub fn make_component(item: TokenStream) -> TokenStream {
component_struct_stream.extend(Some(TokenTree::Ident(ident)));
component_struct_stream.extend(midstream);
component_struct_stream.extend(Some(TokenTree::Ident(component_name)));
component_struct_stream.extend(TokenStream::from(quote!(>,)));
component_struct_stream.extend(quote!(>,));
}
let mut i = 0u32;
for block in &reactive_blocks {
let ident = format_ident!("sub{}", i);
component_struct_stream.extend(quote!(
#ident: Box<dyn rusalka::store::StoreUnsubscribe>,
));
i+=1;
}
for variable in &reactive_variables {
component_struct_stream.extend(Some(TokenTree::Ident(variable.name.clone())));
component_struct_stream.extend(TokenStream::from(quote!(:)));
component_struct_stream.extend(TokenStream::from(quote!(std::sync::Arc<std::sync::Mutex<rusalka::invalidator::Invalidator<)));
component_struct_stream.extend(TokenStream::from(quote!(std::sync::Arc<std::sync::Mutex<rusalka::store::Writable<)));
component_struct_stream.extend(variable.type_.clone());
component_struct_stream.extend(TokenStream::from(quote!(>>>)));
component_struct_stream.extend(TokenStream::from(quote!(,)));
@ -316,11 +329,13 @@ pub fn make_component(item: TokenStream) -> TokenStream {
// Attributes struct
let attributes_ident = Ident::new(&format!("{str_name}Attributes"), name_ident.span());
let partial_attributes_ident = Ident::new(&format!("Partial{str_name}Attributes"), name_ident.span());
let reactive_attributes_ident = Ident::new(&format!("Reactive{str_name}Attributes"), name_ident.span());
component_struct_stream.extend(TokenStream::from(quote!(attrs: )));
component_struct_stream.extend(Some(TokenTree::Ident(attributes_ident.clone())));
component_struct_stream.extend(Some(TokenTree::Ident(reactive_attributes_ident.clone())));
let component_struct_group = Group::new(proc_macro::Delimiter::Brace, component_struct_stream);
let component_struct_group = Group::new(proc_macro2::Delimiter::Brace, component_struct_stream);
output.extend(Some(TokenTree::Group(component_struct_group)));
@ -338,11 +353,10 @@ pub fn make_component(item: TokenStream) -> TokenStream {
attributes_struct_stream.extend(TokenStream::from(quote!(,)));
}
output.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, attributes_struct_stream))));
output.extend(Some(TokenTree::Group(Group::new(proc_macro2::Delimiter::Brace, attributes_struct_stream))));
// partial attributes
let partial_attributes_ident = Ident::new(&format!("Partial{str_name}Attributes"), name_ident.span());
output.extend(TokenStream::from(quote!(#[derive(Default)] pub struct)));
output.extend(Some(TokenTree::Ident(partial_attributes_ident.clone())));
let mut attributes_default_struct_stream = TokenStream::new();
@ -355,7 +369,23 @@ pub fn make_component(item: TokenStream) -> TokenStream {
attributes_default_struct_stream.extend(TokenStream::from(quote!(>,)));
}
output.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, attributes_default_struct_stream))));
output.extend(Some(TokenTree::Group(Group::new(proc_macro2::Delimiter::Brace, attributes_default_struct_stream))));
// reactive attributes
output.extend(TokenStream::from(quote!(#[derive(Default)] pub struct)));
output.extend(Some(TokenTree::Ident(reactive_attributes_ident.clone())));
let mut attributes_default_struct_stream = TokenStream::new();
for attribute in &attributes {
attributes_default_struct_stream.extend(TokenStream::from(quote!(pub)));
attributes_default_struct_stream.extend(Some(TokenTree::Ident(attribute.name.clone())));
attributes_default_struct_stream.extend(TokenStream::from(quote!(: std::sync::Arc<std::sync::Mutex<rusalka::store::Writable<)));
attributes_default_struct_stream.extend(attribute.type_.clone());
attributes_default_struct_stream.extend(TokenStream::from(quote!(>>>,)));
}
output.extend(Some(TokenTree::Group(Group::new(proc_macro2::Delimiter::Brace, attributes_default_struct_stream))));
// impl From<Attributes> for PartialAttributes
@ -371,7 +401,7 @@ pub fn make_component(item: TokenStream) -> TokenStream {
let mut from_args = TokenStream::new();
from_args.extend(TokenStream::from(quote!(attrs:)));
from_args.extend(Some(TokenTree::Ident(attributes_ident.clone())));
from_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Parenthesis, from_args))));
from_stream.extend(Some(TokenTree::Group(Group::new(proc_macro2::Delimiter::Parenthesis, from_args))));
from_stream.extend(TokenStream::from(quote!(-> Self)));
let mut from_fn_stream = TokenStream::from(quote!(Self));
@ -388,57 +418,91 @@ pub fn make_component(item: TokenStream) -> TokenStream {
from_fn_stream_inner_inner.extend(TokenStream::from(quote!(attrs.)));
from_fn_stream_inner_inner.extend(Some(TokenTree::Ident(attribute.name.clone())));
from_fn_stream_inner.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Parenthesis, from_fn_stream_inner_inner))));
from_fn_stream_inner.extend(Some(TokenTree::Group(Group::new(Delimiter::Parenthesis, from_fn_stream_inner_inner))));
}
from_fn_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, from_fn_stream_inner))));
from_fn_stream.extend(Some(TokenTree::Group(Group::new(Delimiter::Brace, from_fn_stream_inner))));
from_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, from_fn_stream))));
output.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, from_stream))));
from_stream.extend(Some(TokenTree::Group(Group::new(Delimiter::Brace, from_fn_stream))));
output.extend(Some(TokenTree::Group(Group::new(Delimiter::Brace, from_stream))));
// impl From<Attributes> for ReactiveAttributes
output.extend(TokenStream::from(quote!(impl From<)));
output.extend(Some(TokenTree::Ident(attributes_ident.clone())));
output.extend(TokenStream::from(quote!(> for)));
output.extend(Some(TokenTree::Ident(reactive_attributes_ident.clone())));
let mut from_stream = TokenStream::new();
from_stream.extend(TokenStream::from(quote!(fn from)));
let mut from_args = TokenStream::new();
from_args.extend(TokenStream::from(quote!(attrs:)));
from_args.extend(Some(TokenTree::Ident(attributes_ident.clone())));
from_stream.extend(Some(TokenTree::Group(Group::new(Delimiter::Parenthesis, from_args))));
from_stream.extend(TokenStream::from(quote!(-> Self)));
let mut from_fn_stream = TokenStream::from(quote!(Self));
let mut from_fn_stream_inner = TokenStream::new();
for attribute in &attributes {
let name = attribute.name.clone();
from_fn_stream_inner.extend(TokenStream::from(quote!(
#name : std::sync::Arc::new(std::sync::Mutex::new(rusalka::store::Writable::new(attrs.#name)))
)));
}
from_fn_stream.extend(Some(TokenTree::Group(Group::new(Delimiter::Brace, from_fn_stream_inner))));
from_stream.extend(Some(TokenTree::Group(Group::new(Delimiter::Brace, from_fn_stream))));
output.extend(Some(TokenTree::Group(Group::new(Delimiter::Brace, from_stream))));
// Component impl
output.extend(TokenStream::from(quote!(impl rusalka::component::Component for)));
output.extend(Some(TokenTree::Ident(name_ident.clone())));
output.extend(TokenStream::from(quote!(impl rusalka::component::Component for #name_ident)));
let mut component_impl_stream = TokenStream::new();
component_impl_stream.extend(TokenStream::from(quote!(type ComponentAttrs =)));
component_impl_stream.extend(Some(TokenTree::Ident(attributes_ident.clone())));
component_impl_stream.extend(TokenStream::from(quote!(;)));
component_impl_stream.extend(TokenStream::from(quote!(type PartialComponentAttrs =)));
component_impl_stream.extend(Some(TokenTree::Ident(partial_attributes_ident.clone())));
component_impl_stream.extend(TokenStream::from(quote!(;)));
component_impl_stream.extend(TokenStream::from(quote!(const UPDATE_LENGTH : usize =)));
component_impl_stream.extend(Some(TokenTree::Literal(Literal::usize_unsuffixed(f64::ceil((attributes.len() + reactive_variables.len()) as f64 / 32 as f64) as usize))));
component_impl_stream.extend(TokenStream::from(quote!(;)));
component_impl_stream.extend(TokenStream::from(quote!(
type ComponentAttrs = #attributes_ident;
type PartialComponentAttrs = #partial_attributes_ident;
type ReactiveComponentAttrs = #reactive_attributes_ident;
)));
// fn new
component_impl_stream.extend(TokenStream::from(quote!(fn new(attrs: Self::ComponentAttrs, selfref: rusalka::WeakSharedComponent<Self>) -> Self)));
component_impl_stream.extend(TokenStream::from(quote!(
fn new(attrs: Self::ComponentAttrs, selfref: rusalka::WeakSharedComponent<Self>) -> Self
)));
let mut new_stream = TokenStream::new();
for variable in &reactive_variables {
new_stream.extend(TokenStream::from(quote!(let)));
new_stream.extend(Some(TokenTree::Ident(variable.name.clone())));
new_stream.extend(TokenStream::from(quote!(:)));
new_stream.extend(TokenStream::from(quote!(std::sync::Arc<std::sync::Mutex<rusalka::invalidator::Invalidator<)));
new_stream.extend(variable.type_.clone());
new_stream.extend(TokenStream::from(quote!(>>>)));
new_stream.extend(TokenStream::from(quote!(=)));
new_stream.extend(TokenStream::from(quote!(
let attrs: Self::ReactiveComponentAttrs = attrs.into();
)));
let mut invalidator = TokenStream::from(quote!(rusalka::invalidator::Invalidator::new));
for attribute in &attributes {
let name = attribute.name.clone();
new_stream.extend(TokenStream::from(quote!(
let #name = attrs.#name.clone();
)));
}
for variable in &reactive_variables {
let name = variable.name.clone();
let type_ = variable.type_.clone();
let mut invalidator_inner = TokenStream::new();
if let Some(def) = &variable.default {
invalidator_inner.extend(replace_variables(def.clone()).1);
} else {
invalidator_inner.extend(TokenStream::from(quote!(Default::default())));
}
invalidator.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Parenthesis, invalidator_inner))));
new_stream.extend(wrap_in_arc_mutex(invalidator));
new_stream.extend(TokenStream::from(quote!(;)));
new_stream.extend(TokenStream::from(quote!(
let #name : std::sync::Arc<std::sync::Mutex<rusalka::store::Writable< #type_ >>> =
std::sync::Arc::new(std::sync::Mutex::new(rusalka::store::Writable::new( #invalidator_inner )));
)));
}
new_stream.extend(main_logic);
@ -466,20 +530,20 @@ pub fn make_component(item: TokenStream) -> TokenStream {
let mut component_new_stream = TokenStream::new();
// The following would allow not importing ComponentAttributes, but rust doesn't support it outside of nightly just yet
// component_new_stream.extend(Some(TokenTree::Punct(Punct::new('<', proc_macro::Spacing::Alone))));
// component_new_stream.extend(Some(TokenTree::Punct(Punct::new('<', Spacing::Alone))));
// component_new_stream.extend(Some(TokenTree::Ident(component_name.clone())));
// component_new_stream.extend(TokenStream::from(quote!(as Component>::ComponentAttrs)));
component_new_stream.extend(Some(TokenTree::Ident(Ident::new(&format!("{}Attributes", component_name), component_name.span()))));
let (_reactive_variables, subcomponent_stream) = replace_variables(component.contents.clone());
let components_attributes_group = Group::new(proc_macro::Delimiter::Brace, subcomponent_stream);
let components_attributes_group = Group::new(Delimiter::Brace, subcomponent_stream);
component_new_stream.extend(Some(TokenTree::Group(components_attributes_group)));
component_new_stream.extend(TokenStream::from(quote!(, cselfref.clone())));
let component_new_group = Group::new(proc_macro::Delimiter::Parenthesis, component_new_stream);
let component_new_group = Group::new(Delimiter::Parenthesis, component_new_stream);
component_stream.extend(Some(TokenTree::Group(component_new_group)));
@ -487,27 +551,44 @@ pub fn make_component(item: TokenStream) -> TokenStream {
},
ComponentType::Node => {
let (_reactive_variables, subcomponent_stream) = replace_variables(component.contents.clone());
let node_group = Group::new(proc_macro::Delimiter::Brace, subcomponent_stream);
let node_group = Group::new(Delimiter::Brace, subcomponent_stream);
component_stream.extend(Some(TokenTree::Group(node_group)));
new_returnvalue_stream.extend(wrap_in_arcrwlock(component_stream));
}
}
new_returnvalue_stream.extend(TokenStream::from(quote!(,)));
new_returnvalue_stream.extend(quote!(,));
i+=1;
}
new_returnvalue_stream.extend(TokenStream::from(quote!(attrs, selfref,)));
new_returnvalue_stream.extend(quote!(attrs, selfref,));
let mut i = 0u32;
for reactive_block in &reactive_blocks {
let ident = format_ident!("sub{}", i);
let content = &reactive_block.contents;
let variables = &reactive_block.variables;
new_returnvalue_stream.extend(quote!(
#ident: {
#(let #variables = #variables.clone();)*
[#(#variables.clone().lock().unwrap()),*].subscribe(Box::new(move || {
#(let #variables = #variables.clone();)*
#content
}))
},
));
i+=1;
}
for variable in &reactive_variables {
new_returnvalue_stream.extend(Some(TokenTree::Ident(variable.name.clone())));
new_returnvalue_stream.extend(TokenStream::from(quote!(,)));
new_returnvalue_stream.extend(quote!(,));
}
let new_returnvalue_group = Group::new(proc_macro::Delimiter::Brace, new_returnvalue_stream);
let new_returnvalue_group = Group::new(Delimiter::Brace, new_returnvalue_stream);
new_stream.extend(Some(TokenTree::Group(new_returnvalue_group)));
new_stream.extend(TokenStream::from(quote!(;)));
new_stream.extend(quote!(;));
i = 0;
for component in &components_used {
@ -551,17 +632,15 @@ pub fn make_component(item: TokenStream) -> TokenStream {
inner_callback_stream.extend(replace_variables(event_listener.callback.clone().stream()).1);
inner_callback_stream.extend(TokenStream::from(quote!(this.tick(None);)));
let callback_group = Group::new(proc_macro::Delimiter::Brace, inner_callback_stream);
let callback_group = Group::new(Delimiter::Brace, inner_callback_stream);
callback_stream.extend(Some(TokenTree::Group(callback_group)));
let callback_group = Group::new(proc_macro::Delimiter::Parenthesis, callback_stream);
let callback_group = Group::new(Delimiter::Parenthesis, callback_stream);
box_stream.extend(Some(TokenTree::Group(callback_group)));
let box_group = Group::new(proc_macro::Delimiter::Parenthesis, box_stream);
let box_group = Group::new(Delimiter::Parenthesis, box_stream);
new_stream.extend(Some(TokenTree::Group(box_group)));
@ -572,7 +651,7 @@ pub fn make_component(item: TokenStream) -> TokenStream {
new_stream.extend(TokenStream::from(quote!(this)));
let new_group = Group::new(proc_macro::Delimiter::Brace, new_stream);
let new_group = Group::new(Delimiter::Brace, new_stream);
component_impl_stream.extend(Some(TokenTree::Group(new_group)));
// fn set
@ -581,14 +660,13 @@ pub fn make_component(item: TokenStream) -> TokenStream {
let mut set_stream = TokenStream::new();
if attributes.len() > 0 {
set_stream.extend(TokenStream::from(quote!(let mut to_update = [0; Self::UPDATE_LENGTH];)));
for (i, attribute) in attributes.iter().enumerate() {
set_stream.extend(TokenStream::from(quote!(if let Some)));
let mut some_inner = TokenStream::new();
some_inner.extend(Some(TokenTree::Ident(attribute.name.clone())));
set_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Parenthesis, some_inner))));
set_stream.extend(Some(TokenTree::Group(Group::new(Delimiter::Parenthesis, some_inner))));
set_stream.extend(TokenStream::from(quote!(= attrs.)));
set_stream.extend(Some(TokenTree::Ident(attribute.name.clone())));
@ -597,31 +675,25 @@ pub fn make_component(item: TokenStream) -> TokenStream {
set_stream_inner.extend(TokenStream::from(quote!(self.attrs.)));
set_stream_inner.extend(Some(TokenTree::Ident(attribute.name.clone())));
set_stream_inner.extend(TokenStream::from(quote!(=)));
set_stream_inner.extend(Some(TokenTree::Ident(attribute.name.clone())));
set_stream_inner.extend(TokenStream::from(quote!(; to_update)));
set_stream_inner.extend(TokenStream::from(quote!(.lock().unwrap().set)));
let mut to_update_stream = TokenStream::new();
let mut set_stream_inner_inner = TokenStream::new();
to_update_stream.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(i as u32 / 32))));
set_stream_inner_inner.extend(Some(TokenTree::Ident(attribute.name.clone())));
set_stream_inner.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Bracket, to_update_stream))));
set_stream_inner.extend(Some(TokenTree::Group(Group::new(Delimiter::Parenthesis, set_stream_inner_inner))));
set_stream_inner.extend(TokenStream::from(quote!(;)));
set_stream_inner.extend(TokenStream::from(quote!(|= )));
set_stream_inner.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(1 << (i as u32 % 32)))));
set_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, set_stream_inner))));
set_stream.extend(Some(TokenTree::Group(Group::new(Delimiter::Brace, set_stream_inner))));
}
set_stream.extend(TokenStream::from(quote!(if to_update.into_iter().reduce(|a,b| a+b).unwrap() != 0 { self.tick(Some(&to_update)); })));
}
component_impl_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, set_stream))));
component_impl_stream.extend(Some(TokenTree::Group(Group::new(Delimiter::Brace, set_stream))));
// fn get
component_impl_stream.extend(TokenStream::from(quote!(fn get(&self) -> &Self::ComponentAttrs { &self.attrs })));
component_impl_stream.extend(TokenStream::from(quote!(fn get(&self) -> &Self::ReactiveComponentAttrs { &self.attrs })));
// fn mount
@ -652,7 +724,7 @@ pub fn make_component(item: TokenStream) -> TokenStream {
node_insert_self_stream.extend(Some(TokenTree::Ident(parent_ident)));
node_insert_self_stream.extend(TokenStream::from(quote!(.clone())));
let node_insert_self_group = Group::new(proc_macro::Delimiter::Brace, node_insert_self_stream);
let node_insert_self_group = Group::new(Delimiter::Brace, node_insert_self_stream);
component_mount_stream.extend(TokenStream::from(quote!(&)));
component_mount_stream.extend(Some(TokenTree::Group(node_insert_self_group)));
},
@ -663,7 +735,7 @@ pub fn make_component(item: TokenStream) -> TokenStream {
component_mount_stream.extend(TokenStream::from(quote!(,)));
component_mount_stream.extend(TokenStream::from(quote!(before)));
let component_mount_group = Group::new(proc_macro::Delimiter::Parenthesis, component_mount_stream);
let component_mount_group = Group::new(Delimiter::Parenthesis, component_mount_stream);
mount_stream.extend(Some(TokenTree::Group(component_mount_group)));
@ -686,7 +758,7 @@ pub fn make_component(item: TokenStream) -> TokenStream {
node_insert_self_stream.extend(Some(TokenTree::Ident(parent_ident)));
node_insert_self_stream.extend(TokenStream::from(quote!(.clone())));
let node_insert_self_group = Group::new(proc_macro::Delimiter::Brace, node_insert_self_stream);
let node_insert_self_group = Group::new(Delimiter::Brace, node_insert_self_stream);
node_insert_stream.extend(TokenStream::from(quote!(&)));
node_insert_stream.extend(Some(TokenTree::Group(node_insert_self_group)));
},
@ -704,13 +776,13 @@ pub fn make_component(item: TokenStream) -> TokenStream {
node_insert_self_stream.extend(Some(TokenTree::Ident(ident)));
node_insert_self_stream.extend(TokenStream::from(quote!(.clone())));
let node_insert_self_group = Group::new(proc_macro::Delimiter::Brace, node_insert_self_stream);
let node_insert_self_group = Group::new(Delimiter::Brace, node_insert_self_stream);
node_insert_stream.extend(Some(TokenTree::Group(node_insert_self_group)));
node_insert_stream.extend(TokenStream::from(quote!(,)));
node_insert_stream.extend(TokenStream::from(quote!(before)));
node_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Parenthesis, node_insert_stream))));
node_stream.extend(Some(TokenTree::Group(Group::new(Delimiter::Parenthesis, node_insert_stream))));
mount_stream.extend(node_stream);
mount_stream.extend(TokenStream::from(quote!(;)));
@ -719,7 +791,7 @@ pub fn make_component(item: TokenStream) -> TokenStream {
}
let mount_group = Group::new(proc_macro::Delimiter::Brace, mount_stream);
let mount_group = Group::new(Delimiter::Brace, mount_stream);
component_impl_stream.extend(Some(TokenTree::Group(mount_group)));
// fn unmount
@ -755,219 +827,29 @@ pub fn make_component(item: TokenStream) -> TokenStream {
node_detach_self_stream.extend(Some(TokenTree::Ident(ident)));
node_detach_self_stream.extend(TokenStream::from(quote!(.clone())));
let node_detach_self_group = Group::new(proc_macro::Delimiter::Brace, node_detach_self_stream);
let node_detach_self_group = Group::new(Delimiter::Brace, node_detach_self_stream);
node_detach_stream.extend(Some(TokenTree::Group(node_detach_self_group)));
let node_detach_group = Group::new(proc_macro::Delimiter::Parenthesis, node_detach_stream);
let node_detach_group = Group::new(Delimiter::Parenthesis, node_detach_stream);
unmount_stream.extend(Some(TokenTree::Group(node_detach_group)));
unmount_stream.extend(TokenStream::from(quote!(;)));
}
}
}
let unmount_group = Group::new(proc_macro::Delimiter::Brace, unmount_stream);
let unmount_group = Group::new(Delimiter::Brace, unmount_stream);
component_impl_stream.extend(Some(TokenTree::Group(unmount_group)));
// fn update
let mut all_variables = Vec::new();
all_variables.extend(attributes.clone());
all_variables.extend(reactive_variables.clone());
component_impl_stream.extend(TokenStream::from(quote!(fn update(&self, bitmap: &[u32]))));
let mut update_stream = TokenStream::new();
update_stream.extend(TokenStream::from(quote!(
self.check_update(bitmap);
let attrs = &self.attrs;
)));
for variable in &reactive_variables {
update_stream.extend(TokenStream::from(quote!(let)));
update_stream.extend(Some(TokenTree::Ident(variable.name.clone())));
update_stream.extend(TokenStream::from(quote!(=)));
update_stream.extend(TokenStream::from(quote!(&self.)));
update_stream.extend(Some(TokenTree::Ident(variable.name.clone())));
update_stream.extend(TokenStream::from(quote!(;)));
}
'block: for block in &reactive_blocks {
let mut keys: Vec<u32> = 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, str_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;
}
if keys.iter().all(|x| *x == 0) {
continue 'block;
}
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 inner_group = Group::new(proc_macro::Delimiter::Brace, block.contents.clone());
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<u32> = 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, str_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 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), component.name.span()))));
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)));
// fn tick
component_impl_stream.extend(TokenStream::from(quote!(fn tick(&mut self, inbitmap: Option<&[u32]>))));
let mut tick_stream = TokenStream::new();
tick_stream.extend(TokenStream::from(quote!(
let mut bitmap = [0; Self::UPDATE_LENGTH];
if let Some(inbitmap) = inbitmap {
bitmap.clone_from_slice(inbitmap);
}
self.check_update(&bitmap);
)));
let mut i = attributes.len() as u32;
for variable in &reactive_variables {
tick_stream.extend(TokenStream::from(quote!(if self.)));
tick_stream.extend(Some(TokenTree::Ident(variable.name.clone())));
tick_stream.extend(TokenStream::from(quote!(.lock().unwrap().invalidated())));
let mut if_stream = TokenStream::new();
let array_offset = i / 32;
let num_offset = i % 32;
if_stream.extend(TokenStream::from(quote!(bitmap)));
let mut ifgroup_stream = TokenStream::new();
ifgroup_stream.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(array_offset))));
if_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Bracket, ifgroup_stream))));
if_stream.extend(TokenStream::from(quote!(|= )));
if_stream.extend(Some(TokenTree::Literal(Literal::u32_unsuffixed(1 << num_offset))));
tick_stream.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, if_stream))));
i += 1;
}
tick_stream.extend(TokenStream::from(quote!(
if bitmap.into_iter().reduce(|a, b| a + b).unwrap() != 0 {
self.update(&bitmap);
}
)));
let tick_group = Group::new(proc_macro::Delimiter::Brace, tick_stream);
component_impl_stream.extend(Some(TokenTree::Group(tick_group)));
output.extend(Some(TokenTree::Group(Group::new(proc_macro::Delimiter::Brace, component_impl_stream))));
output.extend(Some(TokenTree::Group(Group::new(Delimiter::Brace, component_impl_stream))));
println!("{}", output.to_string());
println!();
output
output.into()
}
/// Replaces $variable with **variable.lock().unwrap()
/// Replaces $variable with **variable.lock().unwrap().guard()
/// Returns the found variables as well as tokenstream with replaced variables
/// Returned vec is sorted and deduplicated
fn replace_variables(stream: TokenStream) -> (Vec<Ident>, TokenStream) {
@ -987,7 +869,7 @@ fn replace_variables(stream: TokenStream) -> (Vec<Ident>, TokenStream) {
idents.push(ident.clone());
output.extend(TokenStream::from(quote!(**)));
output.extend(Some(TokenTree::Ident(ident.clone())));
output.extend(TokenStream::from(quote!(.lock().unwrap())));
output.extend(TokenStream::from(quote!(.lock().unwrap().guard())));
},
TokenTree::Group(group) => {
let group_delim = group.delimiter();
@ -1015,7 +897,7 @@ fn wrap_in_arc_mutex(stream: TokenStream) -> TokenStream {
output.extend(TokenStream::from(quote!(std::sync::Arc::new)));
let mutex_group = Group::new(proc_macro::Delimiter::Parenthesis, stream);
let mutex_group = Group::new(Delimiter::Parenthesis, stream);
let mut mutex_stream = TokenStream::new();
@ -1023,7 +905,7 @@ fn wrap_in_arc_mutex(stream: TokenStream) -> TokenStream {
mutex_stream.extend(Some(TokenTree::Group(mutex_group)));
let arc_group = Group::new(proc_macro::Delimiter::Parenthesis, mutex_stream);
let arc_group = Group::new(Delimiter::Parenthesis, mutex_stream);
output.extend(Some(TokenTree::Group(arc_group)));
@ -1035,7 +917,7 @@ fn wrap_in_arcmutex_cyclic(stream: TokenStream) -> TokenStream {
output.extend(TokenStream::from(quote!(std::sync::Arc::new_cyclic)));
let mutex_group = Group::new(proc_macro::Delimiter::Parenthesis, stream);
let mutex_group = Group::new(Delimiter::Parenthesis, stream);
let mut mutex_stream = TokenStream::new();
@ -1045,7 +927,7 @@ fn wrap_in_arcmutex_cyclic(stream: TokenStream) -> TokenStream {
mutex_stream.extend(Some(TokenTree::Group(mutex_group)));
let arc_group = Group::new(proc_macro::Delimiter::Parenthesis, mutex_stream);
let arc_group = Group::new(Delimiter::Parenthesis, mutex_stream);
output.extend(Some(TokenTree::Group(arc_group)));
@ -1057,7 +939,7 @@ fn wrap_in_arcrwlock(stream: TokenStream) -> TokenStream {
output.extend(TokenStream::from(quote!(std::sync::Arc::new)));
let mutex_group = Group::new(proc_macro::Delimiter::Parenthesis, stream);
let mutex_group = Group::new(Delimiter::Parenthesis, stream);
let mut rwlock_stream = TokenStream::new();
@ -1065,7 +947,7 @@ fn wrap_in_arcrwlock(stream: TokenStream) -> TokenStream {
rwlock_stream.extend(Some(TokenTree::Group(mutex_group)));
let arc_group = Group::new(proc_macro::Delimiter::Parenthesis, rwlock_stream);
let arc_group = Group::new(Delimiter::Parenthesis, rwlock_stream);
output.extend(Some(TokenTree::Group(arc_group)));

View file

@ -4,25 +4,18 @@ use crate::WeakSharedComponent;
/// A rusalka component
pub trait Component {
type ComponentAttrs: Default;
type ComponentAttrs;
type ReactiveComponentAttrs: From<Self::ComponentAttrs>;
type PartialComponentAttrs: Default + From<Self::ComponentAttrs>;
const UPDATE_LENGTH : usize = 0;
fn new(attr: Self::ComponentAttrs, selfref: WeakSharedComponent<Self>) -> Self;
fn get(&self) -> &Self::ComponentAttrs;
fn get(&self) -> &Self::ReactiveComponentAttrs;
fn set(&mut self, attr: Self::PartialComponentAttrs);
fn mount(&self, parent: &SharedNode, before: Option<&SharedNode>);
fn update(&self, bitmap: &[u32]);
fn unmount(&self);
fn tick(&mut self, bitmap: Option<&[u32]>) {
if let Some(bitmap) = bitmap {
self.update(bitmap);
}
}
// fn set_selfref(&mut self, selfref: SharedComponent<Self>);
fn check_update(&self, bitmap: &[u32]) -> () {
if bitmap.len() != Self::UPDATE_LENGTH {
panic!("Bitmap length does not match update length");
}
}
}
pub struct Slot {
pub mount: Box<dyn FnMut(&SharedNode, Option<&SharedNode>)>,
pub unmount: Box<dyn FnMut()>,
}

View file

@ -1,36 +0,0 @@
use std::ops::{Deref, DerefMut};
pub struct Invalidator<T> {
inner: T,
invalidated: bool
}
impl<T> Invalidator<T> {
pub fn new(inner: T) -> Self {
Self {
inner,
invalidated: false
}
}
pub fn reset(&mut self) {
self.invalidated = false;
}
pub fn invalidated(&self) -> bool {
self.invalidated
}
}
impl<T> Deref for Invalidator<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> DerefMut for Invalidator<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.invalidated = true;
&mut self.inner
}
}

View file

@ -5,7 +5,6 @@ use mangui::nodes::Node;
pub mod component;
pub mod nodes;
pub mod invalidator;
pub mod store;
pub type SharedComponent<T: Component> = Arc<Mutex<T>>;

View file

@ -1,8 +1,6 @@
use std::sync::Arc;
use mangui::SharedNode;
pub mod primitives;
pub fn detach(node: &SharedNode) {
if let Some(parent) = node.read().unwrap().parent() {
parent.write().unwrap().remove_child(node).unwrap();

View file

@ -1,91 +0,0 @@
// DemoComponent
use std::sync::{Arc, RwLock};
use mangui::{SharedNode, nodes::{primitives, Style}, taffy::prelude::Size, femtovg::{Paint, Color}};
use crate::{component::Component, WeakSharedComponent};
use super::{insert, detach};
pub struct Rectangle {
node: Arc<RwLock<primitives::Rectangle>>,
attrs: RectangleAttributes,
selfref: WeakSharedComponent<Self>
}
#[derive(Default)]
pub struct RectangleAttributes {
pub radius: f32
}
#[derive(Default)]
pub struct PartialRectangleAttributes {
pub radius: Option<f32>
}
impl From<RectangleAttributes> for PartialRectangleAttributes {
fn from(attrs: RectangleAttributes) ->
Self {
Self {
radius: Some(attrs.radius)
}
}
}
impl Component for Rectangle {
type ComponentAttrs = RectangleAttributes;
type PartialComponentAttrs = PartialRectangleAttributes;
const UPDATE_LENGTH : usize = 1;
fn new(attrs: Self::ComponentAttrs, selfref: WeakSharedComponent<Self>) -> Self {
Self {
node: Arc::new(RwLock::new(primitives::Rectangle {
style: Style {
layout: mangui::nodes::TaffyStyle {
min_size: Size {
width: mangui::taffy::style::Dimension::Length(50.),
height: mangui::taffy::style::Dimension::Length(100.)
},
..Default::default()
},
..Default::default()
},
fill: Paint::color(Color::rgb(0, 0, 255)),
radius: attrs.radius,
..Default::default()
})),
attrs,
selfref
}
}
fn set(&mut self, attrs: Self::PartialComponentAttrs) {
let mut to_update = [0; Self::UPDATE_LENGTH];
if let Some(radius) = attrs.radius {
self.attrs.radius = radius;
to_update[0] |= 1;
}
if to_update.into_iter().reduce(|a,b| a+b).unwrap() != 0 {
self.update(&to_update);
}
}
fn get(&self) -> &Self::ComponentAttrs { &self.attrs }
fn mount(&self, parent: &SharedNode, before: Option<&SharedNode>) {
insert(parent, &{self.node.clone()}, before);
}
fn update(&self, bitmap: &[u32]) {
self.check_update(bitmap);
if bitmap[0] & 1 != 0 {
self.node.write().unwrap().radius = self.attrs.radius;
}
if bitmap[0] & 1 != 0 {}
}
fn unmount(&self) {
detach(&{self.node.clone()});
}
}

View file

@ -1,30 +1,33 @@
use std::sync::{atomic::AtomicU64, Arc, Mutex, Weak};
use std::ops::{Deref, DerefMut};
use std::sync::{atomic::AtomicU64, Arc, Mutex, Weak, MutexGuard};
/// Unsubscribes from the store when dropped
pub trait StoreUnsubscribe: Drop {}
pub trait ReadableStore {
pub trait Signal {
fn subscribe(&self, callback: Box<dyn FnMut()>) -> Box<dyn StoreUnsubscribe>;
}
pub trait ReadableStore: Signal {
type State;
fn get(&self) -> &Self::State;
fn subscribe(&self, callback: Box<dyn FnMut(&Self::State) -> ()>) -> Box<dyn StoreUnsubscribe>;
}
pub trait WritableStore: ReadableStore {
fn set(&mut self, state: Self::State);
}
struct Listener<T> {
struct Listener {
hash: u64,
callback: Box<dyn FnMut(&T) -> ()>
callback: Box<dyn FnMut()>
}
struct ReadableUnsubscribe<T> {
listeners: Weak<Mutex<Vec<Listener<T>>>>,
struct ReadableUnsubscribe {
listeners: Weak<Mutex<Vec<Listener>>>,
hash: u64
}
impl<T: Sized> Drop for ReadableUnsubscribe<T> {
impl Drop for ReadableUnsubscribe {
fn drop(&mut self) {
if let Some(listeners) = self.listeners.upgrade() {
let mut listeners = listeners.lock().unwrap();
@ -33,11 +36,11 @@ impl<T: Sized> Drop for ReadableUnsubscribe<T> {
}
}
impl<T> StoreUnsubscribe for ReadableUnsubscribe<T> {}
impl StoreUnsubscribe for ReadableUnsubscribe {}
pub struct Readable<T> {
state: T,
listeners: Arc<Mutex<Vec<Listener<T>>>>
listeners: Arc<Mutex<Vec<Listener>>>
}
impl<T> Readable<T> {
@ -51,14 +54,11 @@ impl<T> Readable<T> {
static CALL_COUNT: AtomicU64 = AtomicU64::new(0);
impl<T: 'static> ReadableStore for Readable<T> {
type State = T;
fn get(&self) -> &Self::State {
&self.state
}
fn subscribe(&self, callback: Box<dyn FnMut(&Self::State) -> ()>) -> Box<dyn StoreUnsubscribe> {
impl<T: 'static> Signal for Readable<T> {
fn subscribe(&self, mut callback: Box<dyn FnMut()>) -> Box<dyn StoreUnsubscribe> {
let hash = CALL_COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let mut listeners = self.listeners.lock().unwrap();
callback();
listeners.push(Listener {
callback,
hash
@ -70,9 +70,16 @@ impl<T: 'static> ReadableStore for Readable<T> {
}
}
impl<T: 'static> ReadableStore for Readable<T> {
type State = T;
fn get(&self) -> &Self::State {
&self.state
}
}
pub struct Writable<T> {
state: T,
listeners: Arc<Mutex<Vec<Listener<T>>>>
listeners: Arc<Mutex<Vec<Listener>>>
}
impl<T> Writable<T> {
@ -84,14 +91,11 @@ impl<T> Writable<T> {
}
}
impl<T: 'static> ReadableStore for Writable<T> {
type State = T;
fn get(&self) -> &Self::State {
&self.state
}
fn subscribe(&self, callback: Box<dyn FnMut(&Self::State) -> ()>) -> Box<dyn StoreUnsubscribe> {
impl<T: 'static> Signal for Writable<T> {
fn subscribe(&self, mut callback: Box<dyn FnMut()>) -> Box<dyn StoreUnsubscribe> {
let hash = CALL_COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let mut listeners = self.listeners.lock().unwrap();
callback();
listeners.push(Listener {
callback,
hash
@ -103,12 +107,112 @@ impl<T: 'static> ReadableStore for Writable<T> {
}
}
impl<T: 'static> ReadableStore for Writable<T> {
type State = T;
fn get(&self) -> &Self::State {
&self.state
}
}
impl<T: 'static> WritableStore for Writable<T> {
fn set(&mut self, state: Self::State) {
self.state = state;
let mut listeners = self.listeners.lock().unwrap();
for listener in listeners.iter_mut() {
(listener.callback)(&self.state);
(listener.callback)();
}
}
}
impl<T: 'static> Default for Writable<T> where T: Default {
fn default() -> Self {
Self::new(Default::default())
}
}
pub struct DerefGuard<T> {
listeners: Arc<Mutex<Vec<Listener>>>,
tainted: bool,
inner: T
}
pub trait DerefGuardExt<T>: WritableStore + Signal {
fn guard(&mut self) -> DerefGuard<&mut T>;
}
impl <T: 'static> DerefGuardExt<T> for Writable<T> {
fn guard(&mut self) -> DerefGuard<&mut T> {
DerefGuard {
listeners: self.listeners.clone(),
tainted: false,
inner: &mut self.state
}
}
}
impl<T> Deref for DerefGuard<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> DerefMut for DerefGuard<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.tainted = true;
&mut self.inner
}
}
impl<T> Drop for DerefGuard<T> {
fn drop(&mut self) {
if self.tainted {
let mut listeners = self.listeners.lock().unwrap();
for listener in listeners.iter_mut() {
(listener.callback)();
}
}
}
}
struct VecUnsub {
unsubscribes: Vec<Box<dyn StoreUnsubscribe>>
}
impl Drop for VecUnsub {
fn drop(&mut self) {}
}
impl StoreUnsubscribe for VecUnsub {}
// odd that I have to implement this but whatever makes the compiler happy
impl<T: Signal> Signal for MutexGuard<'_, T> {
fn subscribe(&self, callback: Box<dyn FnMut()>) -> Box<dyn StoreUnsubscribe> {
self.deref().subscribe(callback)
}
}
impl<T: Signal> Signal for Vec<T> {
/// Subscribes to all signals in the vector
fn subscribe(&self, callback: Box<dyn FnMut()>) -> Box<dyn StoreUnsubscribe> {
let mut unsubscribes = Vec::with_capacity(self.len());
let callback = Arc::new(Mutex::new(callback));
for signal in self.iter() {
let callback = callback.clone();
unsubscribes.push(signal.subscribe(Box::new(move || callback.lock().unwrap()())));
}
Box::new(VecUnsub { unsubscribes })
}
}
impl<T: Signal> Signal for [T] {
/// Subscribes to all signals in the array
fn subscribe(&self, callback: Box<dyn FnMut()>) -> Box<dyn StoreUnsubscribe> {
let mut unsubscribes = Vec::with_capacity(self.len());
let callback = Arc::new(Mutex::new(callback));
for signal in self.iter() {
let callback = callback.clone();
unsubscribes.push(signal.subscribe(Box::new(move || callback.lock().unwrap()())));
}
Box::new(VecUnsub { unsubscribes })
}
}