diff --git a/packages/core/src/component.rs b/packages/core/src/component.rs index ce5fd2b38..26c920596 100644 --- a/packages/core/src/component.rs +++ b/packages/core/src/component.rs @@ -5,11 +5,7 @@ //! if the type supports PartialEq. The Properties trait is used by the rsx! and html! macros to generate the type-safe builder //! that ensures compile-time required and optional fields on cx. -use crate::{ - innerlude::{Context, Element, FC}, - NodeFactory, VNode, -}; - +use crate::innerlude::{Context, Element, VNode}; /// A component is a wrapper around a Context and some Props that share a lifetime /// /// @@ -44,6 +40,27 @@ use crate::{ /// pub type Scope<'a, T> = (Context<'a>, &'a T); +pub struct FragmentProps<'a> { + childen: &'a VNode<'a>, +} +pub struct FragmentPropsBuilder<'a> { + childen: Option<&'a VNode<'a>>, +} + +impl<'a> Properties for FragmentProps<'a> { + type Builder = FragmentPropsBuilder<'a>; + + const IS_STATIC: bool = false; + + fn builder() -> Self::Builder { + todo!() + } + + unsafe fn memoize(&self, other: &Self) -> bool { + todo!() + } +} + /// Create inline fragments using Component syntax. /// /// Fragments capture a series of children without rendering extra nodes. @@ -66,11 +83,8 @@ pub type Scope<'a, T> = (Context<'a>, &'a T); /// 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, _): Scope<'a, ()>) -> Element<'a> { - todo!() - // let p: Box) -> VNode<'a> + '_> = - // Box::new(|f: NodeFactory| f.fragment_from_iter(cx.children())); - // cx.render(p) +pub fn Fragment<'a>((_, props): Scope<'a, FragmentProps<'a>>) -> Element<'a> { + Some(props.childen.decouple()) } /// Every "Props" used for a component must implement the `Properties` trait. This trait gives some hints to Dioxus diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index eddbb447a..654048267 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -420,10 +420,6 @@ impl<'bump> DiffMachine<'bump> { ) => self .stack .create_node(new_node, MountType::Replace { old: old_node }), - - (Placeholder, _) | (_, Placeholder) => { - unreachable!("placeholder should never be diffed"); - } } } diff --git a/packages/core/src/lazynodes.rs b/packages/core/src/lazynodes.rs index b20e8cb04..249948517 100644 --- a/packages/core/src/lazynodes.rs +++ b/packages/core/src/lazynodes.rs @@ -1,21 +1,18 @@ -use std::mem; +//! Support for storing lazy-nodes on the stack +//! +//! This module provides support for a type called `LazyNodes` which is a micro-heap located on the stack to make calls +//! to `rsx!` more efficient. +//! +//! To support returning rsx! from branches in match statements, we need to use dynamic dispatch on NodeFactory closures. +//! +//! This can be done either through boxing directly, or by using dynamic-sized-types and a custom allocator. In our case, +//! we build a tiny alloactor in the stack and allocate the closure into that. +//! +//! The logic for this was borrowed from https://docs.rs/stack_dst/0.6.1/stack_dst/. Unfortunately, this crate does not +//! support non-static closures, so we've implemented the core logic of `ValueA` in this module. -/* -Remember: calls to rsx! are lazy - they are not evaluated immediately. - -They also using dynamic dispatch, so we can return multiple rsx!'s from match statements and such. - -If we allocated every rsx! call on the heap, it would be quite wasteful. Rsx! calls are FnOnce, so they can be stored in a stack. - -Solutions like stackdst are useful, but they only support 'static closures. - -All our closures are bound by the bump lifetime, so stack-dst will not work for us - -Our solution is to try and manually allocate the closure onto the stack. -If it fails, then we default to Box. - -*/ use crate::innerlude::{NodeFactory, VNode}; +use std::mem; /// A concrete type provider for closures that build VNode structures. /// @@ -73,13 +70,13 @@ impl<'a, 'b> LazyNodes<'a, 'b> { let size = mem::size_of::(); if info.len() * mem::size_of::() + size > mem::size_of::() { - log::error!("lazy nodes was too large to fit into stack. falling back to heap"); + log::debug!("lazy nodes was too large to fit into stack. falling back to heap"); Self { inner: StackNodeStorage::Heap(Box::new(val)), } } else { - log::error!("lazy nodes fits on stack!"); + log::debug!("lazy nodes fits on stack!"); let mut buf: StackHeapSize = [0; 12]; assert!(info.len() + round_to_words(size) <= buf.as_ref().len()); @@ -173,3 +170,22 @@ unsafe fn make_fat_ptr(data_ptr: usize, meta_vals: &[usize]) -> *mut fn round_to_words(len: usize) -> usize { (len + mem::size_of::() - 1) / mem::size_of::() } + +#[test] +fn it_works() { + let bump = bumpalo::Bump::new(); + + simple_logger::init(); + + let factory = NodeFactory { bump: &bump }; + + let caller = NodeFactory::annotate_lazy(|f| { + // + f.text(format_args!("hello world!")) + }) + .unwrap(); + + let g = caller.call(factory); + + dbg!(g); +} diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index 7e23af372..bc06eb29d 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -155,6 +155,22 @@ impl<'src> VNode<'src> { VNode::Component(_) => None, } } + + // Create an "owned" version of the vnode. + pub fn decouple(&self) -> VNode<'src> { + match self { + VNode::Text(t) => VNode::Text(*t), + VNode::Element(e) => VNode::Element(*e), + VNode::Component(c) => VNode::Component(*c), + VNode::Suspended(s) => VNode::Suspended(*s), + VNode::Anchor(a) => VNode::Anchor(*a), + VNode::Fragment(f) => VNode::Fragment(VFragment { + children: f.children, + key: f.key, + is_static: f.is_static, + }), + } + } } /// A placeholder node only generated when Fragments don't have any children. diff --git a/packages/core/src/scope.rs b/packages/core/src/scope.rs index 97333cd0d..94db9d67f 100644 --- a/packages/core/src/scope.rs +++ b/packages/core/src/scope.rs @@ -341,21 +341,21 @@ impl ScopeInner { // Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders. // - todo!() - // if let Some(builder) = render(self) { - // let new_head = builder.into_vnode(NodeFactory { - // bump: &self.frames.wip_frame().bump, - // }); - // log::debug!("Render is successful"); + // todo!() + if let Some(builder) = render(self) { + let new_head = builder.into_vnode(NodeFactory { + bump: &self.frames.wip_frame().bump, + }); + log::debug!("Render is successful"); - // // the user's component succeeded. We can safely cycle to the next frame - // self.frames.wip_frame_mut().head_node = unsafe { std::mem::transmute(new_head) }; - // self.frames.cycle_frame(); + // the user's component succeeded. We can safely cycle to the next frame + self.frames.wip_frame_mut().head_node = unsafe { std::mem::transmute(new_head) }; + self.frames.cycle_frame(); - // true - // } else { - // false - // } + true + } else { + false + } } } diff --git a/packages/core/src/test_dom.rs b/packages/core/src/test_dom.rs index fa3a2649e..aab7f3373 100644 --- a/packages/core/src/test_dom.rs +++ b/packages/core/src/test_dom.rs @@ -21,27 +21,13 @@ impl TestDom { NodeFactory::new(&self.bump) } - pub fn render_direct<'a>( - &'a self, - lazy_nodes: Option) -> VNode<'a> + '_>>, - ) -> VNode<'a> -// where - // F: FnOnce(NodeFactory<'a>) -> VNode<'a>, - { - todo!() - // lazy_nodes.into_vnode(NodeFactory::new(&self.bump)) + pub fn render_direct<'a>(&'a self, lazy_nodes: Option>) -> VNode<'a> { + lazy_nodes.into_vnode(NodeFactory::new(&self.bump)) } - pub fn render<'a>( - &'a self, - lazy_nodes: Option) -> VNode<'a> + '_>>, - ) -> &'a VNode<'a> -// where - // F: FnOnce(NodeFactory<'a>) -> VNode<'a>, - { - todo!() - // self.bump - // .alloc(lazy_nodes.into_vnode(NodeFactory::new(&self.bump))) + pub fn render<'a>(&'a self, lazy_nodes: Option>) -> &'a VNode<'a> { + self.bump + .alloc(lazy_nodes.into_vnode(NodeFactory::new(&self.bump))) } pub fn diff<'a>(&'a self, old: &'a VNode<'a>, new: &'a VNode<'a>) -> Mutations<'a> { @@ -51,14 +37,7 @@ impl TestDom { machine.mutations } - pub fn create<'a>( - &'a self, - left: Option) -> VNode<'a> + '_>>, - ) -> Mutations<'a> -// pub fn create<'a, F1>(&'a self, left: LazyNodes<'a, F1>) -> Mutations<'a> - // where - // F1: FnOnce(NodeFactory<'a>) -> VNode<'a>, - { + pub fn create<'a>(&'a self, left: Option>) -> Mutations<'a> { let old = self.bump.alloc(self.render_direct(left)); let mut machine = DiffMachine::new(Mutations::new(), &self.scheduler.pool); @@ -72,13 +51,9 @@ impl TestDom { pub fn lazy_diff<'a>( &'a self, - left: Option) -> VNode<'a> + '_>>, - right: Option) -> VNode<'a> + '_>>, - ) -> (Mutations<'a>, Mutations<'a>) -// where - // F1: FnOnce(NodeFactory<'a>) -> VNode<'a>, - // F2: FnOnce(NodeFactory<'a>) -> VNode<'a>, - { + left: Option>, + right: Option>, + ) -> (Mutations<'a>, Mutations<'a>) { let (old, new) = (self.render(left), self.render(right)); let mut machine = DiffMachine::new(Mutations::new(), &self.scheduler.pool); @@ -105,9 +80,3 @@ impl Default for TestDom { Self::new() } } - -impl VirtualDom { - pub fn simulate(&mut self) { - // - } -}