rip out more lifetimes

This commit is contained in:
Evan Almloff 2024-01-04 18:33:01 -06:00
parent c9ff449e45
commit 3ad16ddd37
18 changed files with 165 additions and 456 deletions

View file

@ -10,9 +10,6 @@ homepage = "https://dioxuslabs.com"
keywords = ["dom", "ui", "gui", "react"] keywords = ["dom", "ui", "gui", "react"]
[dependencies] [dependencies]
# Bumpalo is used as a micro heap backing each component
bumpalo = { version = "3.6", features = ["collections", "boxed"] }
# faster hashmaps # faster hashmaps
rustc-hash = { workspace = true } rustc-hash = { workspace = true }

View file

@ -11,9 +11,9 @@ use std::panic::AssertUnwindSafe;
/// # Safety /// # Safety
/// ///
/// This should not be implemented outside this module /// 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 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; 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 () { fn props_ptr(&self) -> *const () {
&self.props as *const _ as *const () &self.props as *const _ as *const ()
} }

View file

@ -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<Bump>,
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<Vec<*const Attribute<'static>>>,
pub(crate) props_to_drop_before_reset: RefCell<Vec<*const VComponent<'static>>>,
}
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() }
}
}

View file

@ -67,7 +67,7 @@ impl<'b> VirtualDom {
/// Create a new template [`VNode`] and write it to the [`Mutations`] buffer. /// 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. /// 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); self.runtime.scope_stack.borrow_mut().push(scope);
let nodes = self.create(template); let nodes = self.create(template);
self.runtime.scope_stack.borrow_mut().pop(); self.runtime.scope_stack.borrow_mut().pop();
@ -75,7 +75,7 @@ impl<'b> VirtualDom {
} }
/// Create this template and write its mutations /// 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 // check for a overriden template
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
@ -182,7 +182,7 @@ impl<'b> VirtualDom {
1 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::*; use DynamicNode::*;
match &template.dynamic_nodes[idx] { match &template.dynamic_nodes[idx] {
node @ Component { .. } | node @ Fragment(_) => { 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 /// We want to make sure we write these nodes while on top of the root
fn write_element_root( fn write_element_root(
&mut self, &mut self,
template: &'b VNode<'b>, template: &'b VNode,
root_idx: usize, root_idx: usize,
dynamic_attrs: &mut Peekable<impl Iterator<Item = (usize, &'static [u8])>>, dynamic_attrs: &mut Peekable<impl Iterator<Item = (usize, &'static [u8])>>,
dynamic_nodes_iter: &mut Peekable<impl Iterator<Item = ((usize, 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_iter: &mut Peekable<impl Iterator<Item = ((usize, usize), &'static [u8])>>,
dynamic_nodes: &[(usize, &'static [u8])], dynamic_nodes: &[(usize, &'static [u8])],
root_idx: u8, root_idx: u8,
template: &'b VNode<'b>, template: &'b VNode,
) { ) {
let (start, end) = match collect_dyn_node_range(dynamic_nodes_iter, root_idx) { let (start, end) = match collect_dyn_node_range(dynamic_nodes_iter, root_idx) {
Some((a, b)) => (a, b), Some((a, b)) => (a, b),
@ -306,7 +306,7 @@ impl<'b> VirtualDom {
attrs: &mut Peekable<impl Iterator<Item = (usize, &'static [u8])>>, attrs: &mut Peekable<impl Iterator<Item = (usize, &'static [u8])>>,
root_idx: u8, root_idx: u8,
root: ElementId, root: ElementId,
node: &'b VNode<'b>, node: &'b VNode,
) { ) {
while let Some((mut attr_id, path)) = while let Some((mut attr_id, path)) =
attrs.next_if(|(_, p)| p.first().copied() == Some(root_idx)) attrs.next_if(|(_, p)| p.first().copied() == Some(root_idx))
@ -327,7 +327,7 @@ impl<'b> VirtualDom {
fn write_attribute( fn write_attribute(
&mut self, &mut self,
template: &'b VNode<'b>, template: &'b VNode,
idx: usize, idx: usize,
attribute: &'b crate::Attribute<'b>, attribute: &'b crate::Attribute<'b>,
id: ElementId, 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 // Allocate a dynamic element reference for this text node
let new_id = self.next_element(); let new_id = self.next_element();
@ -538,7 +538,7 @@ impl<'b> VirtualDom {
pub(super) fn create_component_node( pub(super) fn create_component_node(
&mut self, &mut self,
parent: Option<ElementRef>, parent: Option<ElementRef>,
component: &'b VComponent<'b>, component: &'b VComponent,
) -> usize { ) -> usize {
use RenderReturn::*; use RenderReturn::*;

View file

@ -59,7 +59,7 @@ impl<'b> VirtualDom {
self.runtime.scope_stack.borrow_mut().pop(); 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(); let id = self.next_element();
p.id.set(Some(id)); p.id.set(Some(id));
p.parent.set(l.parent.get()); 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 // If hot reloading is enabled, we need to make sure we're using the latest template
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
@ -198,8 +198,8 @@ impl<'b> VirtualDom {
fn diff_vcomponent( fn diff_vcomponent(
&mut self, &mut self,
left: &'b VComponent<'b>, left: &'b VComponent,
right: &'b VComponent<'b>, right: &'b VComponent,
parent: Option<ElementRef>, parent: Option<ElementRef>,
) { ) {
if std::ptr::eq(left, right) { if std::ptr::eq(left, right) {
@ -249,8 +249,8 @@ impl<'b> VirtualDom {
fn replace_vcomponent( fn replace_vcomponent(
&mut self, &mut self,
right: &'b VComponent<'b>, right: &'b VComponent,
left: &'b VComponent<'b>, left: &'b VComponent,
parent: Option<ElementRef>, parent: Option<ElementRef>,
) { ) {
let m = self.create_component_node(parent, right); let m = self.create_component_node(parent, right);
@ -307,7 +307,7 @@ impl<'b> VirtualDom {
/// Component { ..props } /// 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(); let parent = left.parent.take();
match matching_components(left, right) { match matching_components(left, right) {
None => self.replace(left, [right], parent), 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 /// 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. /// 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()); let id = left.id.get().unwrap_or_else(|| self.next_element());
right.id.set(Some(id)); right.id.set(Some(id));
@ -331,12 +331,7 @@ impl<'b> VirtualDom {
} }
} }
fn diff_non_empty_fragment( fn diff_non_empty_fragment(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) {
&mut self,
old: &'b [VNode<'b>],
new: &'b [VNode<'b>],
parent: ElementRef,
) {
let new_is_keyed = new[0].key.is_some(); let new_is_keyed = new[0].key.is_some();
let old_is_keyed = old[0].key.is_some(); let old_is_keyed = old[0].key.is_some();
debug_assert!( debug_assert!(
@ -363,12 +358,7 @@ impl<'b> VirtualDom {
// [... parent] // [... parent]
// //
// the change list stack is in the same state when this function returns. // the change list stack is in the same state when this function returns.
fn diff_non_keyed_children( fn diff_non_keyed_children(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) {
&mut self,
old: &'b [VNode<'b>],
new: &'b [VNode<'b>],
parent: ElementRef,
) {
use std::cmp::Ordering; use std::cmp::Ordering;
// Handled these cases in `diff_children` before calling this function. // 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 // https://github.com/infernojs/inferno/blob/36fd96/packages/inferno/src/DOM/patching.ts#L530-L739
// //
// The stack is empty upon entry. // The stack is empty upon entry.
fn diff_keyed_children( fn diff_keyed_children(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) {
&mut self,
old: &'b [VNode<'b>],
new: &'b [VNode<'b>],
parent: ElementRef,
) {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
let mut keys = rustc_hash::FxHashSet::default(); 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(); keys.clear();
for child in children { for child in children {
let key = child.key; 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. /// If there is no offset, then this function returns None and the diffing is complete.
fn diff_keyed_ends( fn diff_keyed_ends(
&mut self, &mut self,
old: &'b [VNode<'b>], old: &'b [VNode],
new: &'b [VNode<'b>], new: &'b [VNode],
parent: ElementRef, parent: ElementRef,
) -> Option<(usize, usize)> { ) -> Option<(usize, usize)> {
let mut left_offset = 0; 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. // Upon exit from this function, it will be restored to that same self.
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
fn diff_keyed_middle( fn diff_keyed_middle(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) {
&mut self,
old: &'b [VNode<'b>],
new: &'b [VNode<'b>],
parent: ElementRef,
) {
/* /*
1. Map the old keys into a numerical ordering based on indices. 1. Map the old keys into a numerical ordering based on indices.
2. Create a map of old key to its index 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 /// 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 node.template
.get() .get()
.roots .roots
@ -783,7 +763,7 @@ impl<'b> VirtualDom {
pub(crate) fn create_children( pub(crate) fn create_children(
&mut self, &mut self,
nodes: impl IntoIterator<Item = &'b VNode<'b>>, nodes: impl IntoIterator<Item = &'b VNode>,
parent: Option<ElementRef>, parent: Option<ElementRef>,
) -> usize { ) -> usize {
nodes nodes
@ -797,8 +777,8 @@ impl<'b> VirtualDom {
fn create_and_insert_before( fn create_and_insert_before(
&mut self, &mut self,
new: &'b [VNode<'b>], new: &'b [VNode],
before: &'b VNode<'b>, before: &'b VNode,
parent: ElementRef, parent: ElementRef,
) { ) {
let m = self.create_children(new, Some(parent)); let m = self.create_children(new, Some(parent));
@ -806,12 +786,7 @@ impl<'b> VirtualDom {
self.mutations.push(Mutation::InsertBefore { id, m }) self.mutations.push(Mutation::InsertBefore { id, m })
} }
fn create_and_insert_after( fn create_and_insert_after(&mut self, new: &'b [VNode], after: &'b VNode, parent: ElementRef) {
&mut self,
new: &'b [VNode<'b>],
after: &'b VNode<'b>,
parent: ElementRef,
) {
let m = self.create_children(new, Some(parent)); let m = self.create_children(new, Some(parent));
let id = self.find_last_element(after); let id = self.find_last_element(after);
self.mutations.push(Mutation::InsertAfter { id, m }) self.mutations.push(Mutation::InsertAfter { id, m })
@ -821,7 +796,7 @@ impl<'b> VirtualDom {
fn replace_placeholder( fn replace_placeholder(
&mut self, &mut self,
l: &'b VPlaceholder, l: &'b VPlaceholder,
r: impl IntoIterator<Item = &'b VNode<'b>>, r: impl IntoIterator<Item = &'b VNode>,
parent: ElementRef, parent: ElementRef,
) { ) {
let m = self.create_children(r, Some(parent)); let m = self.create_children(r, Some(parent));
@ -832,8 +807,8 @@ impl<'b> VirtualDom {
fn replace( fn replace(
&mut self, &mut self,
left: &'b VNode<'b>, left: &'b VNode,
right: impl IntoIterator<Item = &'b VNode<'b>>, right: impl IntoIterator<Item = &'b VNode>,
parent: Option<ElementRef>, parent: Option<ElementRef>,
) { ) {
let m = self.create_children(right, parent); 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 // Create the placeholder first, ensuring we get a dedicated ID for the placeholder
let placeholder = self.next_element(); let placeholder = self.next_element();
@ -878,14 +853,14 @@ impl<'b> VirtualDom {
/// Remove these nodes from the dom /// Remove these nodes from the dom
/// Wont generate mutations for the inner nodes /// 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 nodes
.iter() .iter()
.rev() .rev()
.for_each(|node| self.remove_node(node, true)); .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 // Clean up any attributes that have claimed a static node as dynamic for mount/unmounta
// Will not generate mutations! // Will not generate mutations!
self.reclaim_attributes(node); self.reclaim_attributes(node);
@ -903,7 +878,7 @@ impl<'b> VirtualDom {
self.reclaim_vnode_id(node); 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 // Clean up the vnode id
if let Some(id) = node.stable_id() { if let Some(id) = node.stable_id() {
self.element_refs.remove(id.0); self.element_refs.remove(id.0);
@ -1025,7 +1000,7 @@ impl<'b> VirtualDom {
self.drop_scope(scope, false); 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) { match node.dynamic_root(0) {
None => node.root_ids.borrow()[0], None => node.root_ids.borrow()[0],
Some(Text(t)) => t.id.get().unwrap(), 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) { match node.dynamic_root(node.template.get().roots.len() - 1) {
None => *node.root_ids.borrow().last().unwrap(), None => *node.root_ids.borrow().last().unwrap(),
Some(Text(t)) => t.id.get().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<ElementRef>, child: &'b VNode<'b>) { pub(crate) fn assign_boundary_ref(&mut self, parent: Option<ElementRef>, child: &'b VNode) {
if let Some(parent) = parent { if let Some(parent) = parent {
// assign the parent of the child // assign the parent of the child
child.parent.set(Some(parent)); 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 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 /// 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) 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>( fn matching_components<'a>(
left: &'a VNode<'a>, left: &'a VNode,
right: &'a VNode<'a>, right: &'a VNode,
) -> Option<Vec<(&'a VComponent<'a>, &'a VComponent<'a>)>> { ) -> Option<Vec<(&'a VComponent, &'a VComponent)>> {
let left_template = left.template.get(); let left_template = left.template.get();
let right_template = right.template.get(); let right_template = right.template.get();
if left_template.roots.len() != right_template.roots.len() { if left_template.roots.len() != right_template.roots.len() {

View file

@ -262,7 +262,7 @@ impl<T> Throw for Option<T> {
} }
} }
pub struct ErrorHandler<'a>(Box<dyn Fn(CapturedError) -> LazyNodes<'a, 'a> + 'a>); pub struct ErrorHandler(Box<dyn Fn(CapturedError) -> LazyNodes<'a, 'a>>);
impl<'a, F: Fn(CapturedError) -> LazyNodes<'a, 'a> + 'a> From<F> for ErrorHandler<'a> { impl<'a, F: Fn(CapturedError) -> LazyNodes<'a, 'a> + 'a> From<F> for ErrorHandler<'a> {
fn from(value: F) -> Self { fn from(value: F) -> Self {
Self(Box::new(value)) Self(Box::new(value))
@ -290,7 +290,7 @@ fn default_handler<'a>(error: CapturedError) -> LazyNodes<'a, 'a> {
stable_id: Default::default(), stable_id: Default::default(),
key: None, key: None,
template: std::cell::Cell::new(TEMPLATE), 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 dynamic_nodes: __cx
.bump() .bump()
.alloc([__cx.text_node(format_args!("{0}", error))]), .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> { pub struct ErrorBoundaryProps {
children: Element<'a>, children: Element,
handle_error: ErrorHandler<'a>, handle_error: ErrorHandler,
} }
impl<'a> ErrorBoundaryProps<'a> { impl ErrorBoundaryProps {
/** /**
Create a builder for building `ErrorBoundaryProps`. Create a builder for building `ErrorBoundaryProps`.
On the builder, call `.children(...)`(optional), `.handle_error(...)`(optional) to set the values of the fields. 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`. Finally, call `.build()` to create the instance of `ErrorBoundaryProps`.
*/ */
#[allow(dead_code)] #[allow(dead_code)]
pub fn builder() -> ErrorBoundaryPropsBuilder<'a, ((), ())> { pub fn builder() -> ErrorBoundaryPropsBuilder<((), ())> {
ErrorBoundaryPropsBuilder { ErrorBoundaryPropsBuilder { fields: ((), ()) }
fields: ((), ()),
_phantom: ::core::default::Default::default(),
}
} }
} }
#[must_use] #[must_use]
#[doc(hidden)] #[doc(hidden)]
#[allow(dead_code, non_camel_case_types, non_snake_case)] #[allow(dead_code, non_camel_case_types, non_snake_case)]
pub struct ErrorBoundaryPropsBuilder<'a, TypedBuilderFields> { pub struct ErrorBoundaryPropsBuilder<TypedBuilderFields> {
fields: TypedBuilderFields, fields: TypedBuilderFields,
_phantom: ::core::marker::PhantomData<&'a ()>,
} }
impl<'a, TypedBuilderFields> Clone for ErrorBoundaryPropsBuilder<'a, TypedBuilderFields> impl<TypedBuilderFields> Clone for ErrorBoundaryPropsBuilder<TypedBuilderFields>
where where
TypedBuilderFields: Clone, TypedBuilderFields: Clone,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
fields: self.fields.clone(), fields: self.fields.clone(),
_phantom: ::core::default::Default::default(),
} }
} }
} }
impl<'a> Properties for ErrorBoundaryProps<'a> { impl Properties for ErrorBoundaryProps {
type Builder = ErrorBoundaryPropsBuilder<'a, ((), ())>; type Builder = ErrorBoundaryPropsBuilder<((), ())>;
const IS_STATIC: bool = false;
fn builder() -> Self::Builder { fn builder() -> Self::Builder {
ErrorBoundaryProps::builder() ErrorBoundaryProps::builder()
} }

View file

@ -147,7 +147,7 @@ impl<T> Default for EventHandler<'_, T> {
} }
} }
type ExternalListenerCallback<'bump, T> = bumpalo::boxed::Box<'bump, dyn FnMut(T) + 'bump>; type ExternalListenerCallback<'bump, T> = Box<dyn FnMut(T)>;
impl<T> EventHandler<'_, T> { impl<T> EventHandler<'_, T> {
/// Call this event handler with the appropriate event type /// Call this event handler with the appropriate event type

View file

@ -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. /// 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)] #[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()?; let children = cx.props.0.as_ref()?;
Some(VNode { Some(VNode {
key: children.key, key: children.key,
@ -92,8 +92,8 @@ impl<const A: bool> FragmentBuilder<A> {
/// }) /// })
/// } /// }
/// ``` /// ```
impl<'a> Properties for FragmentProps<'a> { impl<'a> Properties for FragmentProps {
type Builder = FragmentBuilder<'a, false>; type Builder = FragmentBuilder<false>;
fn builder() -> Self::Builder { fn builder() -> Self::Builder {
FragmentBuilder(None) FragmentBuilder(None)
} }

View file

@ -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 <https://docs.rs/stack_dst/0.6.1/stack_dst/>. Unfortunately, this crate does not
//! support non-static closures, so we've implemented the core logic of `ValueA` in this module.
#[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 <https://dioxuslabs.com/learn/0.4/contributing/walkthrough_readme#the-rsx-macro>
pub struct LazyNodes<'a, 'b> {
#[cfg(not(miri))]
inner: SmallBox<dyn FnMut(&'a ScopeState) -> VNode<'a> + 'b, S16>,
#[cfg(miri)]
inner: Box<dyn FnMut(&'a ScopeState) -> 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)
}
}

View file

@ -5,7 +5,6 @@
mod any_props; mod any_props;
mod arena; mod arena;
mod bump_frame;
mod create; mod create;
mod diff; mod diff;
mod dirty_scope; 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 [`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. /// An Errored [`Element`] will propagate the error to the nearest error boundary.
pub type Element<'a> = Option<VNode<'a>>; pub type Element = Option<VNode>;
/// A [`Component`] is a function that takes a [`Scope`] and returns an [`Element`]. /// A [`Component`] is a function that takes a [`Scope`] and returns an [`Element`].
/// ///
@ -97,9 +96,3 @@ pub mod prelude {
VNode, VirtualDom, 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;
}

View file

@ -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 /// 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. /// 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 /// A currently-available element
Ready(VNode<'a>), Ready(VNode),
/// The component aborted rendering early. It might've thrown an error. /// The component aborted rendering early. It might've thrown an error.
/// ///
@ -30,7 +30,7 @@ pub enum RenderReturn<'a> {
Aborted(VPlaceholder), Aborted(VPlaceholder),
} }
impl<'a> Default for RenderReturn<'a> { impl Default for RenderReturn {
fn default() -> Self { fn default() -> Self {
RenderReturn::Aborted(VPlaceholder::default()) RenderReturn::Aborted(VPlaceholder::default())
} }
@ -88,11 +88,11 @@ impl VNode {
/// Create a new VNode /// Create a new VNode
pub fn new( pub fn new(
key: Option<&'a str>, key: Option<String>,
template: Template<'static>, template: Template<'static>,
root_ids: bumpalo::collections::Vec<'a, ElementId>, root_ids: Vec<ElementId>,
dynamic_nodes: &'a [DynamicNode<'a>], dynamic_nodes: &'a [DynamicNode],
dynamic_attrs: &'a [Attribute<'a>], dynamic_attrs: &'a [Attribute],
) -> Self { ) -> Self {
Self { Self {
key, key,
@ -113,7 +113,7 @@ impl VNode {
/// Load a dynamic root at the given index /// Load a dynamic root at the given index
/// ///
/// Returns [`None`] if the root is actually a static node (Element/Text) /// 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] { match &self.template.get().roots[idx] {
TemplateNode::Element { .. } | TemplateNode::Text { text: _ } => None, TemplateNode::Element { .. } | TemplateNode::Text { text: _ } => None,
TemplateNode::Dynamic { id } | TemplateNode::DynamicText { id } => { 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. /// Unlike react, calls to `rsx!` can have multiple roots. This list supports that paradigm.
#[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))] #[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. /// 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), derive(serde::Serialize, serde::Deserialize),
serde(tag = "type") serde(tag = "type")
)] )]
pub enum TemplateNode<'a> { pub enum TemplateNode {
/// An statically known element in the dom. /// An statically known element in the dom.
/// ///
/// In HTML this would be something like `<div id="123"> </div>` /// In HTML this would be something like `<div id="123"> </div>`
@ -250,7 +250,7 @@ pub enum TemplateNode<'a> {
/// The name of the element /// The name of the element
/// ///
/// IE for a div, it would be the string "div" /// IE for a div, it would be the string "div"
tag: &'a str, tag: &'static str,
/// The namespace of the element /// The namespace of the element
/// ///
@ -260,23 +260,23 @@ pub enum TemplateNode<'a> {
feature = "serialize", feature = "serialize",
serde(deserialize_with = "deserialize_option_leaky") serde(deserialize_with = "deserialize_option_leaky")
)] )]
namespace: Option<&'a str>, namespace: Option<&'static str>,
/// A list of possibly dynamic attribues for this element /// 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"`. /// 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"))] #[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 /// A list of template nodes that define another set of template nodes
#[cfg_attr(feature = "serialize", serde(deserialize_with = "deserialize_leaky"))] #[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 /// This template node is just a piece of static text
Text { Text {
/// The actual text /// The actual text
text: &'a str, text: &'static str,
}, },
/// This template node is unknown, and needs to be created at runtime. /// 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 /// This node's index in the DynamicNode list on VNode should match its repsective `Dynamic` index
#[derive(Debug)] #[derive(Debug)]
pub enum DynamicNode<'a> { pub enum DynamicNode {
/// A component node /// A component node
/// ///
/// Most of the time, Dioxus will actually know which component this is as compile time, but the props and /// 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 actual VComponent can be dynamic between two VNodes, though, allowing implementations to swap
/// the render function at runtime /// the render function at runtime
Component(VComponent<'a>), Component(VComponent),
/// A text node /// A text node
Text(VText<'a>), Text(VText),
/// A placeholder /// 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 /// Note that this is not a list of dynamic nodes. These must be VNodes and created through conditional rendering
/// or iterators. /// or iterators.
Fragment(&'a [VNode<'a>]), Fragment(&'static [VNode]),
} }
impl Default for DynamicNode<'_> { impl Default for DynamicNode {
fn default() -> Self { fn default() -> Self {
Self::Placeholder(Default::default()) Self::Placeholder(Default::default())
} }
} }
/// An instance of a child component /// An instance of a child component
pub struct VComponent<'a> { pub struct VComponent {
/// The name of this component /// The name of this component
pub name: &'static str, 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 /// The assigned Scope for this component
pub(crate) scope: Cell<Option<ScopeId>>, pub(crate) scope: Cell<Option<ScopeId>>,
@ -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 /// 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) render_fn: *const (),
pub(crate) props: RefCell<Option<Box<dyn AnyProps<'a> + 'a>>>, pub(crate) props: RefCell<Option<Box<dyn AnyProps>>>,
} }
impl<'a> VComponent<'a> { impl<'a> VComponent {
/// Get the scope that this component is mounted to /// Get the scope that this component is mounted to
pub fn mounted_scope(&self) -> Option<ScopeId> { pub fn mounted_scope(&self) -> Option<ScopeId> {
self.scope.get() 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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("VComponent") f.debug_struct("VComponent")
.field("name", &self.name) .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 /// An instance of some text, mounted to the DOM
#[derive(Debug)] #[derive(Debug)]
pub struct VText<'a> { pub struct VText {
/// The actual text itself /// The actual text itself
pub value: &'a str, pub value: String,
/// The ID of this node in the real DOM /// The ID of this node in the real DOM
pub(crate) id: Cell<Option<ElementId>>, pub(crate) id: Cell<Option<ElementId>>,
} }
impl<'a> VText<'a> { impl<'a> VText {
/// Create a new VText /// Create a new VText
pub fn new(value: &'a str) -> Self { pub fn new(value: String) -> Self {
Self { Self {
value, value,
id: Default::default(), id: Default::default(),
@ -419,21 +412,21 @@ impl VPlaceholder {
derive(serde::Serialize, serde::Deserialize), derive(serde::Serialize, serde::Deserialize),
serde(tag = "type") serde(tag = "type")
)] )]
pub enum TemplateAttribute<'a> { pub enum TemplateAttribute {
/// This attribute is entirely known at compile time, enabling /// This attribute is entirely known at compile time, enabling
Static { Static {
/// The name of this attribute. /// The name of this attribute.
/// ///
/// For example, the `href` attribute in `href="https://example.com"`, would have the name "href" /// 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 /// 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 /// 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 /// 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 /// 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"` /// An attribute on a DOM node, such as `id="my-thing"` or `href="https://example.com"`
#[derive(Debug)] #[derive(Debug)]
pub struct Attribute<'a> { pub struct Attribute {
/// The name of the attribute. /// The name of the attribute.
pub name: &'a str, pub name: &'static str,
/// The value of the attribute /// The value of the attribute
pub value: AttributeValue<'a>, pub value: AttributeValue,
/// The namespace of the attribute. /// The namespace of the attribute.
/// ///
@ -466,11 +459,11 @@ pub struct Attribute<'a> {
pub(crate) mounted_element: Cell<ElementId>, pub(crate) mounted_element: Cell<ElementId>,
} }
impl<'a> Attribute<'a> { impl Attribute {
/// Create a new attribute /// Create a new attribute
pub fn new( pub fn new(
name: &'a str, name: &'static str,
value: AttributeValue<'a>, value: AttributeValue,
namespace: Option<&'static str>, namespace: Option<&'static str>,
volatile: bool, volatile: bool,
) -> Self { ) -> 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`] /// These are built-in to be faster during the diffing process. To use a custom value, use the [`AttributeValue::Any`]
/// variant. /// variant.
pub enum AttributeValue<'a> { pub enum AttributeValue {
/// Text attribute /// Text attribute
Text(&'a str), Text(String),
/// A float /// A float
Float(f64), Float(f64),
@ -507,16 +500,16 @@ pub enum AttributeValue<'a> {
Bool(bool), Bool(bool),
/// A listener, like "onclick" /// A listener, like "onclick"
Listener(RefCell<Option<ListenerCb<'a>>>), Listener(RefCell<Option<ListenerCb>>),
/// An arbitrary value that implements PartialEq and is static /// An arbitrary value that implements PartialEq and is static
Any(RefCell<Option<BumpBox<'a, dyn AnyValue>>>), Any(RefCell<Option<Box<dyn AnyValue>>>),
/// A "none" value, resulting in the removal of an attribute from the dom /// A "none" value, resulting in the removal of an attribute from the dom
None, None,
} }
pub type ListenerCb<'a> = BumpBox<'a, dyn FnMut(Event<dyn Any>) + 'a>; pub type ListenerCb = Box<dyn FnMut(Event<dyn Any>)>;
/// Any of the built-in values that the Dioxus VirtualDom supports as dynamic attributes on elements that are borrowed /// 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, None,
} }
impl<'a> From<&'a AttributeValue<'a>> for BorrowedAttributeValue<'a> { impl<'a> From<&'a AttributeValue> for BorrowedAttributeValue<'a> {
fn from(value: &'a AttributeValue<'a>) -> Self { fn from(value: &'a AttributeValue) -> Self {
match value { match value {
AttributeValue::Text(value) => BorrowedAttributeValue::Text(value), AttributeValue::Text(value) => BorrowedAttributeValue::Text(value),
AttributeValue::Float(value) => BorrowedAttributeValue::Float(*value), AttributeValue::Float(value) => BorrowedAttributeValue::Float(*value),
@ -613,7 +606,7 @@ where
panic!("Any cannot be deserialized") 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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::Text(arg0) => f.debug_tuple("Text").field(arg0).finish(), 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 { fn eq(&self, other: &Self) -> bool {
match (self, other) { match (self, other) {
(Self::Text(l0), Self::Text(r0)) => l0 == r0, (Self::Text(l0), Self::Text(r0)) => l0 == r0,
@ -668,42 +661,33 @@ impl<T: Any + PartialEq + 'static> 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 /// 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, A = ()> {
/// Consume this item along with a scopestate and produce a DynamicNode /// 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 /// 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 () { 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() DynamicNode::default()
} }
} }
impl<'a> IntoDynNode<'a> for VNode<'a> { impl<'a> IntoDynNode<'a> for VNode {
fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode<'a> { fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode {
DynamicNode::Fragment(_cx.bump().alloc([self])) DynamicNode::Fragment(_cx.bump().alloc([self]))
} }
} }
impl<'a> IntoDynNode<'a> for DynamicNode<'a> { impl<'a> IntoDynNode<'a> for DynamicNode {
fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode<'a> { fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode {
self self
} }
} }
impl<'a, T: IntoDynNode<'a>> IntoDynNode<'a> for Option<T> { impl<'a, T: IntoDynNode<'a>> IntoDynNode<'a> for Option<T> {
fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode<'a> { fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode {
match self { match self {
Some(val) => val.into_dyn_node(_cx), Some(val) => val.into_dyn_node(_cx),
None => DynamicNode::default(), None => DynamicNode::default(),
@ -711,8 +695,8 @@ impl<'a, T: IntoDynNode<'a>> IntoDynNode<'a> for Option<T> {
} }
} }
impl<'a> IntoDynNode<'a> for &Element<'a> { impl<'a> IntoDynNode<'a> for &Element {
fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode<'a> { fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode {
match self.as_ref() { match self.as_ref() {
Some(val) => val.clone().into_dyn_node(_cx), Some(val) => val.clone().into_dyn_node(_cx),
_ => DynamicNode::default(), _ => DynamicNode::default(),
@ -721,13 +705,13 @@ impl<'a> IntoDynNode<'a> for &Element<'a> {
} }
impl<'a, 'b> IntoDynNode<'a> for LazyNodes<'a, 'b> { 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()])) DynamicNode::Fragment(cx.bump().alloc([cx.render(self).unwrap()]))
} }
} }
impl<'a, 'b> IntoDynNode<'b> for &'a str { 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 { DynamicNode::Text(VText {
value: cx.bump().alloc_str(self), value: cx.bump().alloc_str(self),
id: Default::default(), id: Default::default(),
@ -745,13 +729,13 @@ impl IntoDynNode<'_> for String {
} }
impl<'b> IntoDynNode<'b> for Arguments<'_> { 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) cx.text_node(self)
} }
} }
impl<'a> IntoDynNode<'a> for &'a VNode<'a> { impl<'a> IntoDynNode<'a> for &'a VNode {
fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode<'a> { fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode {
DynamicNode::Fragment(_cx.bump().alloc([VNode { DynamicNode::Fragment(_cx.bump().alloc([VNode {
parent: self.parent.clone(), parent: self.parent.clone(),
stable_id: self.stable_id.clone(), stable_id: self.stable_id.clone(),
@ -764,24 +748,24 @@ impl<'a> IntoDynNode<'a> for &'a VNode<'a> {
} }
} }
pub trait IntoVNode<'a> { pub trait IntoVNode {
fn into_vnode(self, _cx: &'a ScopeState) -> VNode<'a>; fn into_vnode(self) -> VNode;
} }
impl<'a> IntoVNode<'a> for VNode<'a> { impl<'a> IntoVNode for VNode {
fn into_vnode(self, _cx: &'a ScopeState) -> VNode<'a> { fn into_vnode(self) -> VNode {
self self
} }
} }
impl<'a> IntoVNode<'a> for Element<'a> { impl<'a> IntoVNode for Element {
fn into_vnode(self, cx: &'a ScopeState) -> VNode<'a> { fn into_vnode(self) -> VNode {
match self { match self {
Some(val) => val.into_vnode(cx), Some(val) => val.into_vnode(cx),
_ => VNode::empty(cx).unwrap(), _ => VNode::empty().unwrap(),
} }
} }
} }
impl<'a, 'b> IntoVNode<'a> for LazyNodes<'a, 'b> { impl<'a, 'b> IntoVNode for LazyNodes<'a, 'b> {
fn into_vnode(self, cx: &'a ScopeState) -> VNode<'a> { fn into_vnode(self) -> VNode {
cx.render(self).unwrap() cx.render(self).unwrap()
} }
} }
@ -791,9 +775,9 @@ pub struct FromNodeIterator;
impl<'a, T, I> IntoDynNode<'a, FromNodeIterator> for T impl<'a, T, I> IntoDynNode<'a, FromNodeIterator> for T
where where
T: Iterator<Item = I>, T: Iterator<Item = I>,
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()); let mut nodes = bumpalo::collections::Vec::new_in(cx.bump());
nodes.extend(self.into_iter().map(|node| node.into_vnode(cx))); nodes.extend(self.into_iter().map(|node| node.into_vnode(cx)));

View file

@ -32,7 +32,7 @@ use crate::innerlude::*;
/// data: &'a str /// data: &'a str
/// } /// }
/// ``` /// ```
pub trait Properties: Sized + 'static { pub trait Properties: Clone + Sized + 'static {
/// The type of the builder for this component. /// The type of the builder for this component.
/// Used to create "in-progress" versions of the props. /// Used to create "in-progress" versions of the props.
type Builder; 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 /// This utility function launches the builder method so rsx! and html! macros can use the typed-builder pattern
/// to initialize a component's props. /// 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() T::builder()
} }

View file

@ -1,6 +1,5 @@
use crate::{ use crate::{
any_props::AnyProps, any_props::AnyProps,
bump_frame::BumpFrame,
innerlude::DirtyScope, innerlude::DirtyScope,
nodes::RenderReturn, nodes::RenderReturn,
scope_context::ScopeContext, scope_context::ScopeContext,
@ -11,7 +10,7 @@ use crate::{
impl VirtualDom { impl VirtualDom {
pub(super) fn new_scope( pub(super) fn new_scope(
&mut self, &mut self,
props: Box<dyn AnyProps<'static>>, props: Box<dyn AnyProps>,
name: &'static str, name: &'static str,
) -> &ScopeState { ) -> &ScopeState {
let parent_id = self.runtime.current_scope_id(); let parent_id = self.runtime.current_scope_id();
@ -27,9 +26,6 @@ impl VirtualDom {
props: Some(props), props: Some(props),
node_arena_1: BumpFrame::new(0),
node_arena_2: BumpFrame::new(0),
render_cnt: Default::default(), render_cnt: Default::default(),
hooks: Default::default(), hooks: Default::default(),
hook_idx: Default::default(), hook_idx: Default::default(),

View file

@ -301,7 +301,7 @@ pub fn provide_root_context<T: 'static + Clone>(value: T) -> Option<T> {
} }
/// Suspends the current component /// Suspends the current component
pub fn suspend() -> Option<Element<'static>> { pub fn suspend() -> Option<Element> {
with_current_scope(|cx| { with_current_scope(|cx| {
cx.suspend(); cx.suspend();
}); });

View file

@ -1,16 +1,13 @@
use crate::{ use crate::{
any_props::AnyProps, any_props::AnyProps,
any_props::VProps, any_props::VProps,
bump_frame::BumpFrame,
innerlude::ErrorBoundary, innerlude::ErrorBoundary,
innerlude::{DynamicNode, EventHandler, VComponent, VNodeId, VText}, innerlude::{DynamicNode, EventHandler, VComponent, VNodeId, VText},
lazynodes::LazyNodes,
nodes::{IntoAttributeValue, IntoDynNode, RenderReturn}, nodes::{IntoAttributeValue, IntoDynNode, RenderReturn},
runtime::Runtime, runtime::Runtime,
scope_context::ScopeContext, scope_context::ScopeContext,
AnyValue, Attribute, AttributeValue, Element, Event, Properties, TaskId, AnyValue, Attribute, AttributeValue, Element, Event, Properties, TaskId,
}; };
use bumpalo::{boxed::Box as BumpBox, Bump};
use std::{ use std::{
any::Any, any::Any,
cell::{Cell, Ref, RefCell, UnsafeCell}, cell::{Cell, Ref, RefCell, UnsafeCell},
@ -90,11 +87,11 @@ pub struct ScopeState {
pub(crate) hooks: RefCell<Vec<Box<UnsafeCell<dyn Any>>>>, pub(crate) hooks: RefCell<Vec<Box<UnsafeCell<dyn Any>>>>,
pub(crate) hook_idx: Cell<usize>, pub(crate) hook_idx: Cell<usize>,
pub(crate) borrowed_props: RefCell<Vec<*const VComponent<'static>>>, pub(crate) borrowed_props: RefCell<Vec<*const VComponent>>,
pub(crate) element_refs_to_drop: RefCell<Vec<VNodeId>>, pub(crate) element_refs_to_drop: RefCell<Vec<VNodeId>>,
pub(crate) attributes_to_drop_before_render: RefCell<Vec<*const Attribute<'static>>>, pub(crate) attributes_to_drop_before_render: RefCell<Vec<*const Attribute>>,
pub(crate) props: Option<Box<dyn AnyProps<'static>>>, pub(crate) props: Option<Box<dyn AnyProps>>,
} }
impl Drop for ScopeState { impl Drop for ScopeState {
@ -108,22 +105,6 @@ impl<'src> ScopeState {
self.runtime.get_context(self.context_id).unwrap() 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 /// Get the name of this component
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
self.context().name self.context().name
@ -136,17 +117,6 @@ impl<'src> ScopeState {
self.render_cnt.get() 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 /// 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. /// 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) /// 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 element = rsx.call(self);
let mut listeners = self.attributes_to_drop_before_render.borrow_mut(); 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 /// 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 { DynamicNode::Text(VText {
value: self.raw_text(args), value: self.raw_text(args),
id: Default::default(), 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 /// 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 { pub fn make_node<'c, I>(&'src self, into: impl IntoDynNode<'src, I> + 'c) -> DynamicNode {
into.into_dyn_node(self) into.into_dyn_node(self)
@ -417,7 +375,7 @@ impl<'src> ScopeState {
value: impl IntoAttributeValue<'src>, value: impl IntoAttributeValue<'src>,
namespace: Option<&'static str>, namespace: Option<&'static str>,
volatile: bool, volatile: bool,
) -> Attribute<'src> { ) -> Attribute {
Attribute { Attribute {
name, name,
namespace, namespace,
@ -443,10 +401,10 @@ impl<'src> ScopeState {
/// ``` /// ```
pub fn component<'child, P>( pub fn component<'child, P>(
&'src self, &'src self,
component: fn(Scope<'child, P>) -> Element<'child>, component: fn(Scope<'child, P>) -> Element,
props: P, props: P,
fn_name: &'static str, fn_name: &'static str,
) -> DynamicNode<'src> ) -> DynamicNode
where where
// The properties must be valid until the next bump frame // The properties must be valid until the next bump frame
P: Properties + 'src, P: Properties + 'src,
@ -456,13 +414,12 @@ impl<'src> ScopeState {
let vcomp = VProps::new(component, P::memoize, props); let vcomp = VProps::new(component, P::memoize, props);
// cast off the lifetime of the render return // cast off the lifetime of the render return
let as_dyn: Box<dyn AnyProps<'child> + '_> = Box::new(vcomp); let as_dyn: Box<dyn AnyProps + '_> = Box::new(vcomp);
let extended: Box<dyn AnyProps<'src> + 'src> = unsafe { std::mem::transmute(as_dyn) }; let extended: Box<dyn AnyProps + 'src> = unsafe { std::mem::transmute(as_dyn) };
DynamicNode::Component(VComponent { DynamicNode::Component(VComponent {
name: fn_name, name: fn_name,
render_fn: component as *const (), render_fn: component as *const (),
static_props: P::IS_STATIC,
props: RefCell::new(Some(extended)), props: RefCell::new(Some(extended)),
scope: Default::default(), scope: Default::default(),
}) })
@ -470,9 +427,9 @@ impl<'src> ScopeState {
/// Create a new [`EventHandler`] from an [`FnMut`] /// Create a new [`EventHandler`] from an [`FnMut`]
pub fn event_handler<T>(&'src self, f: impl FnMut(T) + 'src) -> EventHandler<'src, T> { pub fn event_handler<T>(&'src self, f: impl FnMut(T) + 'src) -> EventHandler<'src, T> {
let handler: &mut dyn FnMut(T) = self.bump().alloc(f); let callback = RefCell::new(Some(Box::new(move |event: Event<T>| {
let caller = unsafe { BumpBox::from_raw(handler as *mut dyn FnMut(T)) }; f(event.data);
let callback = RefCell::new(Some(caller)); })));
EventHandler { EventHandler {
callback, callback,
origin: self.context().id, origin: self.context().id,
@ -485,34 +442,22 @@ impl<'src> ScopeState {
pub fn listener<T: 'static>( pub fn listener<T: 'static>(
&'src self, &'src self,
mut callback: impl FnMut(Event<T>) + 'src, mut callback: impl FnMut(Event<T>) + 'src,
) -> AttributeValue<'src> { ) -> AttributeValue {
// safety: there's no other way to create a dynamicly-dispatched bump box other than alloc + from-raw AttributeValue::Listener(RefCell::new(Some(Box::new(
// This is the suggested way to build a bumpbox move |event: Event<dyn Any>| {
//
// 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<dyn Any>| {
if let Ok(data) = event.data.downcast::<T>() { if let Ok(data) = event.data.downcast::<T>() {
callback(Event { callback(Event {
propagates: event.propagates, propagates: event.propagates,
data, data,
}); });
} }
})) },
}; ))))
AttributeValue::Listener(RefCell::new(Some(boxed)))
} }
/// Create a new [`AttributeValue`] with a value that implements [`AnyValue`] /// Create a new [`AttributeValue`] with a value that implements [`AnyValue`]
pub fn any_value<T: AnyValue>(&'src self, value: T) -> AttributeValue<'src> { pub fn any_value<T: AnyValue>(&'src self, value: T) -> AttributeValue {
// safety: there's no other way to create a dynamicly-dispatched bump box other than alloc + from-raw AttributeValue::Any(RefCell::new(Some(Box::new(value))))
// 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)))
} }
/// Mark this component as suspended and then return None /// Mark this component as suspended and then return None

View file

@ -16,7 +16,9 @@ use crate::{
use futures_util::{pin_mut, StreamExt}; use futures_util::{pin_mut, StreamExt};
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use slab::Slab; 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. /// A virtual node system that progresses user events and diffs UI trees.
/// ///
@ -186,7 +188,7 @@ pub struct VirtualDom {
pub(crate) templates: FxHashMap<TemplateId, FxHashMap<usize, Template<'static>>>, pub(crate) templates: FxHashMap<TemplateId, FxHashMap<usize, Template<'static>>>,
// Every element is actually a dual reference - one to the template and the other to the dynamic node in that template // 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<Option<NonNull<VNode<'static>>>>, pub(crate) element_refs: Slab<Option<NonNull<VNode>>>,
// The element ids that are used in the renderer // The element ids that are used in the renderer
pub(crate) elements: Slab<Option<ElementRef>>, pub(crate) elements: Slab<Option<ElementRef>>,

View file

@ -9,7 +9,7 @@ macro_rules! impl_event {
$( $(
$( #[$attr] )* $( #[$attr] )*
#[inline] #[inline]
pub fn $name<'a, E: crate::EventReturn<T>, 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>, T>(_cx: &'a ::dioxus_core::ScopeState, mut _f: impl FnMut(::dioxus_core::Event<$data>) -> E + 'a) -> ::dioxus_core::Attribute {
::dioxus_core::Attribute::new( ::dioxus_core::Attribute::new(
stringify!($name), stringify!($name),
_cx.listener(move |e: ::dioxus_core::Event<$data>| { _cx.listener(move |e: ::dioxus_core::Event<$data>| {

View file

@ -151,7 +151,7 @@ impl_event! {
pub fn ondoubleclick<'a, E: crate::EventReturn<T>, T>( pub fn ondoubleclick<'a, E: crate::EventReturn<T>, T>(
_cx: &'a ::dioxus_core::ScopeState, _cx: &'a ::dioxus_core::ScopeState,
mut _f: impl FnMut(::dioxus_core::Event<MouseData>) -> E + 'a, mut _f: impl FnMut(::dioxus_core::Event<MouseData>) -> E + 'a,
) -> ::dioxus_core::Attribute<'a> { ) -> ::dioxus_core::Attribute {
::dioxus_core::Attribute::new( ::dioxus_core::Attribute::new(
"ondblclick", "ondblclick",
_cx.listener(move |e: ::dioxus_core::Event<MouseData>| { _cx.listener(move |e: ::dioxus_core::Event<MouseData>| {