From 2559740463d298d27a058607c5d80196dc736c11 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sun, 7 Nov 2021 20:59:09 -0500 Subject: [PATCH] wip: clean up, use old approach to components --- packages/core/benches/jsframework.rs | 4 +- packages/core/examples/props_expand.rs | 9 +++ packages/core/examples/works.rs | 6 +- packages/core/src/component.rs | 38 +-------- packages/core/src/diff.rs | 5 +- packages/core/src/diff_stack.rs | 4 - packages/core/src/lib.rs | 8 +- packages/core/src/nodes.rs | 64 +++++++--------- packages/core/src/scope.rs | 24 ++---- packages/core/src/scopearena.rs | 75 +++++++++++++++--- packages/core/src/util.rs | 4 - packages/core/src/virtual_dom.rs | 102 ++++--------------------- packages/core/tests/borrowedstate.rs | 6 +- packages/core/tests/create_dom.rs | 35 ++++----- packages/core/tests/display_vdom.rs | 6 +- packages/core/tests/lifecycle.rs | 4 +- packages/core/tests/sharedstate.rs | 4 +- packages/core/tests/vdom_rebuild.rs | 29 +++---- 18 files changed, 180 insertions(+), 247 deletions(-) create mode 100644 packages/core/examples/props_expand.rs diff --git a/packages/core/benches/jsframework.rs b/packages/core/benches/jsframework.rs index d0c8aae77..a36d4a1e5 100644 --- a/packages/core/benches/jsframework.rs +++ b/packages/core/benches/jsframework.rs @@ -24,7 +24,7 @@ criterion_group!(mbenches, create_rows); criterion_main!(mbenches); fn create_rows(c: &mut Criterion) { - static App: FC<()> = |(cx, _)| { + static App: FC<()> = |cx, _| { let mut rng = SmallRng::from_entropy(); let rows = (0..10_000_usize).map(|f| { let label = Label::new(&mut rng); @@ -58,7 +58,7 @@ struct RowProps { row_id: usize, label: Label, } -fn Row((cx, props): Scope) -> Element { +fn Row(cx: Context, props: &RowProps) -> Element { let [adj, col, noun] = props.label.0; cx.render(rsx! { tr { diff --git a/packages/core/examples/props_expand.rs b/packages/core/examples/props_expand.rs new file mode 100644 index 000000000..29d41129e --- /dev/null +++ b/packages/core/examples/props_expand.rs @@ -0,0 +1,9 @@ +use dioxus_core as dioxus; +use dioxus_core_macro::*; + +fn main() {} + +#[derive(Props)] +struct ChildProps<'a> { + name: &'a str, +} diff --git a/packages/core/examples/works.rs b/packages/core/examples/works.rs index 1e4655589..fa02c3613 100644 --- a/packages/core/examples/works.rs +++ b/packages/core/examples/works.rs @@ -7,7 +7,7 @@ fn main() { let _ = VirtualDom::new(Parent); } -fn Parent((cx, _): Scope<()>) -> Element { +fn Parent(cx: Context, props: &()) -> Element { let value = cx.use_hook(|_| String::new(), |f| &*f); cx.render(rsx! { @@ -22,7 +22,7 @@ struct ChildProps<'a> { name: &'a str, } -fn Child((cx, props): Scope) -> Element { +fn Child(cx: Context, props: &ChildProps) -> Element { cx.render(rsx! { div { h1 { "it's nested" } @@ -36,7 +36,7 @@ struct Grandchild<'a> { name: &'a str, } -fn Child2((cx, props): Scope) -> Element { +fn Child2(cx: Context, props: &Grandchild) -> Element { cx.render(rsx! { div { "Hello {props.name}!" } }) diff --git a/packages/core/src/component.rs b/packages/core/src/component.rs index fceabb196..b3f82bf18 100644 --- a/packages/core/src/component.rs +++ b/packages/core/src/component.rs @@ -6,39 +6,6 @@ //! that ensures compile-time required and optional fields on cx. use crate::innerlude::{Context, Element, LazyNodes, ScopeChildren}; -/// A component is a wrapper around a Context and some Props that share a lifetime -/// -/// -/// # Example -/// -/// With memoized state: -/// ```rust -/// struct State {} -/// -/// fn Example((cx, props): Scope) -> DomTree { -/// // ... -/// } -/// ``` -/// -/// With borrowed state: -/// ```rust -/// struct State<'a> { -/// name: &'a str -/// } -/// -/// fn Example<'a>((cx, props): Scope<'a, State>) -> DomTree<'a> { -/// // ... -/// } -/// ``` -/// -/// With owned state as a closure: -/// ```rust -/// static Example: FC<()> = |(cx, props)| { -/// // ... -/// }; -/// ``` -/// -pub type Scope<'a, T> = (Context<'a>, &'a T); pub struct FragmentProps<'a> { children: ScopeChildren<'a>, @@ -99,7 +66,7 @@ impl<'a> Properties for FragmentProps<'a> { /// You want to use this free-function when your fragment needs a key and simply returning multiple nodes from rsx! won't cut it. /// #[allow(non_upper_case_globals, non_snake_case)] -pub fn Fragment<'a>((cx, props): Scope<'a, FragmentProps<'a>>) -> Element { +pub fn Fragment<'a>(cx: Context<'a>, props: &'a FragmentProps<'a>) -> Element { cx.render(Some(LazyNodes::new(|f| { f.fragment_from_iter(&props.children) }))) @@ -170,6 +137,7 @@ impl EmptyBuilder { /// This utility function launches the builder method so rsx! and html! macros can use the typed-builder pattern /// to initialize a component's props. -pub fn fc_to_builder<'a, T: Properties + 'a>(_: fn(Scope<'a, T>) -> Element) -> T::Builder { +pub fn fc_to_builder<'a, T: Properties + 'a>(_: fn(Context<'a>, &T) -> Element) -> T::Builder { + // pub fn fc_to_builder<'a, T: Properties + 'a>(_: fn(Scope<'a, T>) -> Element) -> T::Builder { T::builder() } diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 98ba2f3fd..2fd66d014 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -90,6 +90,7 @@ use crate::innerlude::*; use fxhash::{FxHashMap, FxHashSet}; +use slab::Slab; use DomEdit::*; /// Our DiffMachine is an iterative tree differ. @@ -609,7 +610,7 @@ impl<'bump> ScopeArena { // make sure the component's caller function is up to date let scope = self.get_scope(&scope_addr).unwrap(); - scope.update_vcomp(new); + let mut items = scope.items.borrow_mut(); // React doesn't automatically memoize, but we do. let props_are_the_same = todo!("reworking component memoization"); @@ -1280,7 +1281,7 @@ impl<'bump> ScopeArena { } /// Adds a listener closure to a scope during diff. - fn attach_listener_to_scope(&'bump self, listener: &'bump Listener<'bump>, scope: &ScopeState) { + fn attach_listener_to_scope(&'bump self, listener: &'bump Listener<'bump>, scope: &Scope) { let long_listener = unsafe { std::mem::transmute(listener) }; scope.items.borrow_mut().listeners.push(long_listener) } diff --git a/packages/core/src/diff_stack.rs b/packages/core/src/diff_stack.rs index 8685824a1..8eaa42a5c 100644 --- a/packages/core/src/diff_stack.rs +++ b/packages/core/src/diff_stack.rs @@ -49,10 +49,6 @@ impl<'bump> DiffStack<'bump> { } } - pub fn is_empty(&self) -> bool { - self.instructions.is_empty() - } - pub fn pop(&mut self) -> Option> { self.instructions.pop() } diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index f8b632917..6c9ef181e 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -40,7 +40,7 @@ pub(crate) mod innerlude { pub use crate::virtual_dom::*; pub type Element = Option; - pub type FC

= for<'a> fn(Scope<'a, P>) -> Element; + pub type FC

= for<'a> fn(Context<'a>, &'a P) -> Element; } pub use crate::innerlude::{ @@ -50,9 +50,11 @@ pub use crate::innerlude::{ }; pub mod prelude { - pub use crate::component::{fc_to_builder, Fragment, Properties, Scope}; + pub use crate::component::{fc_to_builder, Fragment, Properties}; pub use crate::innerlude::Context; - pub use crate::innerlude::{DioxusElement, Element, LazyNodes, NodeFactory, ScopeChildren, FC}; + pub use crate::innerlude::{ + DioxusElement, Element, LazyNodes, NodeFactory, Scope, ScopeChildren, FC, + }; pub use crate::nodes::VNode; pub use crate::VirtualDom; } diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index d6988c503..0e245ff81 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -4,7 +4,7 @@ //! cheap and *very* fast to construct - building a full tree should be quick. use crate::{ - innerlude::{empty_cell, Context, Element, ElementId, Properties, Scope, ScopeId, ScopeState}, + innerlude::{empty_cell, Context, Element, ElementId, Properties, Scope, ScopeId}, lazynodes::LazyNodes, }; use bumpalo::{boxed::Box as BumpBox, Bump}; @@ -344,31 +344,29 @@ pub struct Listener<'bump> { pub(crate) callback: RefCell) + 'bump>>>, } +pub type VCompCaller<'src> = BumpBox<'src, dyn Fn(Context) -> Element + 'src>; /// Virtual Components for custom user-defined components /// Only supports the functional syntax pub struct VComponent<'src> { pub key: Option<&'src str>, pub associated_scope: Cell>, - // pub associated_scope: Cell>, // Function pointer to the FC that was used to generate this component pub user_fc: *const (), + pub(crate) can_memoize: bool, + pub(crate) hard_allocation: Cell>, + // Raw pointer into the bump arena for the props of the component - pub(crate) raw_props: *const (), + pub(crate) bump_props: *const (), // during the "teardown" process we'll take the caller out so it can be dropped properly pub(crate) caller: Option>, pub(crate) comparator: Option bool + 'src>>, } -pub enum VCompCaller<'src> { - Borrowed(BumpBox<'src, dyn for<'b> Fn(&'b ScopeState) -> Element + 'src>), - Owned(Box Fn(&'b ScopeState) -> Element>), -} - pub struct VSuspended<'a> { pub task_id: u64, pub dom_id: Cell>, @@ -511,7 +509,7 @@ impl<'a> NodeFactory<'a> { pub fn component

( &self, - component: fn(Scope<'a, P>) -> Element, + component: fn(Context<'a>, &'a P) -> Element, props: P, key: Option, ) -> VNode<'a> @@ -530,18 +528,8 @@ impl<'a> NodeFactory<'a> { let bump = self.bump(); - // let p = BumpBox::new_in(x, a) - - // the best place to allocate the props are the other component's arena - // the second best place is the global allocator - - // // if the props are static - // let boxed = if P::IS_STATIC { - // todo!() - // } else { - // todo!() - // } - + // later, we'll do a hard allocation + let raw_ptr = bump.alloc(props); // let caller = Box::new(|f: &ScopeInner| -> Element { // // // component((f, &props)) @@ -574,26 +562,26 @@ impl<'a> NodeFactory<'a> { let key = key.map(|f| self.raw_text(f).0); - let caller = match P::IS_STATIC { - true => { - // it just makes sense to box the props - let boxed_props: Box

= Box::new(props); - let props_we_know_are_static = todo!(); - VCompCaller::Owned(Box::new(|f| { - // + // let caller = match P::IS_STATIC { + // true => { + // // it just makes sense to box the props + // let boxed_props: Box

= Box::new(props); + // let props_we_know_are_static = todo!(); + // VCompCaller::Owned(Box::new(|f| { + // // - let p = todo!(); + // let p = todo!(); - todo!() - })) - } - false => VCompCaller::Borrowed({ - // + // todo!() + // })) + // } + // false => VCompCaller::Borrowed({ + // // - todo!() - // let caller = bump.alloc() - }), - }; + // todo!() + // // let caller = bump.alloc() + // }), + // }; todo!() // let caller: &'a mut dyn for<'b> Fn(&'b ScopeInner) -> Element<'b> = diff --git a/packages/core/src/scope.rs b/packages/core/src/scope.rs index fd46f7476..3a826b8c7 100644 --- a/packages/core/src/scope.rs +++ b/packages/core/src/scope.rs @@ -30,7 +30,7 @@ use bumpalo::{boxed::Box as BumpBox, Bump}; /// cx.render(rsx!{ div {"Hello, {props.name}"} }) /// } /// ``` -pub type Context<'a> = &'a ScopeState; +pub type Context<'a> = &'a Scope; /// Every component in Dioxus is represented by a `Scope`. /// @@ -41,7 +41,7 @@ pub type Context<'a> = &'a ScopeState; /// /// We expose the `Scope` type so downstream users can traverse the Dioxus VirtualDOM for whatever /// use case they might have. -pub struct ScopeState { +pub struct Scope { // Book-keeping about our spot in the arena // safety: @@ -49,7 +49,7 @@ pub struct ScopeState { // pointers to scopes are *always* valid since they are bump allocated and never freed until this scope is also freed // this is just a bit of a hack to not need an Rc to the ScopeArena. // todo: replace this will ScopeId and provide a connection to scope arena directly - pub(crate) parent_scope: Option<*mut ScopeState>, + pub(crate) parent_scope: Option<*mut Scope>, pub(crate) our_arena_idx: ScopeId, @@ -62,8 +62,6 @@ pub struct ScopeState { // The double-buffering situation that we will use pub(crate) frames: [Bump; 2], - pub(crate) vcomp: *const VComponent<'static>, - pub(crate) old_root: RefCell>, pub(crate) new_root: RefCell>, @@ -89,6 +87,8 @@ pub struct SelfReferentialItems<'a> { pub(crate) cached_nodes_old: Vec>, pub(crate) cached_nodes_new: Vec>, + pub(crate) caller: &'a dyn Fn(&Scope) -> Element, + pub(crate) generation: Cell, pub(crate) listeners: Vec<&'a Listener<'a>>, @@ -99,7 +99,7 @@ pub struct SelfReferentialItems<'a> { } // Public methods exposed to libraries and components -impl ScopeState { +impl Scope { /// Get the root VNode for this Scope. /// /// This VNode is the "entrypoint" VNode. If the component renders multiple nodes, then this VNode will be a fragment. @@ -440,7 +440,7 @@ Functions prefixed with "use" should never be called conditionally. "###; // Important internal methods -impl ScopeState { +impl Scope { /// Give out our self-referential item with our own borrowed lifetime pub(crate) fn fin_head<'b>(&'b self) -> &'b VNode<'b> { todo!() @@ -527,14 +527,4 @@ impl ScopeState { // Some(cur) // } } - - pub(crate) fn update_vcomp(&self, vcomp: &VComponent) { - let f: *const _ = vcomp; - todo!() - // self.vcomp = unsafe { std::mem::transmute(f) }; - } - - pub(crate) fn load_vcomp<'a>(&'a mut self) -> &'a VComponent<'a> { - unsafe { std::mem::transmute(&*self.vcomp) } - } } diff --git a/packages/core/src/scopearena.rs b/packages/core/src/scopearena.rs index 48732841c..a19600504 100644 --- a/packages/core/src/scopearena.rs +++ b/packages/core/src/scopearena.rs @@ -1,3 +1,4 @@ +use slab::Slab; use std::cell::{Cell, RefCell}; use bumpalo::{boxed::Box as BumpBox, Bump}; @@ -19,7 +20,7 @@ pub struct Heuristic { // has an internal heuristics engine to pre-allocate arenas to the right size pub(crate) struct ScopeArena { bump: Bump, - scopes: Vec<*mut ScopeState>, + scopes: Vec<*mut Scope>, free_scopes: Vec, pub(crate) sender: UnboundedSender, } @@ -30,19 +31,20 @@ impl ScopeArena { bump: Bump::new(), scopes: Vec::new(), free_scopes: Vec::new(), + sender, } } - pub fn get_scope(&self, id: &ScopeId) -> Option<&ScopeState> { + pub fn get_scope(&self, id: &ScopeId) -> Option<&Scope> { unsafe { Some(&*self.scopes[id.0]) } } pub fn new_with_key( &mut self, fc_ptr: *const (), - vcomp: &VComponent, - parent_scope: Option<*mut ScopeState>, + caller: *mut dyn Fn(&Scope) -> Element, + parent_scope: Option<*mut Scope>, height: u32, subtree: u32, ) -> ScopeId { @@ -55,9 +57,10 @@ impl ScopeArena { } else { let id = ScopeId(self.scopes.len()); - let vcomp = unsafe { std::mem::transmute(vcomp as *const VComponent) }; + // cast off the lifetime + let caller = unsafe { std::mem::transmute(caller) }; - let new_scope = ScopeState { + let new_scope = Scope { sender: self.sender.clone(), parent_scope, our_arena_idx: id, @@ -65,7 +68,6 @@ impl ScopeArena { subtree: Cell::new(subtree), is_subtree_root: Cell::new(false), frames: [Bump::default(), Bump::default()], - vcomp, hooks: Default::default(), shared_contexts: Default::default(), @@ -78,7 +80,8 @@ impl ScopeArena { pending_effects: Default::default(), cached_nodes_old: Default::default(), generation: Default::default(), - cached_nodes_new: todo!(), + cached_nodes_new: Default::default(), + caller, }), old_root: todo!(), new_root: todo!(), @@ -90,7 +93,7 @@ impl ScopeArena { } } - pub fn try_remove(&self, id: &ScopeId) -> Option { + pub fn try_remove(&self, id: &ScopeId) -> Option { todo!() } @@ -154,4 +157,58 @@ impl ScopeArena { .map(|li| unsafe { &*li }) .for_each(|listener| drop(listener.callback.borrow_mut().take())); } + + pub(crate) fn run_scope(&self, id: &ScopeId) -> bool { + let scope = self + .get_scope(id) + .expect("The base scope should never be moved"); + + // Cycle to the next frame and then reset it + // This breaks any latent references, invalidating every pointer referencing into it. + // Remove all the outdated listeners + self.ensure_drop_safety(id); + + // Safety: + // - We dropped the listeners, so no more &mut T can be used while these are held + // - All children nodes that rely on &mut T are replaced with a new reference + unsafe { scope.hooks.reset() }; + + // Safety: + // - We've dropped all references to the wip bump frame with "ensure_drop_safety" + unsafe { scope.reset_wip_frame() }; + + let mut items = scope.items.borrow_mut(); + + // just forget about our suspended nodes while we're at it + items.suspended_nodes.clear(); + + // guarantee that we haven't screwed up - there should be no latent references anywhere + debug_assert!(items.listeners.is_empty()); + debug_assert!(items.suspended_nodes.is_empty()); + debug_assert!(items.borrowed_props.is_empty()); + + log::debug!("Borrowed stuff is successfully cleared"); + + // temporarily cast the vcomponent to the right lifetime + // let vcomp = scope.load_vcomp(); + + let render: &dyn Fn(&Scope) -> Element = todo!(); + + // Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders. + if let Some(key) = render(scope) { + // todo!("attach the niode"); + // let new_head = builder.into_vnode(NodeFactory { + // bump: &scope.frames.wip_frame().bump, + // }); + // log::debug!("Render is successful"); + + // the user's component succeeded. We can safely cycle to the next frame + // scope.frames.wip_frame_mut().head_node = unsafe { std::mem::transmute(new_head) }; + // scope.frames.cycle_frame(); + + true + } else { + false + } + } } diff --git a/packages/core/src/util.rs b/packages/core/src/util.rs index fad669026..b0da2c425 100644 --- a/packages/core/src/util.rs +++ b/packages/core/src/util.rs @@ -7,10 +7,6 @@ pub fn empty_cell() -> Cell> { Cell::new(None) } -pub fn type_name_of(_: T) -> &'static str { - std::any::type_name::() -} - /// A component's unique identifier. /// /// `ScopeId` is a `usize` that is unique across the entire VirtualDOM - but not unique across time. If a component is diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 59eed261c..9b164d128 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -20,21 +20,13 @@ //! Additional functionality is defined in the respective files. use crate::innerlude::*; -use bumpalo::Bump; use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender}; -use futures_util::{pin_mut, stream::FuturesUnordered, Future, FutureExt, StreamExt}; -use fxhash::FxHashMap; +use futures_util::{Future, StreamExt}; use fxhash::FxHashSet; use indexmap::IndexSet; -use slab::Slab; use std::pin::Pin; use std::task::Poll; -use std::{ - any::{Any, TypeId}, - cell::{Cell, UnsafeCell}, - collections::{HashSet, VecDeque}, - rc::Rc, -}; +use std::{any::Any, collections::VecDeque}; /// An integrated virtual node system that progresses events and diffs UI trees. /// @@ -69,10 +61,7 @@ use std::{ pub struct VirtualDom { base_scope: ScopeId, - _root_props: Rc, - - // we need to keep the allocation around, but we don't necessarily use it - _root_caller: Box, + _root_caller: *mut dyn Fn(&Scope) -> Element, pub(crate) scopes: ScopeArena, @@ -156,30 +145,22 @@ impl VirtualDom { sender: UnboundedSender, receiver: UnboundedReceiver, ) -> Self { - let mut scopes = ScopeArena::new(sender); + let mut scopes = ScopeArena::new(sender.clone()); - let base_scope = scopes.new_with_key( - // - root as _, - todo!(), - // boxed_comp.as_ref(), - None, - 0, - 0, - ); + let caller = Box::new(move |f: &Scope| -> Element { root(f, &root_props) }); + let caller_ref: *mut dyn Fn(&Scope) -> Element = Box::into_raw(caller); + let base_scope = scopes.new_with_key(root as _, caller_ref, None, 0, 0); Self { scopes, base_scope, receiver, - sender, - - _root_props: todo!(), - _root_caller: todo!(), - + // todo: clean this up manually? + _root_caller: caller_ref, pending_messages: VecDeque::new(), pending_futures: Default::default(), dirty_scopes: Default::default(), + sender, } } @@ -189,7 +170,7 @@ impl VirtualDom { /// directly. /// /// # Example - pub fn base_scope(&self) -> &ScopeState { + pub fn base_scope(&self) -> &Scope { self.get_scope(&self.base_scope).unwrap() } @@ -199,7 +180,7 @@ impl VirtualDom { /// /// /// - pub fn get_scope<'a>(&'a self, id: &ScopeId) -> Option<&'a ScopeState> { + pub fn get_scope<'a>(&'a self, id: &ScopeId) -> Option<&'a Scope> { self.scopes.get_scope(id) } @@ -402,7 +383,7 @@ impl VirtualDom { log::debug!("about to run scope {:?}", scopeid); - if self.run_scope(&scopeid) { + if self.scopes.run_scope(&scopeid) { let scope = self.scopes.get_scope(&scopeid).unwrap(); let (old, new) = (scope.wip_head(), scope.fin_head()); diff_state.stack.scope_stack.push(scopeid); @@ -503,7 +484,7 @@ impl VirtualDom { pub fn hard_diff<'a>(&'a mut self, scope_id: &ScopeId) -> Option> { log::debug!("hard diff {:?}", scope_id); - if self.run_scope(scope_id) { + if self.scopes.run_scope(scope_id) { let mut diff_machine = DiffState::new(Mutations::new()); diff_machine.force_diff = true; @@ -515,61 +496,6 @@ impl VirtualDom { None } } - - fn run_scope(&self, id: &ScopeId) -> bool { - let scope = self - .scopes - .get_scope(id) - .expect("The base scope should never be moved"); - - // Cycle to the next frame and then reset it - // This breaks any latent references, invalidating every pointer referencing into it. - // Remove all the outdated listeners - self.scopes.ensure_drop_safety(id); - - // Safety: - // - We dropped the listeners, so no more &mut T can be used while these are held - // - All children nodes that rely on &mut T are replaced with a new reference - unsafe { scope.hooks.reset() }; - - // Safety: - // - We've dropped all references to the wip bump frame with "ensure_drop_safety" - unsafe { scope.reset_wip_frame() }; - - let mut items = scope.items.borrow_mut(); - - // just forget about our suspended nodes while we're at it - items.suspended_nodes.clear(); - - // guarantee that we haven't screwed up - there should be no latent references anywhere - debug_assert!(items.listeners.is_empty()); - debug_assert!(items.suspended_nodes.is_empty()); - debug_assert!(items.borrowed_props.is_empty()); - - log::debug!("Borrowed stuff is successfully cleared"); - - // temporarily cast the vcomponent to the right lifetime - // let vcomp = scope.load_vcomp(); - - let render: &dyn Fn(&ScopeState) -> Element = todo!(); - - // Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders. - if let Some(key) = render(scope) { - // todo!("attach the niode"); - // let new_head = builder.into_vnode(NodeFactory { - // bump: &scope.frames.wip_frame().bump, - // }); - // log::debug!("Render is successful"); - - // the user's component succeeded. We can safely cycle to the next frame - // scope.frames.wip_frame_mut().head_node = unsafe { std::mem::transmute(new_head) }; - // scope.frames.cycle_frame(); - - true - } else { - false - } - } } pub enum SchedulerMsg { diff --git a/packages/core/tests/borrowedstate.rs b/packages/core/tests/borrowedstate.rs index b12e411a2..692a8f8db 100644 --- a/packages/core/tests/borrowedstate.rs +++ b/packages/core/tests/borrowedstate.rs @@ -10,7 +10,7 @@ fn test_borrowed_state() { let _ = VirtualDom::new(Parent); } -fn Parent((cx, _): Scope<()>) -> Element { +fn Parent(cx: Context, props: &()) -> Element { let value = cx.use_hook(|_| String::new(), |f| &*f); cx.render(rsx! { @@ -28,7 +28,7 @@ struct ChildProps<'a> { name: &'a str, } -fn Child((cx, props): Scope) -> Element { +fn Child(cx: Context, props: &ChildProps) -> Element { cx.render(rsx! { div { h1 { "it's nested" } @@ -42,7 +42,7 @@ struct Grandchild<'a> { name: &'a str, } -fn Child2((cx, props): Scope) -> Element { +fn Child2(cx: Context, props: &Grandchild) -> Element { cx.render(rsx! { div { "Hello {props.name}!" } }) diff --git a/packages/core/tests/create_dom.rs b/packages/core/tests/create_dom.rs index 1d7e0b9bf..49a10fb21 100644 --- a/packages/core/tests/create_dom.rs +++ b/packages/core/tests/create_dom.rs @@ -21,7 +21,7 @@ fn new_dom(app: FC

, props: P) -> VirtualDom { #[test] fn test_original_diff() { - static APP: FC<()> = |(cx, props)| { + static APP: FC<()> = |cx, props| { cx.render(rsx! { div { div { @@ -57,7 +57,7 @@ fn test_original_diff() { #[test] fn create() { - static APP: FC<()> = |(cx, props)| { + static APP: FC<()> = |cx, props| { cx.render(rsx! { div { div { @@ -120,7 +120,7 @@ fn create() { #[test] fn create_list() { - static APP: FC<()> = |(cx, props)| { + static APP: FC<()> = |cx, props| { cx.render(rsx! { {(0..3).map(|f| rsx!{ div { "hello" @@ -169,7 +169,7 @@ fn create_list() { #[test] fn create_simple() { - static APP: FC<()> = |(cx, props)| { + static APP: FC<()> = |cx, props| { cx.render(rsx! { div {} div {} @@ -207,7 +207,7 @@ fn create_simple() { } #[test] fn create_components() { - static App: FC<()> = |(cx, props)| { + static App: FC<()> = |cx, props| { cx.render(rsx! { Child { "abc1" } Child { "abc2" } @@ -220,7 +220,7 @@ fn create_components() { children: ScopeChildren<'a>, } - fn Child<'a>((cx, props): Scope<'a, ChildProps<'a>>) -> Element { + fn Child<'a>(cx: Context<'a>, props: &ChildProps<'a>) -> Element { cx.render(rsx! { h1 {} div { {&props.children} } @@ -273,7 +273,7 @@ fn create_components() { } #[test] fn anchors() { - static App: FC<()> = |(cx, props)| { + static App: FC<()> = |cx, props| { cx.render(rsx! { {true.then(|| rsx!{ div { "hello" } })} {false.then(|| rsx!{ div { "goodbye" } })} @@ -302,17 +302,18 @@ fn anchors() { #[test] fn suspended() { - static App: FC<()> = |(cx, props)| { - let val = use_suspense(cx, || async {}, |p| todo!()); + todo!() + // static App: FC<()> = |cx, props| { + // let val = use_suspense(cx, || async {}, |p| todo!()); - cx.render(rsx! { {val} }) - }; + // cx.render(rsx! { {val} }) + // }; - let mut dom = new_dom(App, ()); - let mutations = dom.rebuild(); + // let mut dom = new_dom(App, ()); + // let mutations = dom.rebuild(); - assert_eq!( - mutations.edits, - [CreatePlaceholder { root: 0 }, AppendChildren { many: 1 },] - ); + // assert_eq!( + // mutations.edits, + // [CreatePlaceholder { root: 0 }, AppendChildren { many: 1 },] + // ); } diff --git a/packages/core/tests/display_vdom.rs b/packages/core/tests/display_vdom.rs index c7acc712c..ee32f27c0 100644 --- a/packages/core/tests/display_vdom.rs +++ b/packages/core/tests/display_vdom.rs @@ -13,7 +13,7 @@ mod test_logging; #[test] fn please_work() { - static App: FC<()> = |(cx, props)| { + static App: FC<()> = |cx, props| { cx.render(rsx! { div { hidden: "true" @@ -27,7 +27,7 @@ fn please_work() { }) }; - static Child: FC<()> = |(cx, props)| { + static Child: FC<()> = |cx, props| { cx.render(rsx! { div { "child" } }) @@ -35,6 +35,4 @@ fn please_work() { let mut dom = VirtualDom::new(App); dom.rebuild(); - - println!("{}", dom); } diff --git a/packages/core/tests/lifecycle.rs b/packages/core/tests/lifecycle.rs index 3b9c05cca..1e65f8f58 100644 --- a/packages/core/tests/lifecycle.rs +++ b/packages/core/tests/lifecycle.rs @@ -20,7 +20,7 @@ fn manual_diffing() { value: Shared<&'static str>, } - static App: FC = |(cx, props)| { + static App: FC = |cx, props| { let val = props.value.lock().unwrap(); cx.render(rsx! { div { "{val}" } }) }; @@ -37,7 +37,7 @@ fn manual_diffing() { *value.lock().unwrap() = "goodbye"; - let edits = dom.diff(); + let edits = dom.rebuild(); log::debug!("edits: {:?}", edits); } diff --git a/packages/core/tests/sharedstate.rs b/packages/core/tests/sharedstate.rs index 7bb9e6501..5a2e8d042 100644 --- a/packages/core/tests/sharedstate.rs +++ b/packages/core/tests/sharedstate.rs @@ -13,12 +13,12 @@ mod test_logging; fn shared_state_test() { struct MySharedState(&'static str); - static App: FC<()> = |(cx, props)| { + static App: FC<()> = |cx, props| { cx.provide_state(MySharedState("world!")); cx.render(rsx!(Child {})) }; - static Child: FC<()> = |(cx, props)| { + static Child: FC<()> = |cx, props| { let shared = cx.consume_state::()?; cx.render(rsx!("Hello, {shared.0}")) }; diff --git a/packages/core/tests/vdom_rebuild.rs b/packages/core/tests/vdom_rebuild.rs index 79aaad112..9aa805918 100644 --- a/packages/core/tests/vdom_rebuild.rs +++ b/packages/core/tests/vdom_rebuild.rs @@ -17,7 +17,7 @@ use dioxus_html as dioxus_elements; #[test] fn app_runs() { - static App: FC<()> = |(cx, props)| { + static App: FC<()> = |cx, props| { // cx.render(rsx!( div{"hello"} )) }; @@ -28,7 +28,7 @@ fn app_runs() { #[test] fn fragments_work() { - static App: FC<()> = |(cx, props)| { + static App: FC<()> = |cx, props| { cx.render(rsx!( div{"hello"} div{"goodbye"} @@ -42,7 +42,7 @@ fn fragments_work() { #[test] fn lists_work() { - static App: FC<()> = |(cx, props)| { + static App: FC<()> = |cx, props| { cx.render(rsx!( h1 {"hello"} {(0..6).map(|f| rsx!(span{ "{f}" }))} @@ -55,7 +55,7 @@ fn lists_work() { #[test] fn conditional_rendering() { - static App: FC<()> = |(cx, props)| { + static App: FC<()> = |cx, props| { cx.render(rsx!( h1 {"hello"} {true.then(|| rsx!(span{ "a" }))} @@ -72,13 +72,13 @@ fn conditional_rendering() { #[test] fn child_components() { - static App: FC<()> = |(cx, props)| { + static App: FC<()> = |cx, props| { cx.render(rsx!( {true.then(|| rsx!(Child { }))} {false.then(|| rsx!(Child { }))} )) }; - static Child: FC<()> = |(cx, props)| { + static Child: FC<()> = |cx, props| { cx.render(rsx!( h1 {"hello"} h1 {"goodbye"} @@ -91,13 +91,14 @@ fn child_components() { #[test] fn suspended_works() { - static App: FC<()> = |(cx, props)| { - let title = use_suspense(cx, || async { "bob" }, move |cx, f| todo!()); - // let title = use_suspense(cx, || async { "bob" }, move |cx, f| rsx! { "{f}"}); - cx.render(rsx!("hello" { title })) - }; + todo!() + // static App: FC<()> = |cx, props| { + // let title = use_suspense(cx, || async { "bob" }, move |cx, f| todo!()); + // // let title = use_suspense(cx, || async { "bob" }, move |cx, f| rsx! { "{f}"}); + // cx.render(rsx!("hello" { title })) + // }; - let mut vdom = VirtualDom::new(App); - let edits = vdom.rebuild(); - dbg!(edits); + // let mut vdom = VirtualDom::new(App); + // let edits = vdom.rebuild(); + // dbg!(edits); }