diff --git a/packages/core/compile_tests/props_safety.rs b/packages/core/compile_tests/props_safety.rs index a9729cec9..485ef7900 100644 --- a/packages/core/compile_tests/props_safety.rs +++ b/packages/core/compile_tests/props_safety.rs @@ -14,10 +14,10 @@ fn app(cx: Scope) -> Element { #[derive(Props)] struct Testing<'a> { - borrowed: &'a RefCell>>, + borrowed: &'a RefCell>, } -fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element<'a> { +fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element { let Testing { borrowed } = cx.props; let borrowed_temporary_data = cx.use_hook(|| String::from("This data is only valid for the lifetime of the child")); diff --git a/packages/core/compile_tests/props_safety_temporary_values.rs b/packages/core/compile_tests/props_safety_temporary_values.rs index c332f63c4..962c9e6e6 100644 --- a/packages/core/compile_tests/props_safety_temporary_values.rs +++ b/packages/core/compile_tests/props_safety_temporary_values.rs @@ -17,7 +17,7 @@ struct Testing<'a> { borrowed: &'a Vec, } -fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element<'a> { +fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element { cx.render(rsx! { div { "{cx.props.borrowed:?}" } }) diff --git a/packages/core/src/any_props.rs b/packages/core/src/any_props.rs index 2cc9c6559..420bf9d32 100644 --- a/packages/core/src/any_props.rs +++ b/packages/core/src/any_props.rs @@ -1,9 +1,4 @@ -use crate::{ - innerlude::Scoped, - nodes::RenderReturn, - scopes::{Scope, ScopeState}, - Element, -}; +use crate::{nodes::RenderReturn, scopes::ScopeState, Element}; use std::panic::AssertUnwindSafe; /// A trait that essentially allows VComponentProps to be used generically @@ -11,24 +6,19 @@ use std::panic::AssertUnwindSafe; /// # Safety /// /// This should not be implemented outside this module -pub(crate) unsafe trait AnyProps { - fn props_ptr(&self) -> *const (); - fn render<'a>(&'a self, bump: &'a ScopeState) -> RenderReturn<'a>; - unsafe fn memoize(&self, other: &dyn AnyProps) -> bool; +pub(crate) trait AnyProps { + fn render<'a>(&'a self, bump: &'a ScopeState) -> RenderReturn; + fn memoize(&self, other: &dyn AnyProps) -> bool; } -pub(crate) struct VProps<'a, P> { - pub render_fn: fn(Scope<'a, P>) -> Element<'a>, - pub memo: unsafe fn(&P, &P) -> bool, +pub(crate) struct VProps

{ + pub render_fn: fn(P) -> Element, + pub memo: fn(&P, &P) -> bool, pub props: P, } -impl<'a, P> VProps<'a, P> { - pub(crate) fn new( - render_fn: fn(Scope<'a, P>) -> Element<'a>, - memo: unsafe fn(&P, &P) -> bool, - props: P, - ) -> Self { +impl

VProps

{ + pub(crate) fn new(render_fn: fn(P) -> Element, memo: fn(&P, &P) -> bool, props: P) -> Self { Self { render_fn, memo, @@ -37,30 +27,19 @@ impl<'a, P> VProps<'a, P> { } } -unsafe impl<'a, P> AnyProps for VProps<'a, P> { - fn props_ptr(&self) -> *const () { - &self.props as *const _ as *const () - } - +impl AnyProps for VProps

{ // Safety: // this will downcast the other ptr as our swallowed type! // you *must* make this check *before* calling this method // if your functions are not the same, then you will downcast a pointer into a different type (UB) - unsafe fn memoize(&self, other: &dyn AnyProps) -> bool { - let real_other: &P = &*(other.props_ptr() as *const _ as *const P); - let real_us: &P = &*(self.props_ptr() as *const _ as *const P); - (self.memo)(real_us, real_other) + fn memoize(&self, other: &dyn AnyProps) -> bool { + (self.memo)(self, other) } - fn render(&'a self, cx: &'a ScopeState) -> RenderReturn<'a> { + fn render(&self, cx: &ScopeState) -> RenderReturn { let res = std::panic::catch_unwind(AssertUnwindSafe(move || { // Call the render function directly - let scope: &mut Scoped

= cx.bump().alloc(Scoped { - props: &self.props, - scope: cx, - }); - - (self.render_fn)(scope) + (self.render_fn)(self.props.clone()) })); match res { diff --git a/packages/core/src/arena.rs b/packages/core/src/arena.rs index ffdd4656b..205060b32 100644 --- a/packages/core/src/arena.rs +++ b/packages/core/src/arena.rs @@ -102,7 +102,7 @@ impl VirtualDom { if recursive { if let Some(root) = self.scopes[id.0].try_root_node() { - if let RenderReturn::Ready(node) = unsafe { root.extend_lifetime_ref() } { + if let RenderReturn::Ready(node) = root { self.drop_scope_inner(node) } } @@ -131,7 +131,6 @@ impl VirtualDom { if let Some(f) = c.scope.get() { self.drop_scope(f, true); } - c.props.take(); } DynamicNode::Fragment(nodes) => { nodes.iter().for_each(|node| self.drop_scope_inner(node)) @@ -166,9 +165,6 @@ impl VirtualDom { Some(child) if child != scope_id => self.ensure_drop_safety(child), _ => (), } - if let Ok(mut props) = comp.props.try_borrow_mut() { - *props = None; - } } let scope = &self.scopes[scope_id.0]; scope.borrowed_props.borrow_mut().clear(); diff --git a/packages/core/src/create.rs b/packages/core/src/create.rs index 55334b900..c4390c212 100644 --- a/packages/core/src/create.rs +++ b/packages/core/src/create.rs @@ -63,11 +63,11 @@ fn sorting() { ); } -impl<'b> VirtualDom { +impl VirtualDom { /// Create a new template [`VNode`] and write it to the [`Mutations`] buffer. /// /// This method pushes the ScopeID to the internal scopestack and returns the number of nodes created. - pub(crate) fn create_scope(&mut self, scope: ScopeId, template: &'b VNode) -> usize { + pub(crate) fn create_scope(&mut self, scope: ScopeId, template: &VNode) -> usize { self.runtime.scope_stack.borrow_mut().push(scope); let nodes = self.create(template); self.runtime.scope_stack.borrow_mut().pop(); @@ -75,7 +75,7 @@ impl<'b> VirtualDom { } /// Create this template and write its mutations - pub(crate) fn create(&mut self, node: &'b VNode) -> usize { + pub(crate) fn create(&mut self, node: &VNode) -> usize { // check for a overriden template #[cfg(debug_assertions)] { @@ -182,7 +182,7 @@ impl<'b> VirtualDom { 1 } - fn write_dynamic_root(&mut self, template: &'b VNode, idx: usize) -> usize { + fn write_dynamic_root(&mut self, template: &VNode, idx: usize) -> usize { use DynamicNode::*; match &template.dynamic_nodes[idx] { node @ Component { .. } | node @ Fragment(_) => { @@ -232,7 +232,7 @@ impl<'b> VirtualDom { /// We want to make sure we write these nodes while on top of the root fn write_element_root( &mut self, - template: &'b VNode, + template: &VNode, root_idx: usize, dynamic_attrs: &mut Peekable>, dynamic_nodes_iter: &mut Peekable>, @@ -269,7 +269,7 @@ impl<'b> VirtualDom { dynamic_nodes_iter: &mut Peekable>, dynamic_nodes: &[(usize, &'static [u8])], root_idx: u8, - template: &'b VNode, + template: &VNode, ) { let (start, end) = match collect_dyn_node_range(dynamic_nodes_iter, root_idx) { Some((a, b)) => (a, b), @@ -306,7 +306,7 @@ impl<'b> VirtualDom { attrs: &mut Peekable>, root_idx: u8, root: ElementId, - node: &'b VNode, + node: &VNode, ) { while let Some((mut attr_id, path)) = attrs.next_if(|(_, p)| p.first().copied() == Some(root_idx)) @@ -327,9 +327,9 @@ impl<'b> VirtualDom { fn write_attribute( &mut self, - template: &'b VNode, + template: &VNode, idx: usize, - attribute: &'b crate::Attribute<'b>, + attribute: &crate::Attribute, id: ElementId, ) { // Make sure we set the attribute's associated id @@ -355,7 +355,7 @@ impl<'b> VirtualDom { } _ => { // Safety: we promise not to re-alias this text later on after committing it to the mutation - let value: BorrowedAttributeValue<'b> = (&attribute.value).into(); + let value: BorrowedAttributeValue = (&attribute.value).into(); let unbounded_value = unsafe { std::mem::transmute(value) }; self.mutations.push(SetAttribute { @@ -476,35 +476,28 @@ impl<'b> VirtualDom { } } - pub(crate) fn create_dynamic_node( - &mut self, - parent: ElementRef, - node: &'b DynamicNode<'b>, - ) -> usize { + pub(crate) fn create_dynamic_node(&mut self, parent: ElementRef, node: &DynamicNode) -> usize { use DynamicNode::*; match node { Text(text) => self.create_dynamic_text(parent, text), Placeholder(place) => self.create_placeholder(place, parent), Component(component) => self.create_component_node(Some(parent), component), - Fragment(frag) => self.create_children(*frag, Some(parent)), + Fragment(frag) => self.create_children(frag, Some(parent)), } } - fn create_dynamic_text(&mut self, parent: ElementRef, text: &'b VText) -> usize { + fn create_dynamic_text(&mut self, parent: ElementRef, text: &VText) -> usize { // Allocate a dynamic element reference for this text node let new_id = self.next_element(); // Make sure the text node is assigned to the correct element text.id.set(Some(new_id)); - // Safety: we promise not to re-alias this text later on after committing it to the mutation - let value = unsafe { std::mem::transmute(text.value) }; - // Add the mutation to the list self.mutations.push(HydrateText { id: new_id, path: &parent.path.path[1..], - value, + value: &text.value, }); // Since we're hydrating an existing node, we don't create any new nodes @@ -538,7 +531,7 @@ impl<'b> VirtualDom { pub(super) fn create_component_node( &mut self, parent: Option, - component: &'b VComponent, + component: &VComponent, ) -> usize { use RenderReturn::*; @@ -547,7 +540,7 @@ impl<'b> VirtualDom { component.scope.set(Some(scope)); - match unsafe { self.run_scope(scope).extend_lifetime_ref() } { + match self.run_scope(scope) { // Create the component's root element Ready(t) => { self.assign_boundary_ref(parent, t); @@ -561,7 +554,6 @@ impl<'b> VirtualDom { fn load_scope_from_vcomponent(&mut self, component: &VComponent) -> ScopeId { component .props - .take() .map(|props| { let unbounded_props: Box = unsafe { std::mem::transmute(props) }; self.new_scope(unbounded_props, component.name).context().id @@ -578,7 +570,7 @@ impl<'b> VirtualDom { 1 } - fn set_slot(&mut self, slot: &'b Cell>) -> ElementId { + fn set_slot(&mut self, slot: &Cell>) -> ElementId { let id = self.next_element(); slot.set(Some(id)); id diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 971c3977e..fefb9512e 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -16,7 +16,7 @@ use crate::{ use rustc_hash::{FxHashMap, FxHashSet}; use DynamicNode::*; -impl<'b> VirtualDom { +impl VirtualDom { pub(super) fn diff_scope(&mut self, scope: ScopeId) { self.runtime.scope_stack.borrow_mut().push(scope); let scope_state = &mut self.get_scope(scope).unwrap(); @@ -59,7 +59,7 @@ impl<'b> VirtualDom { self.runtime.scope_stack.borrow_mut().pop(); } - fn diff_ok_to_err(&mut self, l: &'b VNode, p: &'b VPlaceholder) { + fn diff_ok_to_err(&mut self, l: &VNode, p: &VPlaceholder) { let id = self.next_element(); p.id.set(Some(id)); p.parent.set(l.parent.get()); @@ -82,7 +82,7 @@ impl<'b> VirtualDom { }; } - fn diff_node(&mut self, left_template: &'b VNode, right_template: &'b VNode) { + fn diff_node(&mut self, left_template: &VNode, right_template: &VNode) { // If hot reloading is enabled, we need to make sure we're using the latest template #[cfg(debug_assertions)] { @@ -166,8 +166,8 @@ impl<'b> VirtualDom { fn diff_dynamic_node( &mut self, - left_node: &'b DynamicNode<'b>, - right_node: &'b DynamicNode<'b>, + left_node: &DynamicNode, + right_node: &DynamicNode, parent: ElementRef, ) { match (left_node, right_node) { @@ -184,9 +184,9 @@ impl<'b> VirtualDom { }; } - fn update_attribute(&mut self, right_attr: &'b Attribute<'b>, left_attr: &'b Attribute) { + fn update_attribute(&mut self, right_attr: &Attribute, left_attr: &Attribute) { let name = unsafe { std::mem::transmute(left_attr.name) }; - let value: BorrowedAttributeValue<'b> = (&right_attr.value).into(); + let value: BorrowedAttributeValue = (&right_attr.value).into(); let value = unsafe { std::mem::transmute(value) }; self.mutations.push(Mutation::SetAttribute { id: left_attr.mounted_element.get(), @@ -198,8 +198,8 @@ impl<'b> VirtualDom { fn diff_vcomponent( &mut self, - left: &'b VComponent, - right: &'b VComponent, + left: &VComponent, + right: &VComponent, parent: Option, ) { if std::ptr::eq(left, right) { @@ -249,8 +249,8 @@ impl<'b> VirtualDom { fn replace_vcomponent( &mut self, - right: &'b VComponent, - left: &'b VComponent, + right: &VComponent, + left: &VComponent, parent: Option, ) { let m = self.create_component_node(parent, right); @@ -307,7 +307,7 @@ impl<'b> VirtualDom { /// Component { ..props } /// } /// ``` - fn light_diff_templates(&mut self, left: &'b VNode, right: &'b VNode) { + fn light_diff_templates(&mut self, left: &VNode, right: &VNode) { let parent = left.parent.take(); match matching_components(left, right) { None => self.replace(left, [right], parent), @@ -321,7 +321,7 @@ impl<'b> VirtualDom { /// /// This just moves the ID of the old node over to the new node, and then sets the text of the new node if it's /// different. - fn diff_vtext(&mut self, left: &'b VText, right: &'b VText) { + fn diff_vtext(&mut self, left: &VText, right: &VText) { let id = left.id.get().unwrap_or_else(|| self.next_element()); right.id.set(Some(id)); @@ -331,7 +331,7 @@ impl<'b> VirtualDom { } } - fn diff_non_empty_fragment(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) { + fn diff_non_empty_fragment(&mut self, old: &[VNode], new: &[VNode], parent: ElementRef) { let new_is_keyed = new[0].key.is_some(); let old_is_keyed = old[0].key.is_some(); debug_assert!( @@ -358,7 +358,7 @@ impl<'b> VirtualDom { // [... parent] // // the change list stack is in the same state when this function returns. - fn diff_non_keyed_children(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) { + fn diff_non_keyed_children(&mut self, old: &[VNode], new: &[VNode], parent: ElementRef) { use std::cmp::Ordering; // Handled these cases in `diff_children` before calling this function. @@ -394,10 +394,10 @@ impl<'b> VirtualDom { // https://github.com/infernojs/inferno/blob/36fd96/packages/inferno/src/DOM/patching.ts#L530-L739 // // The stack is empty upon entry. - fn diff_keyed_children(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) { + fn diff_keyed_children(&mut self, old: &[VNode], new: &[VNode], parent: ElementRef) { if cfg!(debug_assertions) { let mut keys = rustc_hash::FxHashSet::default(); - let mut assert_unique_keys = |children: &'b [VNode]| { + let mut assert_unique_keys = |children: &[VNode]| { keys.clear(); for child in children { let key = child.key; @@ -470,8 +470,8 @@ impl<'b> VirtualDom { /// If there is no offset, then this function returns None and the diffing is complete. fn diff_keyed_ends( &mut self, - old: &'b [VNode], - new: &'b [VNode], + old: &[VNode], + new: &[VNode], parent: ElementRef, ) -> Option<(usize, usize)> { let mut left_offset = 0; @@ -527,7 +527,7 @@ impl<'b> VirtualDom { // // Upon exit from this function, it will be restored to that same self. #[allow(clippy::too_many_lines)] - fn diff_keyed_middle(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) { + fn diff_keyed_middle(&mut self, old: &[VNode], new: &[VNode], parent: ElementRef) { /* 1. Map the old keys into a numerical ordering based on indices. 2. Create a map of old key to its index @@ -709,7 +709,7 @@ impl<'b> VirtualDom { } /// Push all the real nodes on the stack - fn push_all_real_nodes(&mut self, node: &'b VNode) -> usize { + fn push_all_real_nodes(&mut self, node: &VNode) -> usize { node.template .get() .roots @@ -746,12 +746,7 @@ impl<'b> VirtualDom { Component(comp) => { let scope = comp.scope.get().unwrap(); - match unsafe { - self.get_scope(scope) - .unwrap() - .root_node() - .extend_lifetime_ref() - } { + match self.get_scope(scope).unwrap().root_node() { RenderReturn::Ready(node) => self.push_all_real_nodes(node), RenderReturn::Aborted(_node) => todo!(), } @@ -761,9 +756,9 @@ impl<'b> VirtualDom { .sum() } - pub(crate) fn create_children( + pub(crate) fn create_children<'a>( &mut self, - nodes: impl IntoIterator, + nodes: impl IntoIterator, parent: Option, ) -> usize { nodes @@ -775,28 +770,23 @@ impl<'b> VirtualDom { .sum() } - fn create_and_insert_before( - &mut self, - new: &'b [VNode], - before: &'b VNode, - parent: ElementRef, - ) { + fn create_and_insert_before(&mut self, new: &[VNode], before: &VNode, parent: ElementRef) { let m = self.create_children(new, Some(parent)); let id = self.find_first_element(before); self.mutations.push(Mutation::InsertBefore { id, m }) } - fn create_and_insert_after(&mut self, new: &'b [VNode], after: &'b VNode, parent: ElementRef) { + fn create_and_insert_after(&mut self, new: &[VNode], after: &VNode, parent: ElementRef) { let m = self.create_children(new, Some(parent)); let id = self.find_last_element(after); self.mutations.push(Mutation::InsertAfter { id, m }) } /// Simply replace a placeholder with a list of nodes - fn replace_placeholder( + fn replace_placeholder<'a>( &mut self, - l: &'b VPlaceholder, - r: impl IntoIterator, + l: &VPlaceholder, + r: impl IntoIterator, parent: ElementRef, ) { let m = self.create_children(r, Some(parent)); @@ -805,10 +795,10 @@ impl<'b> VirtualDom { self.reclaim(id); } - fn replace( + fn replace<'a>( &mut self, - left: &'b VNode, - right: impl IntoIterator, + left: &VNode, + right: impl IntoIterator, parent: Option, ) { let m = self.create_children(right, parent); @@ -830,7 +820,7 @@ impl<'b> VirtualDom { }; } - fn node_to_placeholder(&mut self, l: &'b [VNode], r: &'b VPlaceholder, parent: ElementRef) { + fn node_to_placeholder(&mut self, l: &[VNode], r: &VPlaceholder, parent: ElementRef) { // Create the placeholder first, ensuring we get a dedicated ID for the placeholder let placeholder = self.next_element(); @@ -853,14 +843,14 @@ impl<'b> VirtualDom { /// Remove these nodes from the dom /// Wont generate mutations for the inner nodes - fn remove_nodes(&mut self, nodes: &'b [VNode]) { + fn remove_nodes(&mut self, nodes: &[VNode]) { nodes .iter() .rev() .for_each(|node| self.remove_node(node, true)); } - fn remove_node(&mut self, node: &'b VNode, gen_muts: bool) { + fn remove_node(&mut self, node: &VNode, gen_muts: bool) { // Clean up any attributes that have claimed a static node as dynamic for mount/unmounta // Will not generate mutations! self.reclaim_attributes(node); @@ -878,7 +868,7 @@ impl<'b> VirtualDom { self.reclaim_vnode_id(node); } - fn reclaim_vnode_id(&mut self, node: &'b VNode) { + fn reclaim_vnode_id(&mut self, node: &VNode) { // Clean up the vnode id if let Some(id) = node.stable_id() { self.element_refs.remove(id.0); @@ -982,12 +972,7 @@ impl<'b> VirtualDom { .expect("VComponents to always have a scope"); // Remove the component from the dom - match unsafe { - self.get_scope(scope) - .unwrap() - .root_node() - .extend_lifetime_ref() - } { + match unsafe { self.get_scope(scope).unwrap().root_node() } { RenderReturn::Ready(t) => self.remove_node(t, gen_muts), RenderReturn::Aborted(placeholder) => self.remove_placeholder(placeholder, gen_muts), }; @@ -1000,7 +985,7 @@ impl<'b> VirtualDom { self.drop_scope(scope, false); } - fn find_first_element(&self, node: &'b VNode) -> ElementId { + fn find_first_element(&self, node: &VNode) -> ElementId { match node.dynamic_root(0) { None => node.root_ids.borrow()[0], Some(Text(t)) => t.id.get().unwrap(), @@ -1008,12 +993,7 @@ impl<'b> VirtualDom { Some(Placeholder(t)) => t.id.get().unwrap(), Some(Component(comp)) => { let scope = comp.scope.get().unwrap(); - match unsafe { - self.get_scope(scope) - .unwrap() - .root_node() - .extend_lifetime_ref() - } { + match unsafe { self.get_scope(scope).unwrap().root_node() } { RenderReturn::Ready(t) => self.find_first_element(t), _ => todo!("cannot handle nonstandard nodes"), } @@ -1021,7 +1001,7 @@ impl<'b> VirtualDom { } } - fn find_last_element(&self, node: &'b VNode) -> ElementId { + fn find_last_element(&self, node: &VNode) -> ElementId { match node.dynamic_root(node.template.get().roots.len() - 1) { None => *node.root_ids.borrow().last().unwrap(), Some(Text(t)) => t.id.get().unwrap(), @@ -1029,12 +1009,7 @@ impl<'b> VirtualDom { Some(Placeholder(t)) => t.id.get().unwrap(), Some(Component(comp)) => { let scope = comp.scope.get().unwrap(); - match unsafe { - self.get_scope(scope) - .unwrap() - .root_node() - .extend_lifetime_ref() - } { + match unsafe { self.get_scope(scope).unwrap().root_node() } { RenderReturn::Ready(t) => self.find_last_element(t), _ => todo!("cannot handle nonstandard nodes"), } @@ -1042,7 +1017,7 @@ impl<'b> VirtualDom { } } - pub(crate) fn assign_boundary_ref(&mut self, parent: Option, child: &'b VNode) { + pub(crate) fn assign_boundary_ref(&mut self, parent: Option, child: &VNode) { if let Some(parent) = parent { // assign the parent of the child child.parent.set(Some(parent)); @@ -1055,7 +1030,7 @@ impl<'b> VirtualDom { /// We need to check for the obvious case, and the non-obvious case where the template as cloned /// /// We use the pointer of the dynamic_node list in this case -fn templates_are_the_same<'b>(left_template: &'b VNode, right_template: &'b VNode) -> bool { +fn templates_are_the_same(left_template: &VNode, right_template: &VNode) -> bool { std::ptr::eq(left_template, right_template) } diff --git a/packages/core/src/error_boundary.rs b/packages/core/src/error_boundary.rs index 30e31b7b8..2901acbca 100644 --- a/packages/core/src/error_boundary.rs +++ b/packages/core/src/error_boundary.rs @@ -1,7 +1,7 @@ use crate::{ scope_context::{consume_context, current_scope_id, schedule_update_any}, - Element, IntoDynNode, LazyNodes, Properties, Scope, ScopeId, ScopeState, Template, - TemplateAttribute, TemplateNode, VNode, + Element, IntoDynNode, Properties, ScopeId, ScopeState, Template, TemplateAttribute, + TemplateNode, VNode, }; use std::{ any::{Any, TypeId}, @@ -262,42 +262,40 @@ impl Throw for Option { } } -pub struct ErrorHandler(Box LazyNodes<'a, 'a>>); -impl<'a, F: Fn(CapturedError) -> LazyNodes<'a, 'a> + 'a> From for ErrorHandler<'a> { +pub struct ErrorHandler(Box Element>); +impl Element> From for ErrorHandler { fn from(value: F) -> Self { Self(Box::new(value)) } } -fn default_handler<'a>(error: CapturedError) -> LazyNodes<'a, 'a> { - LazyNodes::new(move |__cx: &ScopeState| -> VNode { - static TEMPLATE: Template = Template { - name: "error_handle.rs:42:5:884", - roots: &[TemplateNode::Element { - tag: "pre", - namespace: None, - attrs: &[TemplateAttribute::Static { - name: "color", - namespace: Some("style"), - value: "red", - }], - children: &[TemplateNode::DynamicText { id: 0usize }], +fn default_handler(error: CapturedError) -> Element { + static TEMPLATE: Template = Template { + name: "error_handle.rs:42:5:884", + roots: &[TemplateNode::Element { + tag: "pre", + namespace: None, + attrs: &[TemplateAttribute::Static { + name: "color", + namespace: Some("style"), + value: "red", }], - node_paths: &[&[0u8, 0u8]], - attr_paths: &[], - }; - VNode { - parent: Default::default(), - stable_id: Default::default(), - key: None, - template: std::cell::Cell::new(TEMPLATE), - root_ids: Vec::with_capacity(1usize).into(), - dynamic_nodes: __cx - .bump() - .alloc([__cx.text_node(format_args!("{0}", error))]), - dynamic_attrs: __cx.bump().alloc([]), - } + children: &[TemplateNode::DynamicText { id: 0usize }], + }], + node_paths: &[&[0u8, 0u8]], + attr_paths: &[], + }; + Some(VNode { + parent: Default::default(), + stable_id: Default::default(), + key: None, + template: std::cell::Cell::new(TEMPLATE), + root_ids: Vec::with_capacity(1usize).into(), + dynamic_nodes: vec![error.to_string().into_dyn_node()], + dynamic_attrs: Default::default(), }) } + +#[derive(Clone)] pub struct ErrorBoundaryProps { children: Element, handle_error: ErrorHandler, @@ -334,7 +332,7 @@ impl Properties for ErrorBoundaryProps { fn builder() -> Self::Builder { ErrorBoundaryProps::builder() } - unsafe fn memoize(&self, _: &Self) -> bool { + fn memoize(&self, _: &Self) -> bool { false } } @@ -354,16 +352,15 @@ impl ErrorBoundaryPropsBuilder_Optional for (T,) { } } #[allow(dead_code, non_camel_case_types, missing_docs)] -impl<'a, __handle_error> ErrorBoundaryPropsBuilder<'a, ((), __handle_error)> { +impl<__handle_error> ErrorBoundaryPropsBuilder<((), __handle_error)> { pub fn children( self, - children: Element<'a>, - ) -> ErrorBoundaryPropsBuilder<'a, ((Element<'a>,), __handle_error)> { + children: Element, + ) -> ErrorBoundaryPropsBuilder<((Element,), __handle_error)> { let children = (children,); let (_, handle_error) = self.fields; ErrorBoundaryPropsBuilder { fields: (children, handle_error), - _phantom: self._phantom, } } } @@ -372,26 +369,25 @@ impl<'a, __handle_error> ErrorBoundaryPropsBuilder<'a, ((), __handle_error)> { pub enum ErrorBoundaryPropsBuilder_Error_Repeated_field_children {} #[doc(hidden)] #[allow(dead_code, non_camel_case_types, missing_docs)] -impl<'a, __handle_error> ErrorBoundaryPropsBuilder<'a, ((Element<'a>,), __handle_error)> { +impl<__handle_error> ErrorBoundaryPropsBuilder<((Element,), __handle_error)> { #[deprecated(note = "Repeated field children")] pub fn children( self, _: ErrorBoundaryPropsBuilder_Error_Repeated_field_children, - ) -> ErrorBoundaryPropsBuilder<'a, ((Element<'a>,), __handle_error)> { + ) -> ErrorBoundaryPropsBuilder<((Element,), __handle_error)> { self } } #[allow(dead_code, non_camel_case_types, missing_docs)] -impl<'a, __children> ErrorBoundaryPropsBuilder<'a, (__children, ())> { +impl<__children> ErrorBoundaryPropsBuilder<(__children, ())> { pub fn handle_error( self, - handle_error: impl ::core::convert::Into>, - ) -> ErrorBoundaryPropsBuilder<'a, (__children, (ErrorHandler<'a>,))> { + handle_error: impl ::core::convert::Into, + ) -> ErrorBoundaryPropsBuilder<(__children, (ErrorHandler,))> { let handle_error = (handle_error.into(),); let (children, _) = self.fields; ErrorBoundaryPropsBuilder { fields: (children, handle_error), - _phantom: self._phantom, } } } @@ -400,23 +396,22 @@ impl<'a, __children> ErrorBoundaryPropsBuilder<'a, (__children, ())> { pub enum ErrorBoundaryPropsBuilder_Error_Repeated_field_handle_error {} #[doc(hidden)] #[allow(dead_code, non_camel_case_types, missing_docs)] -impl<'a, __children> ErrorBoundaryPropsBuilder<'a, (__children, (ErrorHandler<'a>,))> { +impl<__children> ErrorBoundaryPropsBuilder<(__children, (ErrorHandler,))> { #[deprecated(note = "Repeated field handle_error")] pub fn handle_error( self, _: ErrorBoundaryPropsBuilder_Error_Repeated_field_handle_error, - ) -> ErrorBoundaryPropsBuilder<'a, (__children, (ErrorHandler<'a>,))> { + ) -> ErrorBoundaryPropsBuilder<(__children, (ErrorHandler,))> { self } } #[allow(dead_code, non_camel_case_types, missing_docs)] impl< - 'a, - __handle_error: ErrorBoundaryPropsBuilder_Optional>, - __children: ErrorBoundaryPropsBuilder_Optional>, - > ErrorBoundaryPropsBuilder<'a, (__children, __handle_error)> + __handle_error: ErrorBoundaryPropsBuilder_Optional, + __children: ErrorBoundaryPropsBuilder_Optional, + > ErrorBoundaryPropsBuilder<(__children, __handle_error)> { - pub fn build(self) -> ErrorBoundaryProps<'a> { + pub fn build(self) -> ErrorBoundaryProps { let (children, handle_error) = self.fields; let children = ErrorBoundaryPropsBuilder_Optional::into_value(children, || { ::core::default::Default::default() @@ -453,7 +448,7 @@ impl< /// They are similar to `try/catch` in JavaScript, but they only catch errors in the tree below them. /// Error boundaries are quick to implement, but it can be useful to individually handle errors in your components to provide a better user experience when you know that an error is likely to occur. #[allow(non_upper_case_globals, non_snake_case)] -pub fn ErrorBoundary<'a>(cx: Scope<'a, ErrorBoundaryProps<'a>>) -> Element { +pub fn ErrorBoundary(cx: ErrorBoundaryProps) -> Element { let error_boundary = use_error_boundary(cx); match error_boundary.take_error() { Some(error) => cx.render((cx.props.handle_error.0)(error)), @@ -470,11 +465,8 @@ pub fn ErrorBoundary<'a>(cx: Scope<'a, ErrorBoundaryProps<'a>>) -> Element { stable_id: Default::default(), key: None, template: std::cell::Cell::new(TEMPLATE), - root_ids: bumpalo::collections::Vec::with_capacity_in(1usize, __cx.bump()).into(), - dynamic_nodes: __cx.bump().alloc([{ - let ___nodes = (&cx.props.children).into_dyn_node(__cx); - ___nodes - }]), + root_ids: Vec::with_capacity(1usize).into(), + dynamic_nodes: vec![(&cx.props.children).into_dyn_node()], dynamic_attrs: __cx.bump().alloc([]), } }), diff --git a/packages/core/src/events.rs b/packages/core/src/events.rs index 74e07c914..7e208ba35 100644 --- a/packages/core/src/events.rs +++ b/packages/core/src/events.rs @@ -133,12 +133,12 @@ impl std::fmt::Debug for Event { /// } /// /// ``` -pub struct EventHandler<'bump, T = ()> { +pub struct EventHandler { pub(crate) origin: ScopeId, - pub(super) callback: RefCell>>, + pub(super) callback: RefCell>>, } -impl Default for EventHandler<'_, T> { +impl Default for EventHandler { fn default() -> Self { Self { origin: ScopeId::ROOT, @@ -147,9 +147,9 @@ impl Default for EventHandler<'_, T> { } } -type ExternalListenerCallback<'bump, T> = Box; +type ExternalListenerCallback = Box; -impl EventHandler<'_, T> { +impl EventHandler< T> { /// Call this event handler with the appropriate event type /// /// This borrows the event using a RefCell. Recursively calling a listener will cause a panic. diff --git a/packages/core/src/fragment.rs b/packages/core/src/fragment.rs index e4e1d8660..9f5ad7e16 100644 --- a/packages/core/src/fragment.rs +++ b/packages/core/src/fragment.rs @@ -26,8 +26,8 @@ use crate::innerlude::*; /// /// 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, FragmentProps>) -> Element { - let children = cx.props.0.as_ref()?; +pub fn Fragment(cx: FragmentProps) -> Element { + let children = cx.0.as_ref()?; Some(VNode { key: children.key, parent: children.parent.clone(), @@ -39,7 +39,9 @@ pub fn Fragment<'a>(cx: Scope<'a, FragmentProps>) -> Element { }) } +#[derive(Clone, PartialEq)] pub struct FragmentProps(Element); + pub struct FragmentBuilder(Element); impl FragmentBuilder { pub fn children(self, children: Element) -> FragmentBuilder { @@ -92,7 +94,7 @@ impl FragmentBuilder { /// }) /// } /// ``` -impl<'a> Properties for FragmentProps { +impl Properties for FragmentProps { type Builder = FragmentBuilder; fn builder() -> Self::Builder { FragmentBuilder(None) diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 8690d9a31..feecc0590 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -11,7 +11,6 @@ mod dirty_scope; mod error_boundary; mod events; mod fragment; -mod lazynodes; mod mutations; mod nodes; mod properties; @@ -28,7 +27,6 @@ pub(crate) mod innerlude { pub use crate::error_boundary::*; pub use crate::events::*; pub use crate::fragment::*; - pub use crate::lazynodes::*; pub use crate::mutations::*; pub use crate::nodes::RenderReturn; pub use crate::nodes::*; @@ -71,15 +69,14 @@ pub(crate) mod innerlude { /// Example {} /// ) /// ``` - pub type Component

= fn(Scope

) -> Element; + pub type Component

= fn(P) -> Element; } pub use crate::innerlude::{ fc_to_builder, vdom_is_rendering, AnyValue, Attribute, AttributeValue, BorrowedAttributeValue, CapturedError, Component, DynamicNode, Element, ElementId, Event, Fragment, IntoDynNode, - LazyNodes, Mutation, Mutations, Properties, RenderReturn, Scope, ScopeId, ScopeState, Scoped, - TaskId, Template, TemplateAttribute, TemplateNode, VComponent, VNode, VPlaceholder, VText, - VirtualDom, + Mutation, Mutations, Properties, RenderReturn, ScopeId, ScopeState, TaskId, Template, + TemplateAttribute, TemplateNode, VComponent, VNode, VPlaceholder, VText, VirtualDom, }; /// The purpose of this module is to alleviate imports of many common types @@ -91,8 +88,7 @@ pub mod prelude { provide_context, provide_context_to_scope, provide_root_context, push_future, remove_future, schedule_update_any, spawn, spawn_forever, suspend, use_error_boundary, AnyValue, Component, Element, ErrorBoundary, Event, EventHandler, Fragment, - IntoAttributeValue, IntoDynNode, LazyNodes, Properties, Runtime, RuntimeGuard, Scope, - ScopeId, ScopeState, Scoped, TaskId, Template, TemplateAttribute, TemplateNode, Throw, - VNode, VirtualDom, + IntoAttributeValue, IntoDynNode, Properties, Runtime, RuntimeGuard, ScopeId, ScopeState, + TaskId, Template, TemplateAttribute, TemplateNode, Throw, VNode, VirtualDom, }; } diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index 692520b3e..67403b9ec 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -1,9 +1,5 @@ use crate::innerlude::{ElementRef, VNodeId}; -use crate::{ - any_props::AnyProps, arena::ElementId, Element, Event, LazyNodes, ScopeId, ScopeState, -}; -use bumpalo::boxed::Box as BumpBox; -use bumpalo::Bump; +use crate::{any_props::AnyProps, arena::ElementId, Element, Event, ScopeId, ScopeState}; use std::{ any::{Any, TypeId}, cell::{Cell, RefCell}, @@ -91,8 +87,8 @@ impl VNode { key: Option, template: Template<'static>, root_ids: Vec, - dynamic_nodes: &'a [DynamicNode], - dynamic_attrs: &'a [Attribute], + dynamic_nodes: Vec, + dynamic_attrs: Vec, ) -> Self { Self { key, @@ -113,7 +109,7 @@ impl VNode { /// Load a dynamic root at the given index /// /// Returns [`None`] if the root is actually a static node (Element/Text) - pub fn dynamic_root(&self, idx: usize) -> Option<&'a DynamicNode> { + pub fn dynamic_root(&self, idx: usize) -> Option<&DynamicNode> { match &self.template.get().roots[idx] { TemplateNode::Element { .. } | TemplateNode::Text { text: _ } => None, TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => { @@ -297,7 +293,7 @@ pub enum TemplateNode { /// A node created at runtime /// /// This node's index in the DynamicNode list on VNode should match its repsective `Dynamic` index -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum DynamicNode { /// A component node /// @@ -322,7 +318,7 @@ pub enum DynamicNode { /// /// Note that this is not a list of dynamic nodes. These must be VNodes and created through conditional rendering /// or iterators. - Fragment(&'static [VNode]), + Fragment(Vec), } impl Default for DynamicNode { @@ -331,6 +327,7 @@ impl Default for DynamicNode { } } +#[derive(Clone)] /// An instance of a child component pub struct VComponent { /// The name of this component @@ -344,7 +341,7 @@ pub struct VComponent { /// It is possible that components get folded at compile time, so these shouldn't be really used as a key pub(crate) render_fn: *const (), - pub(crate) props: RefCell>>, + pub(crate) props: Box, } impl<'a> VComponent { @@ -662,89 +659,78 @@ impl AnyValue for T { } /// A trait that allows various items to be converted into a dynamic node for the rsx macro -pub trait IntoDynNode<'a, A = ()> { +pub trait IntoDynNode { /// Consume this item along with a scopestate and produce a DynamicNode /// /// You can use the bump alloactor of the scopestate to creat the dynamic node - fn into_dyn_node(self, cx: &'a ScopeState) -> DynamicNode; + fn into_dyn_node(self) -> DynamicNode; } -impl<'a> IntoDynNode<'a> for () { - fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { +impl IntoDynNode for () { + fn into_dyn_node(self) -> DynamicNode { DynamicNode::default() } } -impl<'a> IntoDynNode<'a> for VNode { - fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { - DynamicNode::Fragment(_cx.bump().alloc([self])) +impl IntoDynNode for VNode { + fn into_dyn_node(self) -> DynamicNode { + DynamicNode::Fragment(vec![self]) } } -impl<'a> IntoDynNode<'a> for DynamicNode { - fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { +impl IntoDynNode for DynamicNode { + fn into_dyn_node(self) -> DynamicNode { self } } -impl<'a, T: IntoDynNode<'a>> IntoDynNode<'a> for Option { - fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { +impl IntoDynNode for Option { + fn into_dyn_node(self) -> DynamicNode { match self { - Some(val) => val.into_dyn_node(_cx), + Some(val) => val.into_dyn_node(), None => DynamicNode::default(), } } } -impl<'a> IntoDynNode<'a> for &Element { - fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { +impl IntoDynNode for &Element { + fn into_dyn_node(self) -> DynamicNode { match self.as_ref() { - Some(val) => val.clone().into_dyn_node(_cx), + Some(val) => val.clone().into_dyn_node(), _ => DynamicNode::default(), } } } -impl<'a, 'b> IntoDynNode<'a> for LazyNodes<'a, 'b> { - fn into_dyn_node(self, cx: &'a ScopeState) -> DynamicNode { - DynamicNode::Fragment(cx.bump().alloc([cx.render(self).unwrap()])) - } -} - -impl<'a, 'b> IntoDynNode<'b> for &'a str { - fn into_dyn_node(self, cx: &'b ScopeState) -> DynamicNode { +impl IntoDynNode for &str { + fn into_dyn_node(self) -> DynamicNode { DynamicNode::Text(VText { - value: cx.bump().alloc_str(self), + value: self.to_string(), id: Default::default(), }) } } -impl IntoDynNode<'_> for String { - fn into_dyn_node(self, cx: &ScopeState) -> DynamicNode { +impl IntoDynNode for String { + fn into_dyn_node(self) -> DynamicNode { DynamicNode::Text(VText { - value: cx.bump().alloc_str(&self), + value: self, id: Default::default(), }) } } -impl<'b> IntoDynNode<'b> for Arguments<'_> { - fn into_dyn_node(self, cx: &'b ScopeState) -> DynamicNode { - cx.text_node(self) +impl<'b> IntoDynNode for Arguments<'_> { + fn into_dyn_node(self) -> DynamicNode { + DynamicNode::Text(VText { + value: self.to_string(), + id: Default::default(), + }) } } -impl<'a> IntoDynNode<'a> for &'a VNode { - fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { - DynamicNode::Fragment(_cx.bump().alloc([VNode { - parent: self.parent.clone(), - stable_id: self.stable_id.clone(), - template: self.template.clone(), - root_ids: self.root_ids.clone(), - key: self.key, - dynamic_nodes: self.dynamic_nodes, - dynamic_attrs: self.dynamic_attrs, - }])) +impl IntoDynNode for &VNode { + fn into_dyn_node(self) -> DynamicNode { + DynamicNode::Fragment(vec![self.clone()]) } } @@ -759,97 +745,88 @@ impl<'a> IntoVNode for VNode { impl<'a> IntoVNode for Element { fn into_vnode(self) -> VNode { match self { - Some(val) => val.into_vnode(cx), + Some(val) => val.into_vnode(), _ => VNode::empty().unwrap(), } } } -impl<'a, 'b> IntoVNode for LazyNodes<'a, 'b> { - fn into_vnode(self) -> VNode { - cx.render(self).unwrap() - } -} // Note that we're using the E as a generic but this is never crafted anyways. pub struct FromNodeIterator; -impl<'a, T, I> IntoDynNode<'a, FromNodeIterator> for T +impl IntoDynNode for T where T: Iterator, I: IntoVNode, { - fn into_dyn_node(self, cx: &'a ScopeState) -> DynamicNode { - let mut nodes = bumpalo::collections::Vec::new_in(cx.bump()); + fn into_dyn_node(self) -> DynamicNode { + let mut children: Vec<_> = self.into_iter().map(|node| node.into_vnode()).collect(); - nodes.extend(self.into_iter().map(|node| node.into_vnode(cx))); - - match nodes.into_bump_slice() { - children if children.is_empty() => DynamicNode::default(), - children => DynamicNode::Fragment(children), + if children.is_empty() { + DynamicNode::default() + } else { + DynamicNode::Fragment(children) } } } /// A value that can be converted into an attribute value -pub trait IntoAttributeValue<'a> { +pub trait IntoAttributeValue { /// Convert into an attribute value - fn into_value(self, bump: &'a Bump) -> AttributeValue<'a>; + fn into_value(self) -> AttributeValue; } -impl<'a> IntoAttributeValue<'a> for AttributeValue<'a> { - fn into_value(self, _: &'a Bump) -> AttributeValue<'a> { +impl<'a> IntoAttributeValue for AttributeValue { + fn into_value(self) -> AttributeValue { self } } -impl<'a> IntoAttributeValue<'a> for &'a str { - fn into_value(self, _: &'a Bump) -> AttributeValue<'a> { +impl<'a> IntoAttributeValue for &'a str { + fn into_value(self) -> AttributeValue { + AttributeValue::Text(self.to_string()) + } +} + +impl<'a> IntoAttributeValue for String { + fn into_value(self) -> AttributeValue { AttributeValue::Text(self) } } -impl<'a> IntoAttributeValue<'a> for String { - fn into_value(self, cx: &'a Bump) -> AttributeValue<'a> { - AttributeValue::Text(cx.alloc_str(&self)) - } -} - -impl<'a> IntoAttributeValue<'a> for f64 { - fn into_value(self, _: &'a Bump) -> AttributeValue<'a> { +impl<'a> IntoAttributeValue for f64 { + fn into_value(self) -> AttributeValue { AttributeValue::Float(self) } } -impl<'a> IntoAttributeValue<'a> for i64 { - fn into_value(self, _: &'a Bump) -> AttributeValue<'a> { +impl<'a> IntoAttributeValue for i64 { + fn into_value(self) -> AttributeValue { AttributeValue::Int(self) } } -impl<'a> IntoAttributeValue<'a> for bool { - fn into_value(self, _: &'a Bump) -> AttributeValue<'a> { +impl<'a> IntoAttributeValue for bool { + fn into_value(self) -> AttributeValue { AttributeValue::Bool(self) } } -impl<'a> IntoAttributeValue<'a> for Arguments<'_> { - fn into_value(self, bump: &'a Bump) -> AttributeValue<'a> { - use bumpalo::core_alloc::fmt::Write; - let mut str_buf = bumpalo::collections::String::new_in(bump); - str_buf.write_fmt(self).unwrap(); - AttributeValue::Text(str_buf.into_bump_str()) +impl<'a> IntoAttributeValue for Arguments<'_> { + fn into_value(self) -> AttributeValue { + AttributeValue::Text(self.to_string()) } } -impl<'a> IntoAttributeValue<'a> for BumpBox<'a, dyn AnyValue> { - fn into_value(self, _: &'a Bump) -> AttributeValue<'a> { +impl IntoAttributeValue for Box { + fn into_value(self) -> AttributeValue { AttributeValue::Any(RefCell::new(Some(self))) } } -impl<'a, T: IntoAttributeValue<'a>> IntoAttributeValue<'a> for Option { - fn into_value(self, bump: &'a Bump) -> AttributeValue<'a> { +impl<'a, T: IntoAttributeValue> IntoAttributeValue for Option { + fn into_value(self) -> AttributeValue { match self { - Some(val) => val.into_value(bump), + Some(val) => val.into_value(), None => AttributeValue::None, } } diff --git a/packages/core/src/properties.rs b/packages/core/src/properties.rs index ada5e58d5..7eb3ea85e 100644 --- a/packages/core/src/properties.rs +++ b/packages/core/src/properties.rs @@ -66,7 +66,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(_: fn(T) -> Element) -> T::Builder { T::builder() } diff --git a/packages/core/src/scope_arena.rs b/packages/core/src/scope_arena.rs index b8daeb7cb..3666a40a5 100644 --- a/packages/core/src/scope_arena.rs +++ b/packages/core/src/scope_arena.rs @@ -62,7 +62,7 @@ impl VirtualDom { let props: &dyn AnyProps = std::mem::transmute(props); let _span = tracing::trace_span!("render", scope = %scope.context().name); - props.render(scope).extend_lifetime() + props.render(scope) }; let scope = &self.scopes[scope_id.0]; @@ -93,7 +93,7 @@ impl VirtualDom { } // rebind the lifetime now that its stored internally - let result = unsafe { allocated.extend_lifetime_ref() }; + let result = unsafe { allocated }; self.runtime.scope_stack.borrow_mut().pop(); diff --git a/packages/core/src/scopes.rs b/packages/core/src/scopes.rs index ffdd895f5..980a85fe1 100644 --- a/packages/core/src/scopes.rs +++ b/packages/core/src/scopes.rs @@ -1,7 +1,6 @@ use crate::{ any_props::AnyProps, any_props::VProps, - innerlude::ErrorBoundary, innerlude::{DynamicNode, EventHandler, VComponent, VNodeId, VText}, nodes::{IntoAttributeValue, IntoDynNode, RenderReturn}, runtime::Runtime, @@ -17,40 +16,6 @@ use std::{ sync::Arc, }; -/// A wrapper around the [`Scoped`] object that contains a reference to the [`ScopeState`] and properties for a given -/// component. -/// -/// The [`Scope`] is your handle to the [`crate::VirtualDom`] and the component state. Every component is given its own -/// [`ScopeState`] and merged with its properties to create a [`Scoped`]. -/// -/// The [`Scope`] handle specifically exists to provide a stable reference to these items for the lifetime of the -/// component render. -pub type Scope<'a, T = ()> = &'a Scoped<'a, T>; - -// This ScopedType exists because we want to limit the amount of monomorphization that occurs when making inner -// state type generic over props. When the state is generic, it causes every method to be monomorphized for every -// instance of Scope in the codebase. -// -// -/// A wrapper around a component's [`ScopeState`] and properties. The [`ScopeState`] provides the majority of methods -/// for the VirtualDom and component state. -pub struct Scoped<'a, T = ()> { - /// The component's state and handle to the scheduler. - /// - /// Stores things like the custom bump arena, spawn functions, hooks, and the scheduler. - pub scope: &'a ScopeState, - - /// The component's properties. - pub props: &'a T, -} - -impl<'a, T> std::ops::Deref for Scoped<'a, T> { - type Target = &'a ScopeState; - fn deref(&self) -> &Self::Target { - &self.scope - } -} - /// A component's unique identifier. /// /// `ScopeId` is a `usize` that acts a key for the internal slab of Scopes. This means that the key is not unqiue across @@ -300,69 +265,17 @@ impl<'src> ScopeState { self.context().remove_future(id); } - /// Take a lazy [`crate::VNode`] structure and actually build it with the context of the efficient [`bumpalo::Bump`] allocator. - /// - /// ## Example - /// - /// ```ignore - /// fn Component(cx: Scope) -> Element { - /// // Lazy assemble the VNode tree - /// let lazy_nodes = rsx!("hello world"); - /// - /// // Actually build the tree and allocate it - /// cx.render(lazy_tree) - /// } - ///``` - pub fn render(&'src self, rsx: LazyNodes<'src, '_>) -> Element { - let element = rsx.call(self); - - let mut listeners = self.attributes_to_drop_before_render.borrow_mut(); - for attr in element.dynamic_attrs { - match attr.value { - // We need to drop listeners before the next render because they may borrow data from the borrowed props which will be dropped - AttributeValue::Listener(_) => { - let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) }; - listeners.push(unbounded); - } - // We need to drop any values manually to make sure that their drop implementation is called before the next render - AttributeValue::Any(_) => { - let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) }; - self.previous_frame().add_attribute_to_drop(unbounded); - } - - _ => (), - } - } - - let mut props = self.borrowed_props.borrow_mut(); - let mut drop_props = self - .previous_frame() - .props_to_drop_before_reset - .borrow_mut(); - for node in element.dynamic_nodes { - if let DynamicNode::Component(comp) = node { - let unbounded = unsafe { std::mem::transmute(comp as *const VComponent) }; - if !comp.static_props { - props.push(unbounded); - } - drop_props.push(unbounded); - } - } - - Some(element) - } - /// Create a dynamic text node using [`Arguments`] and the [`ScopeState`]'s internal [`Bump`] allocator pub fn text_node(&'src self, args: Arguments) -> DynamicNode { DynamicNode::Text(VText { - value: self.raw_text(args), + value: args.to_string(), id: Default::default(), }) } /// Convert any item that implements [`IntoDynNode`] into a [`DynamicNode`] using the internal [`Bump`] allocator - pub fn make_node<'c, I>(&'src self, into: impl IntoDynNode<'src, I> + 'c) -> DynamicNode { - into.into_dyn_node(self) + pub fn make_node<'c, I>(&'src self, into: impl IntoDynNode + 'c) -> DynamicNode { + into.into_dyn_node() } /// Create a new [`Attribute`] from a name, value, namespace, and volatile bool @@ -372,7 +285,7 @@ impl<'src> ScopeState { pub fn attr( &'src self, name: &'static str, - value: impl IntoAttributeValue<'src>, + value: impl IntoAttributeValue, namespace: Option<&'static str>, volatile: bool, ) -> Attribute { @@ -381,7 +294,7 @@ impl<'src> ScopeState { namespace, volatile, mounted_element: Default::default(), - value: value.into_value(self.bump()), + value: value.into_value(), } } @@ -399,37 +312,35 @@ impl<'src> ScopeState { /// fn(Scope) -> Element; /// async fn(Scope>) -> Element; /// ``` - pub fn component<'child, P>( - &'src self, - component: fn(Scope<'child, P>) -> Element, + pub fn component

( + &self, + component: fn(P) -> Element, props: P, fn_name: &'static str, ) -> DynamicNode where // The properties must be valid until the next bump frame - P: Properties + 'src, - // The current bump allocator frame must outlive the child's borrowed props - 'src: 'child, + P: Properties, { let vcomp = VProps::new(component, P::memoize, props); // cast off the lifetime of the render return - let as_dyn: Box = Box::new(vcomp); - let extended: Box = unsafe { std::mem::transmute(as_dyn) }; + let as_dyn: Box = Box::new(vcomp); + let extended: Box = unsafe { std::mem::transmute(as_dyn) }; DynamicNode::Component(VComponent { name: fn_name, render_fn: component as *const (), - props: RefCell::new(Some(extended)), + props: extended, scope: Default::default(), }) } /// Create a new [`EventHandler`] from an [`FnMut`] - pub fn event_handler(&'src self, f: impl FnMut(T) + 'src) -> EventHandler<'src, T> { - let callback = RefCell::new(Some(Box::new(move |event: Event| { - f(event.data); - }))); + pub fn event_handler(&self, f: impl FnMut(T)) -> EventHandler { + let callback = RefCell::new(Some(Box::new(move |event: T| { + f(event); + }) as Box)); EventHandler { callback, origin: self.context().id, diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index ec1f0dfe5..a66e4aa20 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -11,7 +11,7 @@ use crate::{ nodes::{Template, TemplateId}, runtime::{Runtime, RuntimeGuard}, scopes::{ScopeId, ScopeState}, - AttributeValue, Element, Event, Scope, VNode, + AttributeValue, Element, Event, VNode, }; use futures_util::{pin_mut, StreamExt}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -76,7 +76,7 @@ use std::{ /// } /// /// #[component] -/// fn Title<'a>(cx: Scope<'a>, children: Element<'a>) -> Element { +/// fn Title<'a>(cx: Scope<'a>, children: Element) -> Element { /// cx.render(rsx! { /// div { id: "title", children } /// }) @@ -224,7 +224,7 @@ impl VirtualDom { /// ``` /// /// Note: the VirtualDom is not progressed, you must either "run_with_deadline" or use "rebuild" to progress it. - pub fn new(app: fn(Scope) -> Element) -> Self { + pub fn new(app: fn() -> Element) -> Self { Self::new_with_props(app, ()) } @@ -258,7 +258,7 @@ impl VirtualDom { /// let mut dom = VirtualDom::new_with_props(Example, SomeProps { name: "jane" }); /// let mutations = dom.rebuild(); /// ``` - pub fn new_with_props(root: fn(Scope

) -> Element, root_props: P) -> Self { + pub fn new_with_props(root: fn(P) -> Element, root_props: P) -> Self { let (tx, rx) = futures_channel::mpsc::unbounded(); let scheduler = Scheduler::new(tx); let mut dom = Self { @@ -567,7 +567,7 @@ impl VirtualDom { /// ``` pub fn rebuild(&mut self) -> Mutations { let _runtime = RuntimeGuard::new(self.runtime.clone()); - match unsafe { self.run_scope(ScopeId::ROOT).extend_lifetime_ref() } { + match unsafe { self.run_scope(ScopeId::ROOT) } { // Rebuilding implies we append the created elements to the root RenderReturn::Ready(node) => { let m = self.create_scope(ScopeId::ROOT, node); diff --git a/packages/core/tests/create_dom.rs b/packages/core/tests/create_dom.rs index 5e5005d3f..4bd232b98 100644 --- a/packages/core/tests/create_dom.rs +++ b/packages/core/tests/create_dom.rs @@ -142,7 +142,7 @@ fn create_components() { #[derive(Props)] struct ChildProps<'a> { - children: Element<'a>, + children: Element, } fn Child<'a>(cx: Scope<'a, ChildProps<'a>>) -> Element { diff --git a/packages/core/tests/create_passthru.rs b/packages/core/tests/create_passthru.rs index 4311cf1b1..01830f6ed 100644 --- a/packages/core/tests/create_passthru.rs +++ b/packages/core/tests/create_passthru.rs @@ -19,7 +19,7 @@ fn nested_passthru_creates() { } #[component] - fn PassThru<'a>(cx: Scope<'a>, children: Element<'a>) -> Element { + fn PassThru<'a>(cx: Scope<'a>, children: Element) -> Element { cx.render(rsx!(children)) } @@ -59,7 +59,7 @@ fn nested_passthru_creates_add() { } #[component] - fn ChildComp<'a>(cx: Scope, children: Element<'a>) -> Element { + fn ChildComp<'a>(cx: Scope, children: Element) -> Element { cx.render(rsx! { children }) } diff --git a/packages/core/tests/fuzzing.rs b/packages/core/tests/fuzzing.rs index 65d131eb8..02017307f 100644 --- a/packages/core/tests/fuzzing.rs +++ b/packages/core/tests/fuzzing.rs @@ -15,7 +15,7 @@ fn random_ns() -> Option<&'static str> { } } -fn create_random_attribute(attr_idx: &mut usize) -> TemplateAttribute<'static> { +fn create_random_attribute(attr_idx: &mut usize) -> TemplateAttribute { match rand::random::() % 2 { 0 => TemplateAttribute::Static { name: Box::leak(format!("attr{}", rand::random::()).into_boxed_str()), @@ -238,7 +238,7 @@ struct BorrowedDepthProps<'a> { inner: DepthProps, } -fn create_random_element_borrowed<'a>(cx: Scope<'a, BorrowedDepthProps<'a>>) -> Element<'a> { +fn create_random_element_borrowed<'a>(cx: Scope<'a, BorrowedDepthProps<'a>>) -> Element { println!("{}", cx.props.borrow); let bump = cx.bump(); let allocated = bump.alloc(Scoped { scope: cx, props: &cx.props.inner });