瀏覽代碼

remove more lifetimes

Evan Almloff 1 年之前
父節點
當前提交
f42ef3ef9d

+ 2 - 2
packages/core/compile_tests/props_safety.rs

@@ -14,10 +14,10 @@ fn app(cx: Scope) -> Element {
 
 #[derive(Props)]
 struct Testing<'a> {
-    borrowed: &'a RefCell<Vec<Element<'a>>>,
+    borrowed: &'a RefCell<Vec<Element>>,
 }
 
-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"));

+ 1 - 1
packages/core/compile_tests/props_safety_temporary_values.rs

@@ -17,7 +17,7 @@ struct Testing<'a> {
     borrowed: &'a Vec<u32>,
 }
 
-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:?}" }
     })

+ 14 - 35
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<P> {
+    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<P> VProps<P> {
+    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<P: Clone> AnyProps for VProps<P> {
     // 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<P> = cx.bump().alloc(Scoped {
-                props: &self.props,
-                scope: cx,
-            });
-
-            (self.render_fn)(scope)
+            (self.render_fn)(self.props.clone())
         }));
 
         match res {

+ 1 - 5
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();

+ 17 - 25
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<impl Iterator<Item = (usize, &'static [u8])>>,
         dynamic_nodes_iter: &mut Peekable<impl Iterator<Item = ((usize, usize), &'static [u8])>>,
@@ -269,7 +269,7 @@ impl<'b> VirtualDom {
         dynamic_nodes_iter: &mut Peekable<impl Iterator<Item = ((usize, usize), &'static [u8])>>,
         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<impl Iterator<Item = (usize, &'static [u8])>>,
         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<ElementRef>,
-        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<dyn AnyProps> = 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<Option<ElementId>>) -> ElementId {
+    fn set_slot(&mut self, slot: &Cell<Option<ElementId>>) -> ElementId {
         let id = self.next_element();
         slot.set(Some(id));
         id

+ 43 - 68
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<ElementRef>,
     ) {
         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<ElementRef>,
     ) {
         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<Item = &'b VNode>,
+        nodes: impl IntoIterator<Item = &'a VNode>,
         parent: Option<ElementRef>,
     ) -> 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<Item = &'b VNode>,
+        l: &VPlaceholder,
+        r: impl IntoIterator<Item = &'a VNode>,
         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<Item = &'b VNode>,
+        left: &VNode,
+        right: impl IntoIterator<Item = &'a VNode>,
         parent: Option<ElementRef>,
     ) {
         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<ElementRef>, child: &'b VNode) {
+    pub(crate) fn assign_boundary_ref(&mut self, parent: Option<ElementRef>, 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)
 }
 

+ 47 - 55
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<T> Throw for Option<T> {
     }
 }
 
-pub struct ErrorHandler(Box<dyn Fn(CapturedError) -> LazyNodes<'a, 'a>>);
-impl<'a, F: Fn(CapturedError) -> LazyNodes<'a, 'a> + 'a> From<F> for ErrorHandler<'a> {
+pub struct ErrorHandler(Box<dyn Fn(CapturedError) -> Element>);
+impl<F: Fn(CapturedError) -> Element> From<F> 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<T> ErrorBoundaryPropsBuilder_Optional<T> 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<ErrorHandler<'a>>,
-    ) -> ErrorBoundaryPropsBuilder<'a, (__children, (ErrorHandler<'a>,))> {
+        handle_error: impl ::core::convert::Into<ErrorHandler>,
+    ) -> 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<ErrorHandler<'a>>,
-        __children: ErrorBoundaryPropsBuilder_Optional<Element<'a>>,
-    > ErrorBoundaryPropsBuilder<'a, (__children, __handle_error)>
+        __handle_error: ErrorBoundaryPropsBuilder_Optional<ErrorHandler>,
+        __children: ErrorBoundaryPropsBuilder_Optional<Element>,
+    > 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([]),
             }
         }),

+ 5 - 5
packages/core/src/events.rs

@@ -133,12 +133,12 @@ impl<T: std::fmt::Debug> std::fmt::Debug for Event<T> {
 /// }
 ///
 /// ```
-pub struct EventHandler<'bump, T = ()> {
+pub struct EventHandler<T = ()> {
     pub(crate) origin: ScopeId,
-    pub(super) callback: RefCell<Option<ExternalListenerCallback<'bump, T>>>,
+    pub(super) callback: RefCell<Option<ExternalListenerCallback<T>>>,
 }
 
-impl<T> Default for EventHandler<'_, T> {
+impl<T> Default for EventHandler<T> {
     fn default() -> Self {
         Self {
             origin: ScopeId::ROOT,
@@ -147,9 +147,9 @@ impl<T> Default for EventHandler<'_, T> {
     }
 }
 
-type ExternalListenerCallback<'bump, T> = Box<dyn FnMut(T)>;
+type ExternalListenerCallback<T> = Box<dyn FnMut(T)>;
 
-impl<T> EventHandler<'_, T> {
+impl<T> 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.

+ 5 - 3
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<const BUILT: bool>(Element);
 impl FragmentBuilder<false> {
     pub fn children(self, children: Element) -> FragmentBuilder<true> {
@@ -92,7 +94,7 @@ impl<const A: bool> FragmentBuilder<A> {
 ///     })
 /// }
 /// ```
-impl<'a> Properties for FragmentProps {
+impl Properties for FragmentProps {
     type Builder = FragmentBuilder<false>;
     fn builder() -> Self::Builder {
         FragmentBuilder(None)

+ 5 - 9
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<P = ()> = fn(Scope<P>) -> Element;
+    pub type Component<P = ()> = 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,
     };
 }

+ 70 - 93
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<String>,
         template: Template<'static>,
         root_ids: Vec<ElementId>,
-        dynamic_nodes: &'a [DynamicNode],
-        dynamic_attrs: &'a [Attribute],
+        dynamic_nodes: Vec<DynamicNode>,
+        dynamic_attrs: Vec<Attribute>,
     ) -> 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<VNode>),
 }
 
 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<Option<Box<dyn AnyProps>>>,
+    pub(crate) props: Box<dyn AnyProps>,
 }
 
 impl<'a> VComponent {
@@ -662,89 +659,78 @@ impl<T: Any + PartialEq + 'static> 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<A = ()> {
     /// 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<T> {
-    fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode {
+impl<T: IntoDynNode> IntoDynNode for Option<T> {
+    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<T, I> IntoDynNode<FromNodeIterator> for T
 where
     T: Iterator<Item = I>,
     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> {
-        AttributeValue::Text(self)
+impl<'a> IntoAttributeValue for &'a str {
+    fn into_value(self) -> AttributeValue {
+        AttributeValue::Text(self.to_string())
     }
 }
 
-impl<'a> IntoAttributeValue<'a> for String {
-    fn into_value(self, cx: &'a Bump) -> AttributeValue<'a> {
-        AttributeValue::Text(cx.alloc_str(&self))
+impl<'a> IntoAttributeValue for String {
+    fn into_value(self) -> AttributeValue {
+        AttributeValue::Text(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<dyn AnyValue> {
+    fn into_value(self) -> AttributeValue {
         AttributeValue::Any(RefCell::new(Some(self)))
     }
 }
 
-impl<'a, T: IntoAttributeValue<'a>> IntoAttributeValue<'a> for Option<T> {
-    fn into_value(self, bump: &'a Bump) -> AttributeValue<'a> {
+impl<'a, T: IntoAttributeValue> IntoAttributeValue for Option<T> {
+    fn into_value(self) -> AttributeValue {
         match self {
-            Some(val) => val.into_value(bump),
+            Some(val) => val.into_value(),
             None => AttributeValue::None,
         }
     }

+ 1 - 1
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<T: Properties>(_: fn(T) -> Element) -> T::Builder {
     T::builder()
 }
 

+ 2 - 2
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();
 

+ 16 - 105
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<T> 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<Props>) -> 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<I> + '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<Props>) -> Element;
     /// async fn(Scope<Props<'_>>) -> Element;
     /// ```
-    pub fn component<'child, P>(
-        &'src self,
-        component: fn(Scope<'child, P>) -> Element,
+    pub fn component<P>(
+        &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<dyn AnyProps + '_> = Box::new(vcomp);
-        let extended: Box<dyn AnyProps + 'src> = unsafe { std::mem::transmute(as_dyn) };
+        let as_dyn: Box<dyn AnyProps> = Box::new(vcomp);
+        let extended: Box<dyn AnyProps> = 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<T>(&'src self, f: impl FnMut(T) + 'src) -> EventHandler<'src, T> {
-        let callback = RefCell::new(Some(Box::new(move |event: Event<T>| {
-            f(event.data);
-        })));
+    pub fn event_handler<T>(&self, f: impl FnMut(T)) -> EventHandler<T> {
+        let callback = RefCell::new(Some(Box::new(move |event: T| {
+            f(event);
+        }) as Box<dyn FnMut(T)>));
         EventHandler {
             callback,
             origin: self.context().id,

+ 5 - 5
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<P: 'static>(root: fn(Scope<P>) -> Element, root_props: P) -> Self {
+    pub fn new_with_props<P: 'static>(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);

+ 1 - 1
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 {

+ 2 - 2
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 })
     }
 

+ 2 - 2
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::<u8>() % 2 {
         0 => TemplateAttribute::Static {
             name: Box::leak(format!("attr{}", rand::random::<usize>()).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 });