mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-12-11 13:22:35 +00:00
rip out more lifetimes
This commit is contained in:
parent
c9ff449e45
commit
3ad16ddd37
18 changed files with 165 additions and 456 deletions
|
@ -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 }
|
||||||
|
|
||||||
|
|
|
@ -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 ()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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::*;
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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)));
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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();
|
||||||
});
|
});
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>>,
|
||||||
|
|
|
@ -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>| {
|
||||||
|
|
|
@ -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>| {
|
||||||
|
|
Loading…
Reference in a new issue