From 3ad16ddd375a8a2926980ee815a8bb12a09918f0 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 4 Jan 2024 18:33:01 -0600 Subject: [PATCH] rip out more lifetimes --- packages/core/Cargo.toml | 3 - packages/core/src/any_props.rs | 6 +- packages/core/src/bump_frame.rs | 76 ------------- packages/core/src/create.rs | 18 ++-- packages/core/src/diff.rs | 93 ++++++---------- packages/core/src/error_boundary.rs | 30 +++--- packages/core/src/events.rs | 2 +- packages/core/src/fragment.rs | 6 +- packages/core/src/lazynodes.rs | 101 ------------------ packages/core/src/lib.rs | 9 +- packages/core/src/nodes.rs | 160 +++++++++++++--------------- packages/core/src/properties.rs | 4 +- packages/core/src/scope_arena.rs | 6 +- packages/core/src/scope_context.rs | 2 +- packages/core/src/scopes.rs | 95 ++++------------- packages/core/src/virtual_dom.rs | 6 +- packages/html/src/events.rs | 2 +- packages/html/src/events/mouse.rs | 2 +- 18 files changed, 165 insertions(+), 456 deletions(-) delete mode 100644 packages/core/src/bump_frame.rs delete mode 100644 packages/core/src/lazynodes.rs diff --git a/packages/core/Cargo.toml b/packages/core/Cargo.toml index ce7c6bccf..f73696f72 100644 --- a/packages/core/Cargo.toml +++ b/packages/core/Cargo.toml @@ -10,9 +10,6 @@ homepage = "https://dioxuslabs.com" keywords = ["dom", "ui", "gui", "react"] [dependencies] -# Bumpalo is used as a micro heap backing each component -bumpalo = { version = "3.6", features = ["collections", "boxed"] } - # faster hashmaps rustc-hash = { workspace = true } diff --git a/packages/core/src/any_props.rs b/packages/core/src/any_props.rs index f14a78065..2cc9c6559 100644 --- a/packages/core/src/any_props.rs +++ b/packages/core/src/any_props.rs @@ -11,9 +11,9 @@ use std::panic::AssertUnwindSafe; /// # Safety /// /// This should not be implemented outside this module -pub(crate) unsafe trait AnyProps<'a> { +pub(crate) unsafe trait AnyProps { fn props_ptr(&self) -> *const (); - fn render(&'a self, bump: &'a ScopeState) -> RenderReturn<'a>; + fn render<'a>(&'a self, bump: &'a ScopeState) -> RenderReturn<'a>; unsafe fn memoize(&self, other: &dyn AnyProps) -> bool; } @@ -37,7 +37,7 @@ impl<'a, P> VProps<'a, P> { } } -unsafe impl<'a, P> AnyProps<'a> for VProps<'a, P> { +unsafe impl<'a, P> AnyProps for VProps<'a, P> { fn props_ptr(&self) -> *const () { &self.props as *const _ as *const () } diff --git a/packages/core/src/bump_frame.rs b/packages/core/src/bump_frame.rs deleted file mode 100644 index 6927bd8bc..000000000 --- a/packages/core/src/bump_frame.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::nodes::RenderReturn; -use crate::{Attribute, AttributeValue, VComponent}; -use bumpalo::Bump; -use std::cell::RefCell; -use std::cell::{Cell, UnsafeCell}; - -pub(crate) struct BumpFrame { - pub bump: UnsafeCell, - pub node: Cell<*const RenderReturn<'static>>, - - // The bump allocator will not call the destructor of the objects it allocated. Attributes and props need to have there destructor called, so we keep a list of them to drop before the bump allocator is reset. - pub(crate) attributes_to_drop_before_reset: RefCell>>, - pub(crate) props_to_drop_before_reset: RefCell>>, -} - -impl BumpFrame { - pub(crate) fn new(capacity: usize) -> Self { - let bump = Bump::with_capacity(capacity); - Self { - bump: UnsafeCell::new(bump), - node: Cell::new(std::ptr::null()), - attributes_to_drop_before_reset: Default::default(), - props_to_drop_before_reset: Default::default(), - } - } - - /// Creates a new lifetime out of thin air - pub(crate) unsafe fn try_load_node<'b>(&self) -> Option<&'b RenderReturn<'b>> { - let node = self.node.get(); - - if node.is_null() { - return None; - } - - unsafe { std::mem::transmute(&*node) } - } - - pub(crate) fn bump(&self) -> &Bump { - unsafe { &*self.bump.get() } - } - - pub(crate) fn add_attribute_to_drop(&self, attribute: *const Attribute<'static>) { - self.attributes_to_drop_before_reset - .borrow_mut() - .push(attribute); - } - - /// Reset the bump allocator and drop all the attributes and props that were allocated in it. - /// - /// # Safety - /// The caller must insure that no reference to anything allocated in the bump allocator is available after this function is called. - pub(crate) unsafe fn reset(&self) { - let mut attributes = self.attributes_to_drop_before_reset.borrow_mut(); - attributes.drain(..).for_each(|attribute| { - let attribute = unsafe { &*attribute }; - if let AttributeValue::Any(l) = &attribute.value { - _ = l.take(); - } - }); - let mut props = self.props_to_drop_before_reset.borrow_mut(); - props.drain(..).for_each(|prop| { - let prop = unsafe { &*prop }; - _ = prop.props.borrow_mut().take(); - }); - unsafe { - let bump = &mut *self.bump.get(); - bump.reset(); - } - } -} - -impl Drop for BumpFrame { - fn drop(&mut self) { - unsafe { self.reset() } - } -} diff --git a/packages/core/src/create.rs b/packages/core/src/create.rs index f3b89ae9e..55334b900 100644 --- a/packages/core/src/create.rs +++ b/packages/core/src/create.rs @@ -67,7 +67,7 @@ impl<'b> 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<'b>) -> usize { + pub(crate) fn create_scope(&mut self, scope: ScopeId, template: &'b 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<'b>) -> usize { + pub(crate) fn create(&mut self, node: &'b 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<'b>, idx: usize) -> usize { + fn write_dynamic_root(&mut self, template: &'b 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<'b>, + template: &'b 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<'b>, + template: &'b 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<'b>, + node: &'b VNode, ) { while let Some((mut attr_id, path)) = attrs.next_if(|(_, p)| p.first().copied() == Some(root_idx)) @@ -327,7 +327,7 @@ impl<'b> VirtualDom { fn write_attribute( &mut self, - template: &'b VNode<'b>, + template: &'b VNode, idx: usize, attribute: &'b crate::Attribute<'b>, id: ElementId, @@ -490,7 +490,7 @@ impl<'b> VirtualDom { } } - fn create_dynamic_text(&mut self, parent: ElementRef, text: &'b VText<'b>) -> usize { + fn create_dynamic_text(&mut self, parent: ElementRef, text: &'b VText) -> usize { // Allocate a dynamic element reference for this text node let new_id = self.next_element(); @@ -538,7 +538,7 @@ impl<'b> VirtualDom { pub(super) fn create_component_node( &mut self, parent: Option, - component: &'b VComponent<'b>, + component: &'b VComponent, ) -> usize { use RenderReturn::*; diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 43b27f2e7..971c3977e 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -59,7 +59,7 @@ impl<'b> VirtualDom { self.runtime.scope_stack.borrow_mut().pop(); } - fn diff_ok_to_err(&mut self, l: &'b VNode<'b>, p: &'b VPlaceholder) { + fn diff_ok_to_err(&mut self, l: &'b VNode, p: &'b 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<'b>, right_template: &'b VNode<'b>) { + fn diff_node(&mut self, left_template: &'b VNode, right_template: &'b VNode) { // If hot reloading is enabled, we need to make sure we're using the latest template #[cfg(debug_assertions)] { @@ -198,8 +198,8 @@ impl<'b> VirtualDom { fn diff_vcomponent( &mut self, - left: &'b VComponent<'b>, - right: &'b VComponent<'b>, + left: &'b VComponent, + right: &'b VComponent, parent: Option, ) { if std::ptr::eq(left, right) { @@ -249,8 +249,8 @@ impl<'b> VirtualDom { fn replace_vcomponent( &mut self, - right: &'b VComponent<'b>, - left: &'b VComponent<'b>, + right: &'b VComponent, + left: &'b 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<'b>, right: &'b VNode<'b>) { + fn light_diff_templates(&mut self, left: &'b VNode, right: &'b 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<'b>, right: &'b VText<'b>) { + fn diff_vtext(&mut self, left: &'b VText, right: &'b VText) { let id = left.id.get().unwrap_or_else(|| self.next_element()); right.id.set(Some(id)); @@ -331,12 +331,7 @@ impl<'b> VirtualDom { } } - fn diff_non_empty_fragment( - &mut self, - old: &'b [VNode<'b>], - new: &'b [VNode<'b>], - parent: ElementRef, - ) { + fn diff_non_empty_fragment(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) { let new_is_keyed = new[0].key.is_some(); let old_is_keyed = old[0].key.is_some(); debug_assert!( @@ -363,12 +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<'b>], - new: &'b [VNode<'b>], - parent: ElementRef, - ) { + fn diff_non_keyed_children(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) { use std::cmp::Ordering; // Handled these cases in `diff_children` before calling this function. @@ -404,15 +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<'b>], - new: &'b [VNode<'b>], - parent: ElementRef, - ) { + fn diff_keyed_children(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) { if cfg!(debug_assertions) { let mut keys = rustc_hash::FxHashSet::default(); - let mut assert_unique_keys = |children: &'b [VNode<'b>]| { + let mut assert_unique_keys = |children: &'b [VNode]| { keys.clear(); for child in children { let key = child.key; @@ -485,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<'b>], - new: &'b [VNode<'b>], + old: &'b [VNode], + new: &'b [VNode], parent: ElementRef, ) -> Option<(usize, usize)> { let mut left_offset = 0; @@ -542,12 +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<'b>], - new: &'b [VNode<'b>], - parent: ElementRef, - ) { + fn diff_keyed_middle(&mut self, old: &'b [VNode], new: &'b [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 @@ -729,7 +709,7 @@ impl<'b> VirtualDom { } /// Push all the real nodes on the stack - fn push_all_real_nodes(&mut self, node: &'b VNode<'b>) -> usize { + fn push_all_real_nodes(&mut self, node: &'b VNode) -> usize { node.template .get() .roots @@ -783,7 +763,7 @@ impl<'b> VirtualDom { pub(crate) fn create_children( &mut self, - nodes: impl IntoIterator>, + nodes: impl IntoIterator, parent: Option, ) -> usize { nodes @@ -797,8 +777,8 @@ impl<'b> VirtualDom { fn create_and_insert_before( &mut self, - new: &'b [VNode<'b>], - before: &'b VNode<'b>, + new: &'b [VNode], + before: &'b VNode, parent: ElementRef, ) { let m = self.create_children(new, Some(parent)); @@ -806,12 +786,7 @@ impl<'b> VirtualDom { self.mutations.push(Mutation::InsertBefore { id, m }) } - fn create_and_insert_after( - &mut self, - new: &'b [VNode<'b>], - after: &'b VNode<'b>, - parent: ElementRef, - ) { + fn create_and_insert_after(&mut self, new: &'b [VNode], after: &'b 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 }) @@ -821,7 +796,7 @@ impl<'b> VirtualDom { fn replace_placeholder( &mut self, l: &'b VPlaceholder, - r: impl IntoIterator>, + r: impl IntoIterator, parent: ElementRef, ) { let m = self.create_children(r, Some(parent)); @@ -832,8 +807,8 @@ impl<'b> VirtualDom { fn replace( &mut self, - left: &'b VNode<'b>, - right: impl IntoIterator>, + left: &'b VNode, + right: impl IntoIterator, parent: Option, ) { let m = self.create_children(right, parent); @@ -855,7 +830,7 @@ impl<'b> VirtualDom { }; } - fn node_to_placeholder(&mut self, l: &'b [VNode<'b>], r: &'b VPlaceholder, parent: ElementRef) { + fn node_to_placeholder(&mut self, l: &'b [VNode], r: &'b VPlaceholder, parent: ElementRef) { // Create the placeholder first, ensuring we get a dedicated ID for the placeholder let placeholder = self.next_element(); @@ -878,14 +853,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<'b>]) { + fn remove_nodes(&mut self, nodes: &'b [VNode]) { nodes .iter() .rev() .for_each(|node| self.remove_node(node, true)); } - fn remove_node(&mut self, node: &'b VNode<'b>, gen_muts: bool) { + fn remove_node(&mut self, node: &'b 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); @@ -903,7 +878,7 @@ impl<'b> VirtualDom { self.reclaim_vnode_id(node); } - fn reclaim_vnode_id(&mut self, node: &'b VNode<'b>) { + fn reclaim_vnode_id(&mut self, node: &'b VNode) { // Clean up the vnode id if let Some(id) = node.stable_id() { self.element_refs.remove(id.0); @@ -1025,7 +1000,7 @@ impl<'b> VirtualDom { self.drop_scope(scope, false); } - fn find_first_element(&self, node: &'b VNode<'b>) -> ElementId { + fn find_first_element(&self, node: &'b VNode) -> ElementId { match node.dynamic_root(0) { None => node.root_ids.borrow()[0], Some(Text(t)) => t.id.get().unwrap(), @@ -1046,7 +1021,7 @@ impl<'b> VirtualDom { } } - fn find_last_element(&self, node: &'b VNode<'b>) -> ElementId { + fn find_last_element(&self, node: &'b 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(), @@ -1067,7 +1042,7 @@ impl<'b> VirtualDom { } } - pub(crate) fn assign_boundary_ref(&mut self, parent: Option, child: &'b VNode<'b>) { + pub(crate) fn assign_boundary_ref(&mut self, parent: Option, child: &'b VNode) { if let Some(parent) = parent { // assign the parent of the child child.parent.set(Some(parent)); @@ -1080,7 +1055,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<'b>, right_template: &'b VNode<'b>) -> bool { +fn templates_are_the_same<'b>(left_template: &'b VNode, right_template: &'b VNode) -> bool { std::ptr::eq(left_template, right_template) } @@ -1092,9 +1067,9 @@ fn templates_are_different(left_template: &VNode, right_template: &VNode) -> boo } fn matching_components<'a>( - left: &'a VNode<'a>, - right: &'a VNode<'a>, -) -> Option, &'a VComponent<'a>)>> { + left: &'a VNode, + right: &'a VNode, +) -> Option> { let left_template = left.template.get(); let right_template = right.template.get(); if left_template.roots.len() != right_template.roots.len() { diff --git a/packages/core/src/error_boundary.rs b/packages/core/src/error_boundary.rs index d42f59395..30e31b7b8 100644 --- a/packages/core/src/error_boundary.rs +++ b/packages/core/src/error_boundary.rs @@ -262,7 +262,7 @@ impl Throw for Option { } } -pub struct ErrorHandler<'a>(Box LazyNodes<'a, 'a> + 'a>); +pub struct ErrorHandler(Box LazyNodes<'a, 'a>>); impl<'a, F: Fn(CapturedError) -> LazyNodes<'a, 'a> + 'a> From for ErrorHandler<'a> { fn from(value: F) -> Self { Self(Box::new(value)) @@ -290,7 +290,7 @@ fn default_handler<'a>(error: CapturedError) -> LazyNodes<'a, 'a> { stable_id: Default::default(), key: None, template: std::cell::Cell::new(TEMPLATE), - root_ids: bumpalo::collections::Vec::with_capacity_in(1usize, __cx.bump()).into(), + root_ids: Vec::with_capacity(1usize).into(), dynamic_nodes: __cx .bump() .alloc([__cx.text_node(format_args!("{0}", error))]), @@ -298,45 +298,39 @@ fn default_handler<'a>(error: CapturedError) -> LazyNodes<'a, 'a> { } }) } -pub struct ErrorBoundaryProps<'a> { - children: Element<'a>, - handle_error: ErrorHandler<'a>, +pub struct ErrorBoundaryProps { + children: Element, + handle_error: ErrorHandler, } -impl<'a> ErrorBoundaryProps<'a> { +impl ErrorBoundaryProps { /** Create a builder for building `ErrorBoundaryProps`. On the builder, call `.children(...)`(optional), `.handle_error(...)`(optional) to set the values of the fields. Finally, call `.build()` to create the instance of `ErrorBoundaryProps`. */ #[allow(dead_code)] - pub fn builder() -> ErrorBoundaryPropsBuilder<'a, ((), ())> { - ErrorBoundaryPropsBuilder { - fields: ((), ()), - _phantom: ::core::default::Default::default(), - } + pub fn builder() -> ErrorBoundaryPropsBuilder<((), ())> { + ErrorBoundaryPropsBuilder { fields: ((), ()) } } } #[must_use] #[doc(hidden)] #[allow(dead_code, non_camel_case_types, non_snake_case)] -pub struct ErrorBoundaryPropsBuilder<'a, TypedBuilderFields> { +pub struct ErrorBoundaryPropsBuilder { fields: TypedBuilderFields, - _phantom: ::core::marker::PhantomData<&'a ()>, } -impl<'a, TypedBuilderFields> Clone for ErrorBoundaryPropsBuilder<'a, TypedBuilderFields> +impl Clone for ErrorBoundaryPropsBuilder where TypedBuilderFields: Clone, { fn clone(&self) -> Self { Self { fields: self.fields.clone(), - _phantom: ::core::default::Default::default(), } } } -impl<'a> Properties for ErrorBoundaryProps<'a> { - type Builder = ErrorBoundaryPropsBuilder<'a, ((), ())>; - const IS_STATIC: bool = false; +impl Properties for ErrorBoundaryProps { + type Builder = ErrorBoundaryPropsBuilder<((), ())>; fn builder() -> Self::Builder { ErrorBoundaryProps::builder() } diff --git a/packages/core/src/events.rs b/packages/core/src/events.rs index 784a8c865..74e07c914 100644 --- a/packages/core/src/events.rs +++ b/packages/core/src/events.rs @@ -147,7 +147,7 @@ impl Default for EventHandler<'_, T> { } } -type ExternalListenerCallback<'bump, T> = bumpalo::boxed::Box<'bump, dyn FnMut(T) + 'bump>; +type ExternalListenerCallback<'bump, T> = Box; impl EventHandler<'_, T> { /// Call this event handler with the appropriate event type diff --git a/packages/core/src/fragment.rs b/packages/core/src/fragment.rs index bfab2f98f..e4e1d8660 100644 --- a/packages/core/src/fragment.rs +++ b/packages/core/src/fragment.rs @@ -26,7 +26,7 @@ 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<'a>>) -> Element { +pub fn Fragment<'a>(cx: Scope<'a, FragmentProps>) -> Element { let children = cx.props.0.as_ref()?; Some(VNode { key: children.key, @@ -92,8 +92,8 @@ impl FragmentBuilder { /// }) /// } /// ``` -impl<'a> Properties for FragmentProps<'a> { - type Builder = FragmentBuilder<'a, false>; +impl<'a> Properties for FragmentProps { + type Builder = FragmentBuilder; fn builder() -> Self::Builder { FragmentBuilder(None) } diff --git a/packages/core/src/lazynodes.rs b/packages/core/src/lazynodes.rs deleted file mode 100644 index ae1bd2109..000000000 --- a/packages/core/src/lazynodes.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Support for storing lazy-nodes on the stack -//! -//! This module provides support for a type called `LazyNodes` which is a micro-heap located on the stack to make calls -//! to `rsx!` more efficient. -//! -//! To support returning rsx! from branches in match statements, we need to use dynamic dispatch on [`ScopeState`] closures. -//! -//! This can be done either through boxing directly, or by using dynamic-sized-types and a custom allocator. In our case, -//! we build a tiny alloactor in the stack and allocate the closure into that. -//! -//! The logic for this was borrowed from . Unfortunately, this crate does not -//! support non-static closures, so we've implemented the core logic of `ValueA` in this module. - -#[allow(unused_imports)] -use smallbox::{smallbox, space::S16, SmallBox}; - -use crate::{innerlude::VNode, ScopeState}; - -/// A concrete type provider for closures that build [`VNode`] structures. -/// -/// This struct wraps lazy structs that build [`VNode`] trees. Normally, we cannot perform a blanket implementation over -/// closures, but if we wrap the closure in a concrete type, we can use it for different branches in matching. -/// -/// -/// ```rust, ignore -/// LazyNodes::new(|f| { -/// static TEMPLATE: dioxus::core::Template = dioxus::core::Template { -/// name: "main.rs:5:5:20", // Source location of the template for hot reloading -/// roots: &[ -/// dioxus::core::TemplateNode::Element { -/// tag: dioxus_elements::div::TAG_NAME, -/// namespace: dioxus_elements::div::NAME_SPACE, -/// attrs: &[], -/// children: &[], -/// }, -/// ], -/// node_paths: &[], -/// attr_paths: &[], -/// }; -/// dioxus::core::VNode { -/// parent: None, -/// key: None, -/// template: std::cell::Cell::new(TEMPLATE), -/// root_ids: dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in( -/// 1usize, -/// f.bump(), -/// ) -/// .into(), -/// dynamic_nodes: f.bump().alloc([]), -/// dynamic_attrs: f.bump().alloc([]), -/// }) -/// } -/// ``` -/// -/// Find more information about how to construct [`VNode`] at - -pub struct LazyNodes<'a, 'b> { - #[cfg(not(miri))] - inner: SmallBox VNode<'a> + 'b, S16>, - - #[cfg(miri)] - inner: Box VNode<'a> + 'b>, -} - -impl<'a, 'b> LazyNodes<'a, 'b> { - /// Create a new [`LazyNodes`] closure, optimistically placing it onto the stack. - /// - /// If the closure cannot fit into the stack allocation (16 bytes), then it - /// is placed on the heap. Most closures will fit into the stack, and is - /// the most optimal way to use the creation function. - pub fn new(val: impl FnOnce(&'a ScopeState) -> VNode<'a> + 'b) -> Self { - // there's no way to call FnOnce without a box, so we need to store it in a slot and use static dispatch - let mut slot = Some(val); - - Self { - #[cfg(not(miri))] - inner: smallbox!(move |f| { - let val = slot.take().expect("cannot call LazyNodes twice"); - val(f) - }), - - #[cfg(miri)] - inner: Box::new(move |f| { - let val = slot.take().expect("cannot call LazyNodes twice"); - val(f) - }), - } - } - - /// Call the closure with the given factory to produce real [`VNode`]. - /// - /// ```rust, ignore - /// let f = LazyNodes::new(/* Closure for creating VNodes */); - /// - /// let node = f.call(cac); - /// ``` - #[must_use] - pub fn call(mut self, f: &'a ScopeState) -> VNode<'a> { - (self.inner)(f) - } -} diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 13d55826b..8690d9a31 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -5,7 +5,6 @@ mod any_props; mod arena; -mod bump_frame; mod create; mod diff; mod dirty_scope; @@ -43,7 +42,7 @@ pub(crate) mod innerlude { /// An [`Element`] is a possibly-none [`VNode`] created by calling `render` on [`Scope`] or [`ScopeState`]. /// /// An Errored [`Element`] will propagate the error to the nearest error boundary. - pub type Element<'a> = Option>; + pub type Element = Option; /// A [`Component`] is a function that takes a [`Scope`] and returns an [`Element`]. /// @@ -97,9 +96,3 @@ pub mod prelude { VNode, VirtualDom, }; } - -pub mod exports { - //! Important dependencies that are used by the rest of the library - //! Feel free to just add the dependencies in your own Crates.toml - pub use bumpalo; -} diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index 3d3afaeb3..692520b3e 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -19,9 +19,9 @@ pub type TemplateId = &'static str; /// /// Dioxus will do its best to immediately resolve any async components into a regular Element, but as an implementor /// you might need to handle the case where there's no node immediately ready. -pub enum RenderReturn<'a> { +pub enum RenderReturn { /// A currently-available element - Ready(VNode<'a>), + Ready(VNode), /// The component aborted rendering early. It might've thrown an error. /// @@ -30,7 +30,7 @@ pub enum RenderReturn<'a> { Aborted(VPlaceholder), } -impl<'a> Default for RenderReturn<'a> { +impl Default for RenderReturn { fn default() -> Self { RenderReturn::Aborted(VPlaceholder::default()) } @@ -88,11 +88,11 @@ impl VNode { /// Create a new VNode pub fn new( - key: Option<&'a str>, + key: Option, template: Template<'static>, - root_ids: bumpalo::collections::Vec<'a, ElementId>, - dynamic_nodes: &'a [DynamicNode<'a>], - dynamic_attrs: &'a [Attribute<'a>], + root_ids: Vec, + dynamic_nodes: &'a [DynamicNode], + dynamic_attrs: &'a [Attribute], ) -> Self { Self { key, @@ -113,7 +113,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<'a>> { + pub fn dynamic_root(&self, idx: usize) -> Option<&'a DynamicNode> { match &self.template.get().roots[idx] { TemplateNode::Element { .. } | TemplateNode::Text { text: _ } => None, TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => { @@ -147,7 +147,7 @@ pub struct Template<'a> { /// /// Unlike react, calls to `rsx!` can have multiple roots. This list supports that paradigm. #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))] - pub roots: &'a [TemplateNode<'a>], + pub roots: &'a [TemplateNode], /// The paths of each node relative to the root of the template. /// @@ -242,7 +242,7 @@ impl<'a> Template<'a> { derive(serde::Serialize, serde::Deserialize), serde(tag = "type") )] -pub enum TemplateNode<'a> { +pub enum TemplateNode { /// An statically known element in the dom. /// /// In HTML this would be something like `
` @@ -250,7 +250,7 @@ pub enum TemplateNode<'a> { /// The name of the element /// /// IE for a div, it would be the string "div" - tag: &'a str, + tag: &'static str, /// The namespace of the element /// @@ -260,23 +260,23 @@ pub enum TemplateNode<'a> { feature = "serialize", serde(deserialize_with = "deserialize_option_leaky") )] - namespace: Option<&'a str>, + namespace: Option<&'static str>, /// A list of possibly dynamic attribues for this element /// /// An attribute on a DOM node, such as `id="my-thing"` or `href="https://example.com"`. #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))] - attrs: &'a [TemplateAttribute<'a>], + attrs: &'static [TemplateAttribute], /// A list of template nodes that define another set of template nodes #[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))] - children: &'a [TemplateNode<'a>], + children: &'static [TemplateNode], }, /// This template node is just a piece of static text Text { /// The actual text - text: &'a str, + text: &'static str, }, /// This template node is unknown, and needs to be created at runtime. @@ -298,7 +298,7 @@ pub enum TemplateNode<'a> { /// /// This node's index in the DynamicNode list on VNode should match its repsective `Dynamic` index #[derive(Debug)] -pub enum DynamicNode<'a> { +pub enum DynamicNode { /// A component node /// /// Most of the time, Dioxus will actually know which component this is as compile time, but the props and @@ -306,10 +306,10 @@ pub enum DynamicNode<'a> { /// /// The actual VComponent can be dynamic between two VNodes, though, allowing implementations to swap /// the render function at runtime - Component(VComponent<'a>), + Component(VComponent), /// A text node - Text(VText<'a>), + Text(VText), /// A placeholder /// @@ -322,27 +322,20 @@ pub enum DynamicNode<'a> { /// /// Note that this is not a list of dynamic nodes. These must be VNodes and created through conditional rendering /// or iterators. - Fragment(&'a [VNode<'a>]), + Fragment(&'static [VNode]), } -impl Default for DynamicNode<'_> { +impl Default for DynamicNode { fn default() -> Self { Self::Placeholder(Default::default()) } } /// An instance of a child component -pub struct VComponent<'a> { +pub struct VComponent { /// The name of this component pub name: &'static str, - /// Are the props valid for the 'static lifetime? - /// - /// Internally, this is used as a guarantee. Externally, this might be incorrect, so don't count on it. - /// - /// This flag is assumed by the [`crate::Properties`] trait which is unsafe to implement - pub(crate) static_props: bool, - /// The assigned Scope for this component pub(crate) scope: Cell>, @@ -351,17 +344,17 @@ pub struct VComponent<'a> { /// 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 + 'a>>>, + pub(crate) props: RefCell>>, } -impl<'a> VComponent<'a> { +impl<'a> VComponent { /// Get the scope that this component is mounted to pub fn mounted_scope(&self) -> Option { self.scope.get() } } -impl<'a> std::fmt::Debug for VComponent<'a> { +impl<'a> std::fmt::Debug for VComponent { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("VComponent") .field("name", &self.name) @@ -373,17 +366,17 @@ impl<'a> std::fmt::Debug for VComponent<'a> { /// An instance of some text, mounted to the DOM #[derive(Debug)] -pub struct VText<'a> { +pub struct VText { /// The actual text itself - pub value: &'a str, + pub value: String, /// The ID of this node in the real DOM pub(crate) id: Cell>, } -impl<'a> VText<'a> { +impl<'a> VText { /// Create a new VText - pub fn new(value: &'a str) -> Self { + pub fn new(value: String) -> Self { Self { value, id: Default::default(), @@ -419,21 +412,21 @@ impl VPlaceholder { derive(serde::Serialize, serde::Deserialize), serde(tag = "type") )] -pub enum TemplateAttribute<'a> { +pub enum TemplateAttribute { /// This attribute is entirely known at compile time, enabling Static { /// The name of this attribute. /// /// For example, the `href` attribute in `href="https://example.com"`, would have the name "href" - name: &'a str, + name: &'static str, /// The value of this attribute, known at compile time /// /// Currently this only accepts &str, so values, even if they're known at compile time, are not known - value: &'a str, + value: &'static str, /// The namespace of this attribute. Does not exist in the HTML spec - namespace: Option<&'a str>, + namespace: Option<&'static str>, }, /// The attribute in this position is actually determined dynamically at runtime @@ -447,12 +440,12 @@ pub enum TemplateAttribute<'a> { /// An attribute on a DOM node, such as `id="my-thing"` or `href="https://example.com"` #[derive(Debug)] -pub struct Attribute<'a> { +pub struct Attribute { /// The name of the attribute. - pub name: &'a str, + pub name: &'static str, /// The value of the attribute - pub value: AttributeValue<'a>, + pub value: AttributeValue, /// The namespace of the attribute. /// @@ -466,11 +459,11 @@ pub struct Attribute<'a> { pub(crate) mounted_element: Cell, } -impl<'a> Attribute<'a> { +impl Attribute { /// Create a new attribute pub fn new( - name: &'a str, - value: AttributeValue<'a>, + name: &'static str, + value: AttributeValue, namespace: Option<&'static str>, volatile: bool, ) -> Self { @@ -493,9 +486,9 @@ impl<'a> Attribute<'a> { /// /// These are built-in to be faster during the diffing process. To use a custom value, use the [`AttributeValue::Any`] /// variant. -pub enum AttributeValue<'a> { +pub enum AttributeValue { /// Text attribute - Text(&'a str), + Text(String), /// A float Float(f64), @@ -507,16 +500,16 @@ pub enum AttributeValue<'a> { Bool(bool), /// A listener, like "onclick" - Listener(RefCell>>), + Listener(RefCell>), /// An arbitrary value that implements PartialEq and is static - Any(RefCell>>), + Any(RefCell>>), /// A "none" value, resulting in the removal of an attribute from the dom None, } -pub type ListenerCb<'a> = BumpBox<'a, dyn FnMut(Event) + 'a>; +pub type ListenerCb = Box)>; /// Any of the built-in values that the Dioxus VirtualDom supports as dynamic attributes on elements that are borrowed /// @@ -550,8 +543,8 @@ pub enum BorrowedAttributeValue<'a> { None, } -impl<'a> From<&'a AttributeValue<'a>> for BorrowedAttributeValue<'a> { - fn from(value: &'a AttributeValue<'a>) -> Self { +impl<'a> From<&'a AttributeValue> for BorrowedAttributeValue<'a> { + fn from(value: &'a AttributeValue) -> Self { match value { AttributeValue::Text(value) => BorrowedAttributeValue::Text(value), AttributeValue::Float(value) => BorrowedAttributeValue::Float(*value), @@ -613,7 +606,7 @@ where panic!("Any cannot be deserialized") } -impl<'a> std::fmt::Debug for AttributeValue<'a> { +impl std::fmt::Debug for AttributeValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Text(arg0) => f.debug_tuple("Text").field(arg0).finish(), @@ -627,7 +620,7 @@ impl<'a> std::fmt::Debug for AttributeValue<'a> { } } -impl<'a> PartialEq for AttributeValue<'a> { +impl PartialEq for AttributeValue { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Text(l0), Self::Text(r0)) => l0 == r0, @@ -668,42 +661,33 @@ impl AnyValue for T { } } -impl<'a> RenderReturn<'a> { - pub(crate) unsafe fn extend_lifetime_ref<'c>(&self) -> &'c RenderReturn<'c> { - unsafe { std::mem::transmute(self) } - } - pub(crate) unsafe fn extend_lifetime<'c>(self) -> RenderReturn<'c> { - unsafe { std::mem::transmute(self) } - } -} - /// A trait that allows various items to be converted into a dynamic node for the rsx macro pub trait IntoDynNode<'a, 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<'a>; + fn into_dyn_node(self, cx: &'a ScopeState) -> DynamicNode; } impl<'a> IntoDynNode<'a> for () { - fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode<'a> { + fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { DynamicNode::default() } } -impl<'a> IntoDynNode<'a> for VNode<'a> { - fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode<'a> { +impl<'a> IntoDynNode<'a> for VNode { + fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { DynamicNode::Fragment(_cx.bump().alloc([self])) } } -impl<'a> IntoDynNode<'a> for DynamicNode<'a> { - fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode<'a> { +impl<'a> IntoDynNode<'a> for DynamicNode { + fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { self } } impl<'a, T: IntoDynNode<'a>> IntoDynNode<'a> for Option { - fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode<'a> { + fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { match self { Some(val) => val.into_dyn_node(_cx), None => DynamicNode::default(), @@ -711,8 +695,8 @@ impl<'a, T: IntoDynNode<'a>> IntoDynNode<'a> for Option { } } -impl<'a> IntoDynNode<'a> for &Element<'a> { - fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode<'a> { +impl<'a> IntoDynNode<'a> for &Element { + fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { match self.as_ref() { Some(val) => val.clone().into_dyn_node(_cx), _ => DynamicNode::default(), @@ -721,13 +705,13 @@ impl<'a> IntoDynNode<'a> for &Element<'a> { } impl<'a, 'b> IntoDynNode<'a> for LazyNodes<'a, 'b> { - fn into_dyn_node(self, cx: &'a ScopeState) -> DynamicNode<'a> { + 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<'b> { + fn into_dyn_node(self, cx: &'b ScopeState) -> DynamicNode { DynamicNode::Text(VText { value: cx.bump().alloc_str(self), id: Default::default(), @@ -745,13 +729,13 @@ impl IntoDynNode<'_> for String { } impl<'b> IntoDynNode<'b> for Arguments<'_> { - fn into_dyn_node(self, cx: &'b ScopeState) -> DynamicNode<'b> { + fn into_dyn_node(self, cx: &'b ScopeState) -> DynamicNode { cx.text_node(self) } } -impl<'a> IntoDynNode<'a> for &'a VNode<'a> { - fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode<'a> { +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(), @@ -764,24 +748,24 @@ impl<'a> IntoDynNode<'a> for &'a VNode<'a> { } } -pub trait IntoVNode<'a> { - fn into_vnode(self, _cx: &'a ScopeState) -> VNode<'a>; +pub trait IntoVNode { + fn into_vnode(self) -> VNode; } -impl<'a> IntoVNode<'a> for VNode<'a> { - fn into_vnode(self, _cx: &'a ScopeState) -> VNode<'a> { +impl<'a> IntoVNode for VNode { + fn into_vnode(self) -> VNode { self } } -impl<'a> IntoVNode<'a> for Element<'a> { - fn into_vnode(self, cx: &'a ScopeState) -> VNode<'a> { +impl<'a> IntoVNode for Element { + fn into_vnode(self) -> VNode { match self { Some(val) => val.into_vnode(cx), - _ => VNode::empty(cx).unwrap(), + _ => VNode::empty().unwrap(), } } } -impl<'a, 'b> IntoVNode<'a> for LazyNodes<'a, 'b> { - fn into_vnode(self, cx: &'a ScopeState) -> VNode<'a> { +impl<'a, 'b> IntoVNode for LazyNodes<'a, 'b> { + fn into_vnode(self) -> VNode { cx.render(self).unwrap() } } @@ -791,9 +775,9 @@ pub struct FromNodeIterator; impl<'a, T, I> IntoDynNode<'a, FromNodeIterator> for T where T: Iterator, - I: IntoVNode<'a>, + I: IntoVNode, { - fn into_dyn_node(self, cx: &'a ScopeState) -> DynamicNode<'a> { + fn into_dyn_node(self, cx: &'a ScopeState) -> DynamicNode { let mut nodes = bumpalo::collections::Vec::new_in(cx.bump()); nodes.extend(self.into_iter().map(|node| node.into_vnode(cx))); diff --git a/packages/core/src/properties.rs b/packages/core/src/properties.rs index 9a36158fc..ada5e58d5 100644 --- a/packages/core/src/properties.rs +++ b/packages/core/src/properties.rs @@ -32,7 +32,7 @@ use crate::innerlude::*; /// data: &'a str /// } /// ``` -pub trait Properties: Sized + 'static { +pub trait Properties: Clone + Sized + 'static { /// The type of the builder for this component. /// Used to create "in-progress" versions of the props. type Builder; @@ -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<'a>) -> T::Builder { +pub fn fc_to_builder<'a, T: Properties + 'a>(_: fn(Scope<'a, T>) -> Element) -> T::Builder { T::builder() } diff --git a/packages/core/src/scope_arena.rs b/packages/core/src/scope_arena.rs index 962a55e86..b8daeb7cb 100644 --- a/packages/core/src/scope_arena.rs +++ b/packages/core/src/scope_arena.rs @@ -1,6 +1,5 @@ use crate::{ any_props::AnyProps, - bump_frame::BumpFrame, innerlude::DirtyScope, nodes::RenderReturn, scope_context::ScopeContext, @@ -11,7 +10,7 @@ use crate::{ impl VirtualDom { pub(super) fn new_scope( &mut self, - props: Box>, + props: Box, name: &'static str, ) -> &ScopeState { let parent_id = self.runtime.current_scope_id(); @@ -27,9 +26,6 @@ impl VirtualDom { props: Some(props), - node_arena_1: BumpFrame::new(0), - node_arena_2: BumpFrame::new(0), - render_cnt: Default::default(), hooks: Default::default(), hook_idx: Default::default(), diff --git a/packages/core/src/scope_context.rs b/packages/core/src/scope_context.rs index e4cb256d2..e06fe5eba 100644 --- a/packages/core/src/scope_context.rs +++ b/packages/core/src/scope_context.rs @@ -301,7 +301,7 @@ pub fn provide_root_context(value: T) -> Option { } /// Suspends the current component -pub fn suspend() -> Option> { +pub fn suspend() -> Option { with_current_scope(|cx| { cx.suspend(); }); diff --git a/packages/core/src/scopes.rs b/packages/core/src/scopes.rs index 552a9d5b9..ffdd895f5 100644 --- a/packages/core/src/scopes.rs +++ b/packages/core/src/scopes.rs @@ -1,16 +1,13 @@ use crate::{ any_props::AnyProps, any_props::VProps, - bump_frame::BumpFrame, innerlude::ErrorBoundary, innerlude::{DynamicNode, EventHandler, VComponent, VNodeId, VText}, - lazynodes::LazyNodes, nodes::{IntoAttributeValue, IntoDynNode, RenderReturn}, runtime::Runtime, scope_context::ScopeContext, AnyValue, Attribute, AttributeValue, Element, Event, Properties, TaskId, }; -use bumpalo::{boxed::Box as BumpBox, Bump}; use std::{ any::Any, cell::{Cell, Ref, RefCell, UnsafeCell}, @@ -90,11 +87,11 @@ pub struct ScopeState { pub(crate) hooks: RefCell>>>, pub(crate) hook_idx: Cell, - pub(crate) borrowed_props: RefCell>>, + pub(crate) borrowed_props: RefCell>, pub(crate) element_refs_to_drop: RefCell>, - pub(crate) attributes_to_drop_before_render: RefCell>>, + pub(crate) attributes_to_drop_before_render: RefCell>, - pub(crate) props: Option>>, + pub(crate) props: Option>, } impl Drop for ScopeState { @@ -108,22 +105,6 @@ impl<'src> ScopeState { self.runtime.get_context(self.context_id).unwrap() } - pub(crate) fn current_frame(&self) -> &BumpFrame { - match self.render_cnt.get() % 2 { - 0 => &self.node_arena_1, - 1 => &self.node_arena_2, - _ => unreachable!(), - } - } - - pub(crate) fn previous_frame(&self) -> &BumpFrame { - match self.render_cnt.get() % 2 { - 1 => &self.node_arena_1, - 0 => &self.node_arena_2, - _ => unreachable!(), - } - } - /// Get the name of this component pub fn name(&self) -> &str { self.context().name @@ -136,17 +117,6 @@ impl<'src> ScopeState { self.render_cnt.get() } - /// Get a handle to the currently active bump arena for this Scope - /// - /// This is a bump memory allocator. Be careful using this directly since the contents will be wiped on the next render. - /// It's easy to leak memory here since the drop implementation will not be called for any objects allocated in this arena. - /// - /// If you need to allocate items that need to be dropped, use bumpalo's box. - pub fn bump(&self) -> &Bump { - // note that this is actually the previous frame since we use that as scratch space while the component is rendering - self.previous_frame().bump() - } - /// Get a handle to the currently active head node arena for this Scope /// /// This is useful for traversing the tree outside of the VirtualDom, such as in a custom renderer or in SSR. @@ -343,7 +313,7 @@ impl<'src> ScopeState { /// cx.render(lazy_tree) /// } ///``` - pub fn render(&'src self, rsx: LazyNodes<'src, '_>) -> Element<'src> { + 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(); @@ -383,25 +353,13 @@ impl<'src> ScopeState { } /// Create a dynamic text node using [`Arguments`] and the [`ScopeState`]'s internal [`Bump`] allocator - pub fn text_node(&'src self, args: Arguments) -> DynamicNode<'src> { + pub fn text_node(&'src self, args: Arguments) -> DynamicNode { DynamicNode::Text(VText { value: self.raw_text(args), id: Default::default(), }) } - /// Allocate some text inside the [`ScopeState`] from [`Arguments`] - /// - /// Uses the currently active [`Bump`] allocator - pub fn raw_text(&'src self, args: Arguments) -> &'src str { - args.as_str().unwrap_or_else(|| { - use bumpalo::core_alloc::fmt::Write; - let mut str_buf = bumpalo::collections::String::new_in(self.bump()); - str_buf.write_fmt(args).unwrap(); - str_buf.into_bump_str() - }) - } - /// 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) @@ -417,7 +375,7 @@ impl<'src> ScopeState { value: impl IntoAttributeValue<'src>, namespace: Option<&'static str>, volatile: bool, - ) -> Attribute<'src> { + ) -> Attribute { Attribute { name, namespace, @@ -443,10 +401,10 @@ impl<'src> ScopeState { /// ``` pub fn component<'child, P>( &'src self, - component: fn(Scope<'child, P>) -> Element<'child>, + component: fn(Scope<'child, P>) -> Element, props: P, fn_name: &'static str, - ) -> DynamicNode<'src> + ) -> DynamicNode where // The properties must be valid until the next bump frame P: Properties + 'src, @@ -456,13 +414,12 @@ impl<'src> ScopeState { 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 + 'src> = 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 (), - static_props: P::IS_STATIC, props: RefCell::new(Some(extended)), scope: Default::default(), }) @@ -470,9 +427,9 @@ impl<'src> ScopeState { /// Create a new [`EventHandler`] from an [`FnMut`] pub fn event_handler(&'src self, f: impl FnMut(T) + 'src) -> EventHandler<'src, T> { - let handler: &mut dyn FnMut(T) = self.bump().alloc(f); - let caller = unsafe { BumpBox::from_raw(handler as *mut dyn FnMut(T)) }; - let callback = RefCell::new(Some(caller)); + let callback = RefCell::new(Some(Box::new(move |event: Event| { + f(event.data); + }))); EventHandler { callback, origin: self.context().id, @@ -485,34 +442,22 @@ impl<'src> ScopeState { pub fn listener( &'src self, mut callback: impl FnMut(Event) + 'src, - ) -> AttributeValue<'src> { - // safety: there's no other way to create a dynamicly-dispatched bump box other than alloc + from-raw - // This is the suggested way to build a bumpbox - // - // In theory, we could just use regular boxes - let boxed: BumpBox<'src, dyn FnMut(_) + 'src> = unsafe { - BumpBox::from_raw(self.bump().alloc(move |event: Event| { + ) -> AttributeValue { + AttributeValue::Listener(RefCell::new(Some(Box::new( + move |event: Event| { if let Ok(data) = event.data.downcast::() { callback(Event { propagates: event.propagates, data, }); } - })) - }; - - AttributeValue::Listener(RefCell::new(Some(boxed))) + }, + )))) } /// Create a new [`AttributeValue`] with a value that implements [`AnyValue`] - pub fn any_value(&'src self, value: T) -> AttributeValue<'src> { - // safety: there's no other way to create a dynamicly-dispatched bump box other than alloc + from-raw - // This is the suggested way to build a bumpbox - // - // In theory, we could just use regular boxes - let boxed: BumpBox<'src, dyn AnyValue> = - unsafe { BumpBox::from_raw(self.bump().alloc(value)) }; - AttributeValue::Any(RefCell::new(Some(boxed))) + pub fn any_value(&'src self, value: T) -> AttributeValue { + AttributeValue::Any(RefCell::new(Some(Box::new(value)))) } /// Mark this component as suspended and then return None diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index f469cd9e2..ec1f0dfe5 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -16,7 +16,9 @@ use crate::{ use futures_util::{pin_mut, StreamExt}; use rustc_hash::{FxHashMap, FxHashSet}; use slab::Slab; -use std::{any::Any, cell::Cell, collections::BTreeSet, future::Future, ptr::NonNull, rc::Rc, sync::Arc}; +use std::{ + any::Any, cell::Cell, collections::BTreeSet, future::Future, ptr::NonNull, rc::Rc, sync::Arc, +}; /// A virtual node system that progresses user events and diffs UI trees. /// @@ -186,7 +188,7 @@ pub struct VirtualDom { pub(crate) templates: FxHashMap>>, // Every element is actually a dual reference - one to the template and the other to the dynamic node in that template - pub(crate) element_refs: Slab>>>, + pub(crate) element_refs: Slab>>, // The element ids that are used in the renderer pub(crate) elements: Slab>, diff --git a/packages/html/src/events.rs b/packages/html/src/events.rs index c59149493..32c48aafb 100644 --- a/packages/html/src/events.rs +++ b/packages/html/src/events.rs @@ -9,7 +9,7 @@ macro_rules! impl_event { $( $( #[$attr] )* #[inline] - pub fn $name<'a, E: crate::EventReturn, T>(_cx: &'a ::dioxus_core::ScopeState, mut _f: impl FnMut(::dioxus_core::Event<$data>) -> E + 'a) -> ::dioxus_core::Attribute<'a> { + pub fn $name<'a, E: crate::EventReturn, T>(_cx: &'a ::dioxus_core::ScopeState, mut _f: impl FnMut(::dioxus_core::Event<$data>) -> E + 'a) -> ::dioxus_core::Attribute { ::dioxus_core::Attribute::new( stringify!($name), _cx.listener(move |e: ::dioxus_core::Event<$data>| { diff --git a/packages/html/src/events/mouse.rs b/packages/html/src/events/mouse.rs index 17128f4e4..890d56546 100644 --- a/packages/html/src/events/mouse.rs +++ b/packages/html/src/events/mouse.rs @@ -151,7 +151,7 @@ impl_event! { pub fn ondoubleclick<'a, E: crate::EventReturn, T>( _cx: &'a ::dioxus_core::ScopeState, mut _f: impl FnMut(::dioxus_core::Event) -> E + 'a, -) -> ::dioxus_core::Attribute<'a> { +) -> ::dioxus_core::Attribute { ::dioxus_core::Attribute::new( "ondblclick", _cx.listener(move |e: ::dioxus_core::Event| {