From b3c96a5996f434332813c737bb83ad564d91af5f Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Fri, 12 Mar 2021 15:41:36 -0500 Subject: [PATCH] Feat: props now autoderives its own trait --- packages/core-macro/examples/prop_test.rs | 19 ++++++ packages/core-macro/src/props/mod.rs | 15 +++++ packages/core/examples/borrowed.rs | 7 --- packages/core/examples/fc.rs | 7 --- packages/core/examples/props.rs | 8 +-- packages/core/examples/step.rs | 8 --- packages/core/src/diff.rs | 14 +++-- packages/core/src/patch.rs | 53 ++++++++++------- packages/core/src/scope.rs | 3 + packages/core/src/virtual_dom.rs | 72 ++++++++++++++--------- 10 files changed, 123 insertions(+), 83 deletions(-) create mode 100644 packages/core-macro/examples/prop_test.rs diff --git a/packages/core-macro/examples/prop_test.rs b/packages/core-macro/examples/prop_test.rs new file mode 100644 index 000000000..aa42daef2 --- /dev/null +++ b/packages/core-macro/examples/prop_test.rs @@ -0,0 +1,19 @@ +fn main() {} + +pub mod dioxus { + pub mod prelude { + pub trait Properties { + type Builder; + fn builder() -> Self::Builder; + } + } +} +#[derive(dioxus_core_macro::Props)] +struct SomeProps { + a: String, +} + +#[derive(dioxus_core_macro::Props)] +struct SomePropsTwo<'a> { + a: &'a str, +} diff --git a/packages/core-macro/src/props/mod.rs b/packages/core-macro/src/props/mod.rs index 95090105c..ef706043a 100644 --- a/packages/core-macro/src/props/mod.rs +++ b/packages/core-macro/src/props/mod.rs @@ -678,6 +678,14 @@ Finally, call `.build()` to create the instance of `{name}`. } } } + + impl #impl_generics dioxus::prelude::Properties for #name #ty_generics{ + type Builder = #builder_name #generics_with_empty; + fn builder() -> Self::Builder { + #name::builder() + } + } + }) } @@ -1071,6 +1079,13 @@ Finally, call `.build()` to create the instance of `{name}`. } ) } + + pub fn build_props_impl(&self) -> TokenStream { + // SomeProps: #name + // #builder_name + // #generics_with_empty + quote! {} + } } #[derive(Debug, Default)] diff --git a/packages/core/examples/borrowed.rs b/packages/core/examples/borrowed.rs index f9304a8dd..45f6ed3dd 100644 --- a/packages/core/examples/borrowed.rs +++ b/packages/core/examples/borrowed.rs @@ -69,13 +69,6 @@ impl PartialEq for ChildProps<'_> { } } -impl<'a> Properties for ChildProps<'a> { - type Builder = ChildPropsBuilder<'a, ((), ())>; - fn builder() -> ::Builder { - ChildProps::builder() - } -} - fn ChildItem(_ctx: Context, _props: &ChildProps) -> DomTree { todo!() // ctx.render(rsx! { diff --git a/packages/core/examples/fc.rs b/packages/core/examples/fc.rs index 0e6440bcf..8a249beba 100644 --- a/packages/core/examples/fc.rs +++ b/packages/core/examples/fc.rs @@ -24,10 +24,3 @@ static SomeComponent: FC = |ctx, _props| { }; fn main() {} - -impl Properties for ExampleProps { - type Builder = ExamplePropsBuilder<((),)>; - fn builder() -> Self::Builder { - ExampleProps::builder() - } -} diff --git a/packages/core/examples/props.rs b/packages/core/examples/props.rs index 90315b1f5..1434bfabe 100644 --- a/packages/core/examples/props.rs +++ b/packages/core/examples/props.rs @@ -1,6 +1,6 @@ -use dioxus_core_macro::Props; +use dioxus_core::prelude::*; -#[derive(Debug, Props)] +#[derive(Debug, PartialEq, Props)] struct SomeProps { a: i32, @@ -9,12 +9,8 @@ struct SomeProps { b: Option, } -// have we committed to the trait style yet? - fn main() { let g: SomeProps = SomeProps::builder().a(10).b(10).build(); let _r = g.b.unwrap_or_else(|| 10); } - -fn auto_into_some() {} diff --git a/packages/core/examples/step.rs b/packages/core/examples/step.rs index eefc250a4..0e2873ea9 100644 --- a/packages/core/examples/step.rs +++ b/packages/core/examples/step.rs @@ -23,11 +23,3 @@ static Example: FC = |ctx, _props| { }) }; - -// toodo: derive this -impl Properties for SomeProps { - type Builder = SomePropsBuilder<((),)>; - fn builder() -> Self::Builder { - SomeProps::builder() - } -} diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 7ddbeca3d..8fa0807ba 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -42,7 +42,7 @@ use std::{ cell::{RefCell, RefMut}, cmp::Ordering, collections::VecDeque, - rc::Rc, + rc::{Rc, Weak}, }; /// The DiffState is a cursor internal to the VirtualDOM's diffing algorithm that allows persistence of state while @@ -62,11 +62,9 @@ pub struct DiffMachine<'a> { pub diffed: FxHashSet, pub lifecycle_events: VecDeque>, } - -// #[derive(Debug)] pub enum LifeCycleEvent<'a> { Mount { - caller: Rc Fn(Context<'r>) -> DomTree + 'a>, + caller: Weak Fn(Context<'r>) -> DomTree + 'a>, id: Uuid, }, PropsChanged, @@ -76,7 +74,6 @@ pub enum LifeCycleEvent<'a> { impl<'a> DiffMachine<'a> { pub fn new() -> Self { - // pub fn new(bump: &'a Bump) -> Self { Self { lifecycle_events: VecDeque::new(), change_list: EditMachine::new(), @@ -265,8 +262,13 @@ impl<'a> DiffMachine<'a> { let id = uuid::Uuid::new_v4(); *component.stable_addr.as_ref().borrow_mut() = Some(id); self.change_list.save_known_root(id); + + let caller = Rc::downgrade(&component.caller); + // let broken_caller: Weak DomTree + 'static> = + // unsafe { std::mem::transmute(caller) }; self.lifecycle_events.push_back(LifeCycleEvent::Mount { - caller: component.caller.clone(), + caller, + // caller: broken_caller, id, }); } diff --git a/packages/core/src/patch.rs b/packages/core/src/patch.rs index 2e7c726d2..4b4bb12e3 100644 --- a/packages/core/src/patch.rs +++ b/packages/core/src/patch.rs @@ -23,38 +23,42 @@ pub type EditList<'src> = Vec>; /// The `Edit` represents a single modifcation of the renderer tree. /// todo@ jon: allow serde to be optional +/// todo @jon, go through and make certain fields static. tag names should be known at compile time #[derive(Debug, serde::Serialize, serde::Deserialize)] #[serde(tag = "type")] -pub enum Edit<'d> { +pub enum Edit<'src_bump> { // ======================================================== // Common Ops: The most common operation types // ======================================================== SetText { - text: &'d str, + text: &'src_bump str, }, SetClass { - class_name: &'d str, + class_name: &'src_bump str, }, CreateTextNode { - text: &'d str, + text: &'src_bump str, }, CreateElement { - tag_name: &'d str, + // todo - make static? + tag_name: &'src_bump str, }, CreateElementNs { - tag_name: &'d str, - ns: &'d str, + // todo - make static? + tag_name: &'src_bump str, + // todo - make static? + ns: &'src_bump str, }, // ======================================================== // Attributes // ======================================================== SetAttribute { - name: &'d str, - value: &'d str, + name: &'src_bump str, + value: &'src_bump str, }, RemoveAttribute { - name: &'d str, + name: &'src_bump str, }, RemoveChild { n: u32, @@ -64,17 +68,20 @@ pub enum Edit<'d> { // Event Listeners: Event types and IDs used to update the VDOM // ============================================================ NewListener { - event: &'d str, + // todo - make static? + event: &'src_bump str, scope: ScopeIdx, id: usize, }, UpdateListener { - event: &'d str, + // todo - make static? + event: &'src_bump str, scope: ScopeIdx, id: usize, }, RemoveListener { - event: &'d str, + // todo - make static? + event: &'src_bump str, }, // ======================================================== @@ -124,22 +131,28 @@ pub enum Edit<'d> { }, } -pub struct EditMachine<'src> { +/// The edit machine represents a stream of differences between two component trees. +/// +/// This struct is interesting in that it keeps track of differences by borrowing +/// from the source rather than writing to a new buffer. This means that the virtual dom +/// *cannot* be updated while this machine is in existence without "unsafe". +/// +/// This unsafety is handled by methods on the virtual dom and is not exposed via lib code. +pub struct EditMachine<'lock> { pub traversal: Traversal, next_temporary: u32, forcing_new_listeners: bool, - pub emitter: EditList<'src>, + + pub emitter: EditList<'lock>, } -impl<'b> EditMachine<'b> { +impl<'lock> EditMachine<'lock> { pub fn new() -> Self { - // pub fn new(_bump: &'b bumpalo::Bump) -> Self { - // todo: see if bumpalo is needed for edit list Self { traversal: Traversal::new(), next_temporary: 0, forcing_new_listeners: false, - emitter: EditList::<'b>::default(), + emitter: EditList::<'lock>::default(), } } } @@ -147,7 +160,7 @@ impl<'b> EditMachine<'b> { // =================================== // Traversal Methods // =================================== -impl<'b> EditMachine<'b> { +impl<'src> EditMachine<'src> { pub fn go_down(&mut self) { self.traversal.down(); } diff --git a/packages/core/src/scope.rs b/packages/core/src/scope.rs index a8dce6bfa..1d275fa70 100644 --- a/packages/core/src/scope.rs +++ b/packages/core/src/scope.rs @@ -97,6 +97,8 @@ impl Scope { // To make sure that the lifetime isn't truly broken, we receive a Weak RC so we can't keep it around after the parent dies. // This should never happen, but is a good check to keep around pub fn new<'creator_node>( + // pub fn new( + // caller: Weak DomTree + 'static>, caller: Weak DomTree + 'creator_node>, myidx: ScopeIdx, parent: Option, @@ -106,6 +108,7 @@ impl Scope { let broken_caller: Weak DomTree + 'static> = unsafe { std::mem::transmute(caller) }; + // let broken_caller = caller; Self { caller: broken_caller, hook_arena: typed_arena::Arena::new(), diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 5e8391d19..6562012f7 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -101,6 +101,9 @@ impl VirtualDom { component.run(); } + // get raw pointer to the arena + let very_unsafe_components = &mut self.components as *mut generational_arena::Arena; + { let component = self .components @@ -110,36 +113,47 @@ impl VirtualDom { diff_machine.diff_node(component.old_frame(), component.new_frame()); } - // 'render: loop { - // for event in &mut diff_machine.lifecycle_events.drain(..) { - // log::debug!("event is {:#?}", event); - // match event { - // LifeCycleEvent::Mount { caller, id } => { - // diff_machine.change_list.load_known_root(id); - // let idx = self - // .components - // .insert_with(|f| create_scoped(caller, f, None)); - // // .insert_with(|f| create_scoped(caller, props, myidx, parent)); - // } - // LifeCycleEvent::PropsChanged => { - // // - // break 'render; - // } - // LifeCycleEvent::SameProps => { - // // - // break 'render; - // } - // LifeCycleEvent::Remove => { - // // - // break 'render; - // } - // } - // } + // chew down the the lifecycle events until all dirty nodes are computed + while let Some(event) = diff_machine.lifecycle_events.pop_front() { + match event { + // A new component has been computed from the diffing algorithm + // create a new component in the arena, run it, move the diffing machine to this new spot, and then diff it + // this will flood the lifecycle queue with new updates + LifeCycleEvent::Mount { caller, id } => { + log::debug!("Mounting a new component"); + diff_machine.change_list.load_known_root(id); - // if diff_machine.lifecycle_events.is_empty() { - // break 'render; - // } - // } + // We're modifying the component arena while holding onto references into the assoiated bump arenas of its children + // those references are stable, even if the component arena moves around in memory, thanks to the bump arenas. + // However, there is no way to convey this to rust, so we need to use unsafe to pierce through the lifetime. + unsafe { + let p = &mut *(very_unsafe_components); + + // todo, hook up the parent/child indexes properly + let idx = p.insert_with(|f| Scope::new(caller, f, None)); + let c = p.get_mut(idx).unwrap(); + c.run(); + diff_machine.diff_node(c.old_frame(), c.new_frame()); + } + } + LifeCycleEvent::PropsChanged => { + // + // break 'render; + } + LifeCycleEvent::SameProps => { + // + // break 'render; + } + LifeCycleEvent::Remove => { + // + // break 'render; + } + } + + // } else { + // break 'render; + // } + } let edits: Vec> = diff_machine.consume(); Ok(edits)