remove more lifetimes

This commit is contained in:
Evan Almloff committed 2024-01-05 08:39:22 -06:00
1 parent 3ad16ddd37
commit f42ef3ef9d
18 files changed
+241 -421

No files matched your search

+2 -2
View File
@@ -14,10 +14,10 @@ fn app(cx: Scope) -> Element {
#[derive(Props)] #[derive(Props)]
struct Testing<'a> { struct Testing<'a> {
borrowed: &'a RefCell<Vec<Element<'a>>>, borrowed: &'a RefCell<Vec<Element>>,
} }
fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element<'a> { fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element {
let Testing { borrowed } = cx.props; let Testing { borrowed } = cx.props;
let borrowed_temporary_data = let borrowed_temporary_data =
cx.use_hook(|| String::from("This data is only valid for the lifetime of the child")); cx.use_hook(|| String::from("This data is only valid for the lifetime of the child"));
@@ -17,7 +17,7 @@ struct Testing<'a> {
borrowed: &'a Vec<u32>, borrowed: &'a Vec<u32>,
} }
fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element<'a> { fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element {
cx.render(rsx! { cx.render(rsx! {
div { "{cx.props.borrowed:?}" } div { "{cx.props.borrowed:?}" }
}) })
+14 -35
View File
@@ -1,9 +1,4 @@
use crate::{ use crate::{nodes::RenderReturn, scopes::ScopeState, Element};
innerlude::Scoped,
nodes::RenderReturn,
scopes::{Scope, ScopeState},
Element,
};
use std::panic::AssertUnwindSafe; use std::panic::AssertUnwindSafe;
/// A trait that essentially allows VComponentProps to be used generically /// A trait that essentially allows VComponentProps to be used generically
@@ -11,24 +6,19 @@ 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 { pub(crate) trait AnyProps {
fn props_ptr(&self) -> *const (); fn render<'a>(&'a self, bump: &'a ScopeState) -> RenderReturn;
fn render<'a>(&'a self, bump: &'a ScopeState) -> RenderReturn<'a>; fn memoize(&self, other: &dyn AnyProps) -> bool;
unsafe fn memoize(&self, other: &dyn AnyProps) -> bool;
} }
pub(crate) struct VProps<'a, P> { pub(crate) struct VProps<P> {
pub render_fn: fn(Scope<'a, P>) -> Element<'a>, pub render_fn: fn(P) -> Element,
pub memo: unsafe fn(&P, &P) -> bool, pub memo: fn(&P, &P) -> bool,
pub props: P, pub props: P,
} }
impl<'a, P> VProps<'a, P> { impl<P> VProps<P> {
pub(crate) fn new( pub(crate) fn new(render_fn: fn(P) -> Element, memo: fn(&P, &P) -> bool, props: P) -> Self {
render_fn: fn(Scope<'a, P>) -> Element<'a>,
memo: unsafe fn(&P, &P) -> bool,
props: P,
) -> Self {
Self { Self {
render_fn, render_fn,
memo, memo,
@@ -37,30 +27,19 @@ impl<'a, P> VProps<'a, P> {
} }
} }
unsafe impl<'a, P> AnyProps for VProps<'a, P> { impl<P: Clone> AnyProps for VProps<P> {
fn props_ptr(&self) -> *const () {
&self.props as *const _ as *const ()
}
// Safety: // Safety:
// this will downcast the other ptr as our swallowed type! // this will downcast the other ptr as our swallowed type!
// you *must* make this check *before* calling this method // you *must* make this check *before* calling this method
// if your functions are not the same, then you will downcast a pointer into a different type (UB) // if your functions are not the same, then you will downcast a pointer into a different type (UB)
unsafe fn memoize(&self, other: &dyn AnyProps) -> bool { fn memoize(&self, other: &dyn AnyProps) -> bool {
let real_other: &P = &*(other.props_ptr() as *const _ as *const P); (self.memo)(self, other)
let real_us: &P = &*(self.props_ptr() as *const _ as *const P);
(self.memo)(real_us, real_other)
} }
fn render(&'a self, cx: &'a ScopeState) -> RenderReturn<'a> { fn render(&self, cx: &ScopeState) -> RenderReturn {
let res = std::panic::catch_unwind(AssertUnwindSafe(move || { let res = std::panic::catch_unwind(AssertUnwindSafe(move || {
// Call the render function directly // Call the render function directly
let scope: &mut Scoped<P> = cx.bump().alloc(Scoped { (self.render_fn)(self.props.clone())
props: &self.props,
scope: cx,
});
(self.render_fn)(scope)
})); }));
match res { match res {
+1 -5
View File
@@ -102,7 +102,7 @@ impl VirtualDom {
if recursive { if recursive {
if let Some(root) = self.scopes[id.0].try_root_node() { if let Some(root) = self.scopes[id.0].try_root_node() {
if let RenderReturn::Ready(node) = unsafe { root.extend_lifetime_ref() } { if let RenderReturn::Ready(node) = root {
self.drop_scope_inner(node) self.drop_scope_inner(node)
} }
} }
@@ -131,7 +131,6 @@ impl VirtualDom {
if let Some(f) = c.scope.get() { if let Some(f) = c.scope.get() {
self.drop_scope(f, true); self.drop_scope(f, true);
} }
c.props.take();
} }
DynamicNode::Fragment(nodes) => { DynamicNode::Fragment(nodes) => {
nodes.iter().for_each(|node| self.drop_scope_inner(node)) nodes.iter().for_each(|node| self.drop_scope_inner(node))
@@ -166,9 +165,6 @@ impl VirtualDom {
Some(child) if child != scope_id => self.ensure_drop_safety(child), Some(child) if child != scope_id => self.ensure_drop_safety(child),
_ => (), _ => (),
} }
if let Ok(mut props) = comp.props.try_borrow_mut() {
*props = None;
}
} }
let scope = &self.scopes[scope_id.0]; let scope = &self.scopes[scope_id.0];
scope.borrowed_props.borrow_mut().clear(); scope.borrowed_props.borrow_mut().clear();
+17 -25
View File
@@ -63,11 +63,11 @@ fn sorting() {
); );
} }
impl<'b> VirtualDom { impl 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) -> usize { pub(crate) fn create_scope(&mut self, scope: ScopeId, template: &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) -> usize { pub(crate) fn create(&mut self, node: &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, idx: usize) -> usize { fn write_dynamic_root(&mut self, template: &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, template: &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, template: &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, node: &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,9 +327,9 @@ impl<'b> VirtualDom {
fn write_attribute( fn write_attribute(
&mut self, &mut self,
template: &'b VNode, template: &VNode,
idx: usize, idx: usize,
attribute: &'b crate::Attribute<'b>, attribute: &crate::Attribute,
id: ElementId, id: ElementId,
) { ) {
// Make sure we set the attribute's associated id // Make sure we set the attribute's associated id
@@ -355,7 +355,7 @@ impl<'b> VirtualDom {
} }
_ => { _ => {
// Safety: we promise not to re-alias this text later on after committing it to the mutation // Safety: we promise not to re-alias this text later on after committing it to the mutation
let value: BorrowedAttributeValue<'b> = (&attribute.value).into(); let value: BorrowedAttributeValue = (&attribute.value).into();
let unbounded_value = unsafe { std::mem::transmute(value) }; let unbounded_value = unsafe { std::mem::transmute(value) };
self.mutations.push(SetAttribute { self.mutations.push(SetAttribute {
@@ -476,35 +476,28 @@ impl<'b> VirtualDom {
} }
} }
pub(crate) fn create_dynamic_node( pub(crate) fn create_dynamic_node(&mut self, parent: ElementRef, node: &DynamicNode) -> usize {
&mut self,
parent: ElementRef,
node: &'b DynamicNode<'b>,
) -> usize {
use DynamicNode::*; use DynamicNode::*;
match node { match node {
Text(text) => self.create_dynamic_text(parent, text), Text(text) => self.create_dynamic_text(parent, text),
Placeholder(place) => self.create_placeholder(place, parent), Placeholder(place) => self.create_placeholder(place, parent),
Component(component) => self.create_component_node(Some(parent), component), Component(component) => self.create_component_node(Some(parent), component),
Fragment(frag) => self.create_children(*frag, Some(parent)), Fragment(frag) => self.create_children(frag, Some(parent)),
} }
} }
fn create_dynamic_text(&mut self, parent: ElementRef, text: &'b VText) -> usize { fn create_dynamic_text(&mut self, parent: ElementRef, text: &VText) -> usize {
// Allocate a dynamic element reference for this text node // Allocate a dynamic element reference for this text node
let new_id = self.next_element(); let new_id = self.next_element();
// Make sure the text node is assigned to the correct element // Make sure the text node is assigned to the correct element
text.id.set(Some(new_id)); text.id.set(Some(new_id));
// Safety: we promise not to re-alias this text later on after committing it to the mutation
let value = unsafe { std::mem::transmute(text.value) };
// Add the mutation to the list // Add the mutation to the list
self.mutations.push(HydrateText { self.mutations.push(HydrateText {
id: new_id, id: new_id,
path: &parent.path.path[1..], path: &parent.path.path[1..],
value, value: &text.value,
}); });
// Since we're hydrating an existing node, we don't create any new nodes // Since we're hydrating an existing node, we don't create any new nodes
@@ -538,7 +531,7 @@ impl<'b> VirtualDom {
pub(super) fn create_component_node( pub(super) fn create_component_node(
&mut self, &mut self,
parent: Option<ElementRef>, parent: Option<ElementRef>,
component: &'b VComponent, component: &VComponent,
) -> usize { ) -> usize {
use RenderReturn::*; use RenderReturn::*;
@@ -547,7 +540,7 @@ impl<'b> VirtualDom {
component.scope.set(Some(scope)); component.scope.set(Some(scope));
match unsafe { self.run_scope(scope).extend_lifetime_ref() } { match self.run_scope(scope) {
// Create the component's root element // Create the component's root element
Ready(t) => { Ready(t) => {
self.assign_boundary_ref(parent, t); self.assign_boundary_ref(parent, t);
@@ -561,7 +554,6 @@ impl<'b> VirtualDom {
fn load_scope_from_vcomponent(&mut self, component: &VComponent) -> ScopeId { fn load_scope_from_vcomponent(&mut self, component: &VComponent) -> ScopeId {
component component
.props .props
.take()
.map(|props| { .map(|props| {
let unbounded_props: Box<dyn AnyProps> = unsafe { std::mem::transmute(props) }; let unbounded_props: Box<dyn AnyProps> = unsafe { std::mem::transmute(props) };
self.new_scope(unbounded_props, component.name).context().id self.new_scope(unbounded_props, component.name).context().id
@@ -578,7 +570,7 @@ impl<'b> VirtualDom {
1 1
} }
fn set_slot(&mut self, slot: &'b Cell<Option<ElementId>>) -> ElementId { fn set_slot(&mut self, slot: &Cell<Option<ElementId>>) -> ElementId {
let id = self.next_element(); let id = self.next_element();
slot.set(Some(id)); slot.set(Some(id));
id id
+43 -68
View File
@@ -16,7 +16,7 @@ use crate::{
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use DynamicNode::*; use DynamicNode::*;
impl<'b> VirtualDom { impl VirtualDom {
pub(super) fn diff_scope(&mut self, scope: ScopeId) { pub(super) fn diff_scope(&mut self, scope: ScopeId) {
self.runtime.scope_stack.borrow_mut().push(scope); self.runtime.scope_stack.borrow_mut().push(scope);
let scope_state = &mut self.get_scope(scope).unwrap(); let scope_state = &mut self.get_scope(scope).unwrap();
@@ -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, p: &'b VPlaceholder) { fn diff_ok_to_err(&mut self, l: &VNode, p: &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, right_template: &'b VNode) { fn diff_node(&mut self, left_template: &VNode, right_template: &VNode) {
// If hot reloading is enabled, we need to make sure we're using the latest template // If hot reloading is enabled, we need to make sure we're using the latest template
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
@@ -166,8 +166,8 @@ impl<'b> VirtualDom {
fn diff_dynamic_node( fn diff_dynamic_node(
&mut self, &mut self,
left_node: &'b DynamicNode<'b>, left_node: &DynamicNode,
right_node: &'b DynamicNode<'b>, right_node: &DynamicNode,
parent: ElementRef, parent: ElementRef,
) { ) {
match (left_node, right_node) { match (left_node, right_node) {
@@ -184,9 +184,9 @@ impl<'b> VirtualDom {
}; };
} }
fn update_attribute(&mut self, right_attr: &'b Attribute<'b>, left_attr: &'b Attribute) { fn update_attribute(&mut self, right_attr: &Attribute, left_attr: &Attribute) {
let name = unsafe { std::mem::transmute(left_attr.name) }; let name = unsafe { std::mem::transmute(left_attr.name) };
let value: BorrowedAttributeValue<'b> = (&right_attr.value).into(); let value: BorrowedAttributeValue = (&right_attr.value).into();
let value = unsafe { std::mem::transmute(value) }; let value = unsafe { std::mem::transmute(value) };
self.mutations.push(Mutation::SetAttribute { self.mutations.push(Mutation::SetAttribute {
id: left_attr.mounted_element.get(), id: left_attr.mounted_element.get(),
@@ -198,8 +198,8 @@ impl<'b> VirtualDom {
fn diff_vcomponent( fn diff_vcomponent(
&mut self, &mut self,
left: &'b VComponent, left: &VComponent,
right: &'b VComponent, right: &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, right: &VComponent,
left: &'b VComponent, left: &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, right: &'b VNode) { fn light_diff_templates(&mut self, left: &VNode, right: &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, right: &'b VText) { fn diff_vtext(&mut self, left: &VText, right: &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,7 +331,7 @@ impl<'b> VirtualDom {
} }
} }
fn diff_non_empty_fragment(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) { fn diff_non_empty_fragment(&mut self, old: &[VNode], new: &[VNode], parent: ElementRef) {
let new_is_keyed = new[0].key.is_some(); let 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!(
@@ -358,7 +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(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) { fn diff_non_keyed_children(&mut self, old: &[VNode], new: &[VNode], parent: ElementRef) {
use std::cmp::Ordering; use std::cmp::Ordering;
// Handled these cases in `diff_children` before calling this function. // Handled these cases in `diff_children` before calling this function.
@@ -394,10 +394,10 @@ impl<'b> VirtualDom {
// https://github.com/infernojs/inferno/blob/36fd96/packages/inferno/src/DOM/patching.ts#L530-L739 // 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(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) { fn diff_keyed_children(&mut self, old: &[VNode], new: &[VNode], parent: ElementRef) {
if cfg!(debug_assertions) { 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]| { let mut assert_unique_keys = |children: &[VNode]| {
keys.clear(); keys.clear();
for child in children { for child in children {
let key = child.key; let key = child.key;
@@ -470,8 +470,8 @@ impl<'b> VirtualDom {
/// If there is no offset, then this function returns None and the diffing is complete. /// 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], old: &[VNode],
new: &'b [VNode], new: &[VNode],
parent: ElementRef, parent: ElementRef,
) -> Option<(usize, usize)> { ) -> Option<(usize, usize)> {
let mut left_offset = 0; let mut left_offset = 0;
@@ -527,7 +527,7 @@ impl<'b> VirtualDom {
// //
// Upon exit from this function, it will be restored to that same self. // 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(&mut self, old: &'b [VNode], new: &'b [VNode], parent: ElementRef) { fn diff_keyed_middle(&mut self, old: &[VNode], new: &[VNode], parent: ElementRef) {
/* /*
1. Map the old keys into a numerical ordering based on indices. 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
@@ -709,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) -> usize { fn push_all_real_nodes(&mut self, node: &VNode) -> usize {
node.template node.template
.get() .get()
.roots .roots
@@ -746,12 +746,7 @@ impl<'b> VirtualDom {
Component(comp) => { Component(comp) => {
let scope = comp.scope.get().unwrap(); let scope = comp.scope.get().unwrap();
match unsafe { match self.get_scope(scope).unwrap().root_node() {
self.get_scope(scope)
.unwrap()
.root_node()
.extend_lifetime_ref()
} {
RenderReturn::Ready(node) => self.push_all_real_nodes(node), RenderReturn::Ready(node) => self.push_all_real_nodes(node),
RenderReturn::Aborted(_node) => todo!(), RenderReturn::Aborted(_node) => todo!(),
} }
@@ -761,9 +756,9 @@ impl<'b> VirtualDom {
.sum() .sum()
} }
pub(crate) fn create_children( pub(crate) fn create_children<'a>(
&mut self, &mut self,
nodes: impl IntoIterator<Item = &'b VNode>, nodes: impl IntoIterator<Item = &'a VNode>,
parent: Option<ElementRef>, parent: Option<ElementRef>,
) -> usize { ) -> usize {
nodes nodes
@@ -775,28 +770,23 @@ impl<'b> VirtualDom {
.sum() .sum()
} }
fn create_and_insert_before( fn create_and_insert_before(&mut self, new: &[VNode], before: &VNode, parent: ElementRef) {
&mut self,
new: &'b [VNode],
before: &'b VNode,
parent: ElementRef,
) {
let m = self.create_children(new, Some(parent)); let m = self.create_children(new, Some(parent));
let id = self.find_first_element(before); let id = self.find_first_element(before);
self.mutations.push(Mutation::InsertBefore { id, m }) self.mutations.push(Mutation::InsertBefore { id, m })
} }
fn create_and_insert_after(&mut self, new: &'b [VNode], after: &'b VNode, parent: ElementRef) { fn create_and_insert_after(&mut self, new: &[VNode], after: &VNode, parent: ElementRef) {
let m = self.create_children(new, Some(parent)); let 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 })
} }
/// Simply replace a placeholder with a list of nodes /// Simply replace a placeholder with a list of nodes
fn replace_placeholder( fn replace_placeholder<'a>(
&mut self, &mut self,
l: &'b VPlaceholder, l: &VPlaceholder,
r: impl IntoIterator<Item = &'b VNode>, r: impl IntoIterator<Item = &'a VNode>,
parent: ElementRef, parent: ElementRef,
) { ) {
let m = self.create_children(r, Some(parent)); let m = self.create_children(r, Some(parent));
@@ -805,10 +795,10 @@ impl<'b> VirtualDom {
self.reclaim(id); self.reclaim(id);
} }
fn replace( fn replace<'a>(
&mut self, &mut self,
left: &'b VNode, left: &VNode,
right: impl IntoIterator<Item = &'b VNode>, right: impl IntoIterator<Item = &'a VNode>,
parent: Option<ElementRef>, parent: Option<ElementRef>,
) { ) {
let m = self.create_children(right, parent); let m = self.create_children(right, parent);
@@ -830,7 +820,7 @@ impl<'b> VirtualDom {
}; };
} }
fn node_to_placeholder(&mut self, l: &'b [VNode], r: &'b VPlaceholder, parent: ElementRef) { fn node_to_placeholder(&mut self, l: &[VNode], r: &VPlaceholder, parent: ElementRef) {
// Create the placeholder first, ensuring we get a dedicated ID for the placeholder // Create the placeholder first, ensuring we get a dedicated ID for the placeholder
let placeholder = self.next_element(); let placeholder = self.next_element();
@@ -853,14 +843,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]) { fn remove_nodes(&mut self, nodes: &[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, gen_muts: bool) { fn remove_node(&mut self, node: &VNode, gen_muts: bool) {
// Clean up any attributes that have claimed a static node as dynamic for mount/unmounta // 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);
@@ -878,7 +868,7 @@ impl<'b> VirtualDom {
self.reclaim_vnode_id(node); self.reclaim_vnode_id(node);
} }
fn reclaim_vnode_id(&mut self, node: &'b VNode) { fn reclaim_vnode_id(&mut self, node: &VNode) {
// Clean up the vnode id // 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);
@@ -982,12 +972,7 @@ impl<'b> VirtualDom {
.expect("VComponents to always have a scope"); .expect("VComponents to always have a scope");
// Remove the component from the dom // Remove the component from the dom
match unsafe { match unsafe { self.get_scope(scope).unwrap().root_node() } {
self.get_scope(scope)
.unwrap()
.root_node()
.extend_lifetime_ref()
} {
RenderReturn::Ready(t) => self.remove_node(t, gen_muts), RenderReturn::Ready(t) => self.remove_node(t, gen_muts),
RenderReturn::Aborted(placeholder) => self.remove_placeholder(placeholder, gen_muts), RenderReturn::Aborted(placeholder) => self.remove_placeholder(placeholder, gen_muts),
}; };
@@ -1000,7 +985,7 @@ impl<'b> VirtualDom {
self.drop_scope(scope, false); self.drop_scope(scope, false);
} }
fn find_first_element(&self, node: &'b VNode) -> ElementId { fn find_first_element(&self, node: &VNode) -> ElementId {
match node.dynamic_root(0) { 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(),
@@ -1008,12 +993,7 @@ impl<'b> VirtualDom {
Some(Placeholder(t)) => t.id.get().unwrap(), Some(Placeholder(t)) => t.id.get().unwrap(),
Some(Component(comp)) => { Some(Component(comp)) => {
let scope = comp.scope.get().unwrap(); let scope = comp.scope.get().unwrap();
match unsafe { match unsafe { self.get_scope(scope).unwrap().root_node() } {
self.get_scope(scope)
.unwrap()
.root_node()
.extend_lifetime_ref()
} {
RenderReturn::Ready(t) => self.find_first_element(t), RenderReturn::Ready(t) => self.find_first_element(t),
_ => todo!("cannot handle nonstandard nodes"), _ => todo!("cannot handle nonstandard nodes"),
} }
@@ -1021,7 +1001,7 @@ impl<'b> VirtualDom {
} }
} }
fn find_last_element(&self, node: &'b VNode) -> ElementId { fn find_last_element(&self, node: &VNode) -> ElementId {
match node.dynamic_root(node.template.get().roots.len() - 1) { 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(),
@@ -1029,12 +1009,7 @@ impl<'b> VirtualDom {
Some(Placeholder(t)) => t.id.get().unwrap(), Some(Placeholder(t)) => t.id.get().unwrap(),
Some(Component(comp)) => { Some(Component(comp)) => {
let scope = comp.scope.get().unwrap(); let scope = comp.scope.get().unwrap();
match unsafe { match unsafe { self.get_scope(scope).unwrap().root_node() } {
self.get_scope(scope)
.unwrap()
.root_node()
.extend_lifetime_ref()
} {
RenderReturn::Ready(t) => self.find_last_element(t), RenderReturn::Ready(t) => self.find_last_element(t),
_ => todo!("cannot handle nonstandard nodes"), _ => todo!("cannot handle nonstandard nodes"),
} }
@@ -1042,7 +1017,7 @@ impl<'b> VirtualDom {
} }
} }
pub(crate) fn assign_boundary_ref(&mut self, parent: Option<ElementRef>, child: &'b VNode) { pub(crate) fn assign_boundary_ref(&mut self, parent: Option<ElementRef>, child: &VNode) {
if let Some(parent) = parent { 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));
@@ -1055,7 +1030,7 @@ impl<'b> VirtualDom {
/// We need to check for the obvious case, and the non-obvious case where the template as cloned /// We 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, right_template: &'b VNode) -> bool { fn templates_are_the_same(left_template: &VNode, right_template: &VNode) -> bool {
std::ptr::eq(left_template, right_template) std::ptr::eq(left_template, right_template)
} }
+47 -55
View File
@@ -1,7 +1,7 @@
use crate::{ use crate::{
scope_context::{consume_context, current_scope_id, schedule_update_any}, scope_context::{consume_context, current_scope_id, schedule_update_any},
Element, IntoDynNode, LazyNodes, Properties, Scope, ScopeId, ScopeState, Template, Element, IntoDynNode, Properties, ScopeId, ScopeState, Template, TemplateAttribute,
TemplateAttribute, TemplateNode, VNode, TemplateNode, VNode,
}; };
use std::{ use std::{
any::{Any, TypeId}, any::{Any, TypeId},
@@ -262,42 +262,40 @@ impl<T> Throw for Option<T> {
} }
} }
pub struct ErrorHandler(Box<dyn Fn(CapturedError) -> LazyNodes<'a, 'a>>); pub struct ErrorHandler(Box<dyn Fn(CapturedError) -> Element>);
impl<'a, F: Fn(CapturedError) -> LazyNodes<'a, 'a> + 'a> From<F> for ErrorHandler<'a> { impl<F: Fn(CapturedError) -> Element> From<F> for ErrorHandler {
fn from(value: F) -> Self { fn from(value: F) -> Self {
Self(Box::new(value)) Self(Box::new(value))
} }
} }
fn default_handler<'a>(error: CapturedError) -> LazyNodes<'a, 'a> { fn default_handler(error: CapturedError) -> Element {
LazyNodes::new(move |__cx: &ScopeState| -> VNode { static TEMPLATE: Template = Template {
static TEMPLATE: Template = Template { name: "error_handle.rs:42:5:884",
name: "error_handle.rs:42:5:884", roots: &[TemplateNode::Element {
roots: &[TemplateNode::Element { tag: "pre",
tag: "pre", namespace: None,
namespace: None, attrs: &[TemplateAttribute::Static {
attrs: &[TemplateAttribute::Static { name: "color",
name: "color", namespace: Some("style"),
namespace: Some("style"), value: "red",
value: "red",
}],
children: &[TemplateNode::DynamicText { id: 0usize }],
}], }],
node_paths: &[&[0u8, 0u8]], children: &[TemplateNode::DynamicText { id: 0usize }],
attr_paths: &[], }],
}; node_paths: &[&[0u8, 0u8]],
VNode { attr_paths: &[],
parent: Default::default(), };
stable_id: Default::default(), Some(VNode {
key: None, parent: Default::default(),
template: std::cell::Cell::new(TEMPLATE), stable_id: Default::default(),
root_ids: Vec::with_capacity(1usize).into(), key: None,
dynamic_nodes: __cx template: std::cell::Cell::new(TEMPLATE),
.bump() root_ids: Vec::with_capacity(1usize).into(),
.alloc([__cx.text_node(format_args!("{0}", error))]), dynamic_nodes: vec![error.to_string().into_dyn_node()],
dynamic_attrs: __cx.bump().alloc([]), dynamic_attrs: Default::default(),
}
}) })
} }
#[derive(Clone)]
pub struct ErrorBoundaryProps { pub struct ErrorBoundaryProps {
children: Element, children: Element,
handle_error: ErrorHandler, handle_error: ErrorHandler,
@@ -334,7 +332,7 @@ impl Properties for ErrorBoundaryProps {
fn builder() -> Self::Builder { fn builder() -> Self::Builder {
ErrorBoundaryProps::builder() ErrorBoundaryProps::builder()
} }
unsafe fn memoize(&self, _: &Self) -> bool { fn memoize(&self, _: &Self) -> bool {
false false
} }
} }
@@ -354,16 +352,15 @@ impl<T> ErrorBoundaryPropsBuilder_Optional<T> for (T,) {
} }
} }
#[allow(dead_code, non_camel_case_types, missing_docs)] #[allow(dead_code, non_camel_case_types, missing_docs)]
impl<'a, __handle_error> ErrorBoundaryPropsBuilder<'a, ((), __handle_error)> { impl<__handle_error> ErrorBoundaryPropsBuilder<((), __handle_error)> {
pub fn children( pub fn children(
self, self,
children: Element<'a>, children: Element,
) -> ErrorBoundaryPropsBuilder<'a, ((Element<'a>,), __handle_error)> { ) -> ErrorBoundaryPropsBuilder<((Element,), __handle_error)> {
let children = (children,); let children = (children,);
let (_, handle_error) = self.fields; let (_, handle_error) = self.fields;
ErrorBoundaryPropsBuilder { ErrorBoundaryPropsBuilder {
fields: (children, handle_error), fields: (children, handle_error),
_phantom: self._phantom,
} }
} }
} }
@@ -372,26 +369,25 @@ impl<'a, __handle_error> ErrorBoundaryPropsBuilder<'a, ((), __handle_error)> {
pub enum ErrorBoundaryPropsBuilder_Error_Repeated_field_children {} pub enum ErrorBoundaryPropsBuilder_Error_Repeated_field_children {}
#[doc(hidden)] #[doc(hidden)]
#[allow(dead_code, non_camel_case_types, missing_docs)] #[allow(dead_code, non_camel_case_types, missing_docs)]
impl<'a, __handle_error> ErrorBoundaryPropsBuilder<'a, ((Element<'a>,), __handle_error)> { impl<__handle_error> ErrorBoundaryPropsBuilder<((Element,), __handle_error)> {
#[deprecated(note = "Repeated field children")] #[deprecated(note = "Repeated field children")]
pub fn children( pub fn children(
self, self,
_: ErrorBoundaryPropsBuilder_Error_Repeated_field_children, _: ErrorBoundaryPropsBuilder_Error_Repeated_field_children,
) -> ErrorBoundaryPropsBuilder<'a, ((Element<'a>,), __handle_error)> { ) -> ErrorBoundaryPropsBuilder<((Element,), __handle_error)> {
self self
} }
} }
#[allow(dead_code, non_camel_case_types, missing_docs)] #[allow(dead_code, non_camel_case_types, missing_docs)]
impl<'a, __children> ErrorBoundaryPropsBuilder<'a, (__children, ())> { impl<__children> ErrorBoundaryPropsBuilder<(__children, ())> {
pub fn handle_error( pub fn handle_error(
self, self,
handle_error: impl ::core::convert::Into<ErrorHandler<'a>>, handle_error: impl ::core::convert::Into<ErrorHandler>,
) -> ErrorBoundaryPropsBuilder<'a, (__children, (ErrorHandler<'a>,))> { ) -> ErrorBoundaryPropsBuilder<(__children, (ErrorHandler,))> {
let handle_error = (handle_error.into(),); let handle_error = (handle_error.into(),);
let (children, _) = self.fields; let (children, _) = self.fields;
ErrorBoundaryPropsBuilder { ErrorBoundaryPropsBuilder {
fields: (children, handle_error), fields: (children, handle_error),
_phantom: self._phantom,
} }
} }
} }
@@ -400,23 +396,22 @@ impl<'a, __children> ErrorBoundaryPropsBuilder<'a, (__children, ())> {
pub enum ErrorBoundaryPropsBuilder_Error_Repeated_field_handle_error {} pub enum ErrorBoundaryPropsBuilder_Error_Repeated_field_handle_error {}
#[doc(hidden)] #[doc(hidden)]
#[allow(dead_code, non_camel_case_types, missing_docs)] #[allow(dead_code, non_camel_case_types, missing_docs)]
impl<'a, __children> ErrorBoundaryPropsBuilder<'a, (__children, (ErrorHandler<'a>,))> { impl<__children> ErrorBoundaryPropsBuilder<(__children, (ErrorHandler,))> {
#[deprecated(note = "Repeated field handle_error")] #[deprecated(note = "Repeated field handle_error")]
pub fn handle_error( pub fn handle_error(
self, self,
_: ErrorBoundaryPropsBuilder_Error_Repeated_field_handle_error, _: ErrorBoundaryPropsBuilder_Error_Repeated_field_handle_error,
) -> ErrorBoundaryPropsBuilder<'a, (__children, (ErrorHandler<'a>,))> { ) -> ErrorBoundaryPropsBuilder<(__children, (ErrorHandler,))> {
self self
} }
} }
#[allow(dead_code, non_camel_case_types, missing_docs)] #[allow(dead_code, non_camel_case_types, missing_docs)]
impl< impl<
'a, __handle_error: ErrorBoundaryPropsBuilder_Optional<ErrorHandler>,
__handle_error: ErrorBoundaryPropsBuilder_Optional<ErrorHandler<'a>>, __children: ErrorBoundaryPropsBuilder_Optional<Element>,
__children: ErrorBoundaryPropsBuilder_Optional<Element<'a>>, > ErrorBoundaryPropsBuilder<(__children, __handle_error)>
> ErrorBoundaryPropsBuilder<'a, (__children, __handle_error)>
{ {
pub fn build(self) -> ErrorBoundaryProps<'a> { pub fn build(self) -> ErrorBoundaryProps {
let (children, handle_error) = self.fields; let (children, handle_error) = self.fields;
let children = ErrorBoundaryPropsBuilder_Optional::into_value(children, || { let children = ErrorBoundaryPropsBuilder_Optional::into_value(children, || {
::core::default::Default::default() ::core::default::Default::default()
@@ -453,7 +448,7 @@ impl<
/// They are similar to `try/catch` in JavaScript, but they only catch errors in the tree below them. /// They are similar to `try/catch` in JavaScript, but they only catch errors in the tree below them.
/// Error boundaries are quick to implement, but it can be useful to individually handle errors in your components to provide a better user experience when you know that an error is likely to occur. /// Error boundaries are quick to implement, but it can be useful to individually handle errors in your components to provide a better user experience when you know that an error is likely to occur.
#[allow(non_upper_case_globals, non_snake_case)] #[allow(non_upper_case_globals, non_snake_case)]
pub fn ErrorBoundary<'a>(cx: Scope<'a, ErrorBoundaryProps<'a>>) -> Element { pub fn ErrorBoundary(cx: ErrorBoundaryProps) -> Element {
let error_boundary = use_error_boundary(cx); let error_boundary = use_error_boundary(cx);
match error_boundary.take_error() { match error_boundary.take_error() {
Some(error) => cx.render((cx.props.handle_error.0)(error)), Some(error) => cx.render((cx.props.handle_error.0)(error)),
@@ -470,11 +465,8 @@ pub fn ErrorBoundary<'a>(cx: Scope<'a, ErrorBoundaryProps<'a>>) -> Element {
stable_id: Default::default(), 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.bump().alloc([{ dynamic_nodes: vec![(&cx.props.children).into_dyn_node()],
let ___nodes = (&cx.props.children).into_dyn_node(__cx);
___nodes
}]),
dynamic_attrs: __cx.bump().alloc([]), dynamic_attrs: __cx.bump().alloc([]),
} }
}), }),
+5 -5
View File
@@ -133,12 +133,12 @@ impl<T: std::fmt::Debug> std::fmt::Debug for Event<T> {
/// } /// }
/// ///
/// ``` /// ```
pub struct EventHandler<'bump, T = ()> { pub struct EventHandler<T = ()> {
pub(crate) origin: ScopeId, pub(crate) origin: ScopeId,
pub(super) callback: RefCell<Option<ExternalListenerCallback<'bump, T>>>, pub(super) callback: RefCell<Option<ExternalListenerCallback<T>>>,
} }
impl<T> Default for EventHandler<'_, T> { impl<T> Default for EventHandler<T> {
fn default() -> Self { fn default() -> Self {
Self { Self {
origin: ScopeId::ROOT, origin: ScopeId::ROOT,
@@ -147,9 +147,9 @@ impl<T> Default for EventHandler<'_, T> {
} }
} }
type ExternalListenerCallback<'bump, T> = Box<dyn FnMut(T)>; type ExternalListenerCallback<T> = Box<dyn FnMut(T)>;
impl<T> EventHandler<'_, T> { impl<T> EventHandler< T> {
/// Call this event handler with the appropriate event type /// Call this event handler with the appropriate event type
/// ///
/// This borrows the event using a RefCell. Recursively calling a listener will cause a panic. /// This borrows the event using a RefCell. Recursively calling a listener will cause a panic.
+5 -3
View File
@@ -26,8 +26,8 @@ use crate::innerlude::*;
/// ///
/// You want to use this free-function when your fragment needs a key and simply returning multiple nodes from rsx! won't cut it. /// 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>) -> Element { pub fn Fragment(cx: FragmentProps) -> Element {
let children = cx.props.0.as_ref()?; let children = cx.0.as_ref()?;
Some(VNode { Some(VNode {
key: children.key, key: children.key,
parent: children.parent.clone(), parent: children.parent.clone(),
@@ -39,7 +39,9 @@ pub fn Fragment<'a>(cx: Scope<'a, FragmentProps>) -> Element {
}) })
} }
#[derive(Clone, PartialEq)]
pub struct FragmentProps(Element); pub struct FragmentProps(Element);
pub struct FragmentBuilder<const BUILT: bool>(Element); pub struct FragmentBuilder<const BUILT: bool>(Element);
impl FragmentBuilder<false> { impl FragmentBuilder<false> {
pub fn children(self, children: Element) -> FragmentBuilder<true> { pub fn children(self, children: Element) -> FragmentBuilder<true> {
@@ -92,7 +94,7 @@ impl<const A: bool> FragmentBuilder<A> {
/// }) /// })
/// } /// }
/// ``` /// ```
impl<'a> Properties for FragmentProps { impl Properties for FragmentProps {
type Builder = FragmentBuilder<false>; type Builder = FragmentBuilder<false>;
fn builder() -> Self::Builder { fn builder() -> Self::Builder {
FragmentBuilder(None) FragmentBuilder(None)
+5 -9
View File
@@ -11,7 +11,6 @@ mod dirty_scope;
mod error_boundary; mod error_boundary;
mod events; mod events;
mod fragment; mod fragment;
mod lazynodes;
mod mutations; mod mutations;
mod nodes; mod nodes;
mod properties; mod properties;
@@ -28,7 +27,6 @@ pub(crate) mod innerlude {
pub use crate::error_boundary::*; pub use crate::error_boundary::*;
pub use crate::events::*; pub use crate::events::*;
pub use crate::fragment::*; pub use crate::fragment::*;
pub use crate::lazynodes::*;
pub use crate::mutations::*; pub use crate::mutations::*;
pub use crate::nodes::RenderReturn; pub use crate::nodes::RenderReturn;
pub use crate::nodes::*; pub use crate::nodes::*;
@@ -71,15 +69,14 @@ pub(crate) mod innerlude {
/// Example {} /// Example {}
/// ) /// )
/// ``` /// ```
pub type Component<P = ()> = fn(Scope<P>) -> Element; pub type Component<P = ()> = fn(P) -> Element;
} }
pub use crate::innerlude::{ pub use crate::innerlude::{
fc_to_builder, vdom_is_rendering, AnyValue, Attribute, AttributeValue, BorrowedAttributeValue, fc_to_builder, vdom_is_rendering, AnyValue, Attribute, AttributeValue, BorrowedAttributeValue,
CapturedError, Component, DynamicNode, Element, ElementId, Event, Fragment, IntoDynNode, CapturedError, Component, DynamicNode, Element, ElementId, Event, Fragment, IntoDynNode,
LazyNodes, Mutation, Mutations, Properties, RenderReturn, Scope, ScopeId, ScopeState, Scoped, Mutation, Mutations, Properties, RenderReturn, ScopeId, ScopeState, TaskId, Template,
TaskId, Template, TemplateAttribute, TemplateNode, VComponent, VNode, VPlaceholder, VText, TemplateAttribute, TemplateNode, VComponent, VNode, VPlaceholder, VText, VirtualDom,
VirtualDom,
}; };
/// The purpose of this module is to alleviate imports of many common types /// The purpose of this module is to alleviate imports of many common types
@@ -91,8 +88,7 @@ pub mod prelude {
provide_context, provide_context_to_scope, provide_root_context, push_future, provide_context, provide_context_to_scope, provide_root_context, push_future,
remove_future, schedule_update_any, spawn, spawn_forever, suspend, use_error_boundary, remove_future, schedule_update_any, spawn, spawn_forever, suspend, use_error_boundary,
AnyValue, Component, Element, ErrorBoundary, Event, EventHandler, Fragment, AnyValue, Component, Element, ErrorBoundary, Event, EventHandler, Fragment,
IntoAttributeValue, IntoDynNode, LazyNodes, Properties, Runtime, RuntimeGuard, Scope, IntoAttributeValue, IntoDynNode, Properties, Runtime, RuntimeGuard, ScopeId, ScopeState,
ScopeId, ScopeState, Scoped, TaskId, Template, TemplateAttribute, TemplateNode, Throw, TaskId, Template, TemplateAttribute, TemplateNode, Throw, VNode, VirtualDom,
VNode, VirtualDom,
}; };
} }
+72 -95
View File
@@ -1,9 +1,5 @@
use crate::innerlude::{ElementRef, VNodeId}; use crate::innerlude::{ElementRef, VNodeId};
use crate::{ use crate::{any_props::AnyProps, arena::ElementId, Element, Event, ScopeId, ScopeState};
any_props::AnyProps, arena::ElementId, Element, Event, LazyNodes, ScopeId, ScopeState,
};
use bumpalo::boxed::Box as BumpBox;
use bumpalo::Bump;
use std::{ use std::{
any::{Any, TypeId}, any::{Any, TypeId},
cell::{Cell, RefCell}, cell::{Cell, RefCell},
@@ -91,8 +87,8 @@ impl VNode {
key: Option<String>, key: Option<String>,
template: Template<'static>, template: Template<'static>,
root_ids: Vec<ElementId>, root_ids: Vec<ElementId>,
dynamic_nodes: &'a [DynamicNode], dynamic_nodes: Vec<DynamicNode>,
dynamic_attrs: &'a [Attribute], dynamic_attrs: Vec<Attribute>,
) -> Self { ) -> Self {
Self { Self {
key, key,
@@ -113,7 +109,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> { pub fn dynamic_root(&self, idx: usize) -> Option<&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 } => {
@@ -297,7 +293,7 @@ pub enum TemplateNode {
/// A node created at runtime /// A node created at runtime
/// ///
/// 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, Clone)]
pub enum DynamicNode { pub enum DynamicNode {
/// A component node /// A component node
/// ///
@@ -322,7 +318,7 @@ pub enum DynamicNode {
/// ///
/// Note that this is not a list of dynamic nodes. These must be VNodes and created through conditional rendering /// Note that this is not a list of dynamic nodes. These must be VNodes and created through conditional rendering
/// or iterators. /// or iterators.
Fragment(&'static [VNode]), Fragment(Vec<VNode>),
} }
impl Default for DynamicNode { impl Default for DynamicNode {
@@ -331,6 +327,7 @@ impl Default for DynamicNode {
} }
} }
#[derive(Clone)]
/// An instance of a child component /// An instance of a child component
pub struct VComponent { pub struct VComponent {
/// The name of this component /// The name of this component
@@ -344,7 +341,7 @@ pub struct VComponent {
/// It is possible that components get folded at compile time, so these shouldn't be really used as a key /// 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>>>, pub(crate) props: Box<dyn AnyProps>,
} }
impl<'a> VComponent { impl<'a> VComponent {
@@ -662,89 +659,78 @@ impl<T: Any + PartialEq + 'static> AnyValue for T {
} }
/// A trait that allows various items to be converted into a dynamic node for the rsx macro /// A trait that allows various items to be converted into a dynamic node for the rsx macro
pub trait IntoDynNode<'a, A = ()> { pub trait IntoDynNode<A = ()> {
/// Consume this item along with a scopestate and produce a DynamicNode /// 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; fn into_dyn_node(self) -> DynamicNode;
} }
impl<'a> IntoDynNode<'a> for () { impl IntoDynNode for () {
fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { fn into_dyn_node(self) -> DynamicNode {
DynamicNode::default() DynamicNode::default()
} }
} }
impl<'a> IntoDynNode<'a> for VNode { impl IntoDynNode for VNode {
fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { fn into_dyn_node(self) -> DynamicNode {
DynamicNode::Fragment(_cx.bump().alloc([self])) DynamicNode::Fragment(vec![self])
} }
} }
impl<'a> IntoDynNode<'a> for DynamicNode { impl IntoDynNode for DynamicNode {
fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { fn into_dyn_node(self) -> DynamicNode {
self self
} }
} }
impl<'a, T: IntoDynNode<'a>> IntoDynNode<'a> for Option<T> { impl<T: IntoDynNode> IntoDynNode for Option<T> {
fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { fn into_dyn_node(self) -> DynamicNode {
match self { match self {
Some(val) => val.into_dyn_node(_cx), Some(val) => val.into_dyn_node(),
None => DynamicNode::default(), None => DynamicNode::default(),
} }
} }
} }
impl<'a> IntoDynNode<'a> for &Element { impl IntoDynNode for &Element {
fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { fn into_dyn_node(self) -> DynamicNode {
match self.as_ref() { match self.as_ref() {
Some(val) => val.clone().into_dyn_node(_cx), Some(val) => val.clone().into_dyn_node(),
_ => DynamicNode::default(), _ => DynamicNode::default(),
} }
} }
} }
impl<'a, 'b> IntoDynNode<'a> for LazyNodes<'a, 'b> { impl IntoDynNode for &str {
fn into_dyn_node(self, cx: &'a ScopeState) -> DynamicNode { fn into_dyn_node(self) -> DynamicNode {
DynamicNode::Fragment(cx.bump().alloc([cx.render(self).unwrap()]))
}
}
impl<'a, 'b> IntoDynNode<'b> for &'a str {
fn into_dyn_node(self, cx: &'b ScopeState) -> DynamicNode {
DynamicNode::Text(VText { DynamicNode::Text(VText {
value: cx.bump().alloc_str(self), value: self.to_string(),
id: Default::default(), id: Default::default(),
}) })
} }
} }
impl IntoDynNode<'_> for String { impl IntoDynNode for String {
fn into_dyn_node(self, cx: &ScopeState) -> DynamicNode { fn into_dyn_node(self) -> DynamicNode {
DynamicNode::Text(VText { DynamicNode::Text(VText {
value: cx.bump().alloc_str(&self), value: self,
id: Default::default(), id: Default::default(),
}) })
} }
} }
impl<'b> IntoDynNode<'b> for Arguments<'_> { impl<'b> IntoDynNode for Arguments<'_> {
fn into_dyn_node(self, cx: &'b ScopeState) -> DynamicNode { fn into_dyn_node(self) -> DynamicNode {
cx.text_node(self) DynamicNode::Text(VText {
value: self.to_string(),
id: Default::default(),
})
} }
} }
impl<'a> IntoDynNode<'a> for &'a VNode { impl IntoDynNode for &VNode {
fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode { fn into_dyn_node(self) -> DynamicNode {
DynamicNode::Fragment(_cx.bump().alloc([VNode { DynamicNode::Fragment(vec![self.clone()])
parent: self.parent.clone(),
stable_id: self.stable_id.clone(),
template: self.template.clone(),
root_ids: self.root_ids.clone(),
key: self.key,
dynamic_nodes: self.dynamic_nodes,
dynamic_attrs: self.dynamic_attrs,
}]))
} }
} }
@@ -759,97 +745,88 @@ impl<'a> IntoVNode for VNode {
impl<'a> IntoVNode for Element { impl<'a> IntoVNode for Element {
fn into_vnode(self) -> VNode { fn into_vnode(self) -> VNode {
match self { match self {
Some(val) => val.into_vnode(cx), Some(val) => val.into_vnode(),
_ => VNode::empty().unwrap(), _ => VNode::empty().unwrap(),
} }
} }
} }
impl<'a, 'b> IntoVNode for LazyNodes<'a, 'b> {
fn into_vnode(self) -> VNode {
cx.render(self).unwrap()
}
}
// Note that we're using the E as a generic but this is never crafted anyways. // Note that we're using the E as a generic but this is never crafted anyways.
pub struct FromNodeIterator; pub struct FromNodeIterator;
impl<'a, T, I> IntoDynNode<'a, FromNodeIterator> for T impl<T, I> IntoDynNode<FromNodeIterator> for T
where where
T: Iterator<Item = I>, T: Iterator<Item = I>,
I: IntoVNode, I: IntoVNode,
{ {
fn into_dyn_node(self, cx: &'a ScopeState) -> DynamicNode { fn into_dyn_node(self) -> DynamicNode {
let mut nodes = bumpalo::collections::Vec::new_in(cx.bump()); let mut children: Vec<_> = self.into_iter().map(|node| node.into_vnode()).collect();
nodes.extend(self.into_iter().map(|node| node.into_vnode(cx))); if children.is_empty() {
DynamicNode::default()
match nodes.into_bump_slice() { } else {
children if children.is_empty() => DynamicNode::default(), DynamicNode::Fragment(children)
children => DynamicNode::Fragment(children),
} }
} }
} }
/// A value that can be converted into an attribute value /// A value that can be converted into an attribute value
pub trait IntoAttributeValue<'a> { pub trait IntoAttributeValue {
/// Convert into an attribute value /// Convert into an attribute value
fn into_value(self, bump: &'a Bump) -> AttributeValue<'a>; fn into_value(self) -> AttributeValue;
} }
impl<'a> IntoAttributeValue<'a> for AttributeValue<'a> { impl<'a> IntoAttributeValue for AttributeValue {
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> { fn into_value(self) -> AttributeValue {
self self
} }
} }
impl<'a> IntoAttributeValue<'a> for &'a str { impl<'a> IntoAttributeValue for &'a str {
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> { fn into_value(self) -> AttributeValue {
AttributeValue::Text(self.to_string())
}
}
impl<'a> IntoAttributeValue for String {
fn into_value(self) -> AttributeValue {
AttributeValue::Text(self) AttributeValue::Text(self)
} }
} }
impl<'a> IntoAttributeValue<'a> for String { impl<'a> IntoAttributeValue for f64 {
fn into_value(self, cx: &'a Bump) -> AttributeValue<'a> { fn into_value(self) -> AttributeValue {
AttributeValue::Text(cx.alloc_str(&self))
}
}
impl<'a> IntoAttributeValue<'a> for f64 {
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
AttributeValue::Float(self) AttributeValue::Float(self)
} }
} }
impl<'a> IntoAttributeValue<'a> for i64 { impl<'a> IntoAttributeValue for i64 {
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> { fn into_value(self) -> AttributeValue {
AttributeValue::Int(self) AttributeValue::Int(self)
} }
} }
impl<'a> IntoAttributeValue<'a> for bool { impl<'a> IntoAttributeValue for bool {
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> { fn into_value(self) -> AttributeValue {
AttributeValue::Bool(self) AttributeValue::Bool(self)
} }
} }
impl<'a> IntoAttributeValue<'a> for Arguments<'_> { impl<'a> IntoAttributeValue for Arguments<'_> {
fn into_value(self, bump: &'a Bump) -> AttributeValue<'a> { fn into_value(self) -> AttributeValue {
use bumpalo::core_alloc::fmt::Write; AttributeValue::Text(self.to_string())
let mut str_buf = bumpalo::collections::String::new_in(bump);
str_buf.write_fmt(self).unwrap();
AttributeValue::Text(str_buf.into_bump_str())
} }
} }
impl<'a> IntoAttributeValue<'a> for BumpBox<'a, dyn AnyValue> { impl IntoAttributeValue for Box<dyn AnyValue> {
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> { fn into_value(self) -> AttributeValue {
AttributeValue::Any(RefCell::new(Some(self))) AttributeValue::Any(RefCell::new(Some(self)))
} }
} }
impl<'a, T: IntoAttributeValue<'a>> IntoAttributeValue<'a> for Option<T> { impl<'a, T: IntoAttributeValue> IntoAttributeValue for Option<T> {
fn into_value(self, bump: &'a Bump) -> AttributeValue<'a> { fn into_value(self) -> AttributeValue {
match self { match self {
Some(val) => val.into_value(bump), Some(val) => val.into_value(),
None => AttributeValue::None, None => AttributeValue::None,
} }
} }
+1 -1
View File
@@ -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) -> T::Builder { pub fn fc_to_builder<T: Properties>(_: fn(T) -> Element) -> T::Builder {
T::builder() T::builder()
} }
+2 -2
View File
@@ -62,7 +62,7 @@ impl VirtualDom {
let props: &dyn AnyProps = std::mem::transmute(props); let props: &dyn AnyProps = std::mem::transmute(props);
let _span = tracing::trace_span!("render", scope = %scope.context().name); let _span = tracing::trace_span!("render", scope = %scope.context().name);
props.render(scope).extend_lifetime() props.render(scope)
}; };
let scope = &self.scopes[scope_id.0]; let scope = &self.scopes[scope_id.0];
@@ -93,7 +93,7 @@ impl VirtualDom {
} }
// rebind the lifetime now that its stored internally // rebind the lifetime now that its stored internally
let result = unsafe { allocated.extend_lifetime_ref() }; let result = unsafe { allocated };
self.runtime.scope_stack.borrow_mut().pop(); self.runtime.scope_stack.borrow_mut().pop();
+16 -105
View File
@@ -1,7 +1,6 @@
use crate::{ use crate::{
any_props::AnyProps, any_props::AnyProps,
any_props::VProps, any_props::VProps,
innerlude::ErrorBoundary,
innerlude::{DynamicNode, EventHandler, VComponent, VNodeId, VText}, innerlude::{DynamicNode, EventHandler, VComponent, VNodeId, VText},
nodes::{IntoAttributeValue, IntoDynNode, RenderReturn}, nodes::{IntoAttributeValue, IntoDynNode, RenderReturn},
runtime::Runtime, runtime::Runtime,
@@ -17,40 +16,6 @@ use std::{
sync::Arc, sync::Arc,
}; };
/// A wrapper around the [`Scoped`] object that contains a reference to the [`ScopeState`] and properties for a given
/// component.
///
/// The [`Scope`] is your handle to the [`crate::VirtualDom`] and the component state. Every component is given its own
/// [`ScopeState`] and merged with its properties to create a [`Scoped`].
///
/// The [`Scope`] handle specifically exists to provide a stable reference to these items for the lifetime of the
/// component render.
pub type Scope<'a, T = ()> = &'a Scoped<'a, T>;
// This ScopedType exists because we want to limit the amount of monomorphization that occurs when making inner
// state type generic over props. When the state is generic, it causes every method to be monomorphized for every
// instance of Scope<T> in the codebase.
//
//
/// A wrapper around a component's [`ScopeState`] and properties. The [`ScopeState`] provides the majority of methods
/// for the VirtualDom and component state.
pub struct Scoped<'a, T = ()> {
/// The component's state and handle to the scheduler.
///
/// Stores things like the custom bump arena, spawn functions, hooks, and the scheduler.
pub scope: &'a ScopeState,
/// The component's properties.
pub props: &'a T,
}
impl<'a, T> std::ops::Deref for Scoped<'a, T> {
type Target = &'a ScopeState;
fn deref(&self) -> &Self::Target {
&self.scope
}
}
/// A component's unique identifier. /// A component's unique identifier.
/// ///
/// `ScopeId` is a `usize` that acts a key for the internal slab of Scopes. This means that the key is not unqiue across /// `ScopeId` is a `usize` that acts a key for the internal slab of Scopes. This means that the key is not unqiue across
@@ -300,69 +265,17 @@ impl<'src> ScopeState {
self.context().remove_future(id); self.context().remove_future(id);
} }
/// Take a lazy [`crate::VNode`] structure and actually build it with the context of the efficient [`bumpalo::Bump`] allocator.
///
/// ## Example
///
/// ```ignore
/// fn Component(cx: Scope<Props>) -> Element {
/// // Lazy assemble the VNode tree
/// let lazy_nodes = rsx!("hello world");
///
/// // Actually build the tree and allocate it
/// cx.render(lazy_tree)
/// }
///```
pub fn render(&'src self, rsx: LazyNodes<'src, '_>) -> Element {
let element = rsx.call(self);
let mut listeners = self.attributes_to_drop_before_render.borrow_mut();
for attr in element.dynamic_attrs {
match attr.value {
// We need to drop listeners before the next render because they may borrow data from the borrowed props which will be dropped
AttributeValue::Listener(_) => {
let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) };
listeners.push(unbounded);
}
// We need to drop any values manually to make sure that their drop implementation is called before the next render
AttributeValue::Any(_) => {
let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) };
self.previous_frame().add_attribute_to_drop(unbounded);
}
_ => (),
}
}
let mut props = self.borrowed_props.borrow_mut();
let mut drop_props = self
.previous_frame()
.props_to_drop_before_reset
.borrow_mut();
for node in element.dynamic_nodes {
if let DynamicNode::Component(comp) = node {
let unbounded = unsafe { std::mem::transmute(comp as *const VComponent) };
if !comp.static_props {
props.push(unbounded);
}
drop_props.push(unbounded);
}
}
Some(element)
}
/// Create a dynamic text node using [`Arguments`] and the [`ScopeState`]'s internal [`Bump`] allocator /// Create a dynamic text node using [`Arguments`] and the [`ScopeState`]'s internal [`Bump`] allocator
pub fn text_node(&'src self, args: Arguments) -> DynamicNode { pub fn text_node(&'src self, args: Arguments) -> DynamicNode {
DynamicNode::Text(VText { DynamicNode::Text(VText {
value: self.raw_text(args), value: args.to_string(),
id: Default::default(), id: Default::default(),
}) })
} }
/// 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<I> + 'c) -> DynamicNode {
into.into_dyn_node(self) into.into_dyn_node()
} }
/// Create a new [`Attribute`] from a name, value, namespace, and volatile bool /// Create a new [`Attribute`] from a name, value, namespace, and volatile bool
@@ -372,7 +285,7 @@ impl<'src> ScopeState {
pub fn attr( pub fn attr(
&'src self, &'src self,
name: &'static str, name: &'static str,
value: impl IntoAttributeValue<'src>, value: impl IntoAttributeValue,
namespace: Option<&'static str>, namespace: Option<&'static str>,
volatile: bool, volatile: bool,
) -> Attribute { ) -> Attribute {
@@ -381,7 +294,7 @@ impl<'src> ScopeState {
namespace, namespace,
volatile, volatile,
mounted_element: Default::default(), mounted_element: Default::default(),
value: value.into_value(self.bump()), value: value.into_value(),
} }
} }
@@ -399,37 +312,35 @@ impl<'src> ScopeState {
/// fn(Scope<Props>) -> Element; /// fn(Scope<Props>) -> Element;
/// async fn(Scope<Props<'_>>) -> Element; /// async fn(Scope<Props<'_>>) -> Element;
/// ``` /// ```
pub fn component<'child, P>( pub fn component<P>(
&'src self, &self,
component: fn(Scope<'child, P>) -> Element, component: fn(P) -> Element,
props: P, props: P,
fn_name: &'static str, fn_name: &'static str,
) -> DynamicNode ) -> 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,
// The current bump allocator frame must outlive the child's borrowed props
'src: 'child,
{ {
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 + '_> = Box::new(vcomp); let as_dyn: Box<dyn AnyProps> = Box::new(vcomp);
let extended: Box<dyn AnyProps + 'src> = unsafe { std::mem::transmute(as_dyn) }; let extended: Box<dyn AnyProps> = 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 (),
props: RefCell::new(Some(extended)), props: extended,
scope: Default::default(), scope: Default::default(),
}) })
} }
/// 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>(&self, f: impl FnMut(T)) -> EventHandler<T> {
let callback = RefCell::new(Some(Box::new(move |event: Event<T>| { let callback = RefCell::new(Some(Box::new(move |event: T| {
f(event.data); f(event);
}))); }) as Box<dyn FnMut(T)>));
EventHandler { EventHandler {
callback, callback,
origin: self.context().id, origin: self.context().id,
+5 -5
View File
@@ -11,7 +11,7 @@ use crate::{
nodes::{Template, TemplateId}, nodes::{Template, TemplateId},
runtime::{Runtime, RuntimeGuard}, runtime::{Runtime, RuntimeGuard},
scopes::{ScopeId, ScopeState}, scopes::{ScopeId, ScopeState},
AttributeValue, Element, Event, Scope, VNode, AttributeValue, Element, Event, VNode,
}; };
use futures_util::{pin_mut, StreamExt}; use futures_util::{pin_mut, StreamExt};
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
@@ -76,7 +76,7 @@ use std::{
/// } /// }
/// ///
/// #[component] /// #[component]
/// fn Title<'a>(cx: Scope<'a>, children: Element<'a>) -> Element { /// fn Title<'a>(cx: Scope<'a>, children: Element) -> Element {
/// cx.render(rsx! { /// cx.render(rsx! {
/// div { id: "title", children } /// div { id: "title", children }
/// }) /// })
@@ -224,7 +224,7 @@ impl VirtualDom {
/// ``` /// ```
/// ///
/// Note: the VirtualDom is not progressed, you must either "run_with_deadline" or use "rebuild" to progress it. /// Note: the VirtualDom is not progressed, you must either "run_with_deadline" or use "rebuild" to progress it.
pub fn new(app: fn(Scope) -> Element) -> Self { pub fn new(app: fn() -> Element) -> Self {
Self::new_with_props(app, ()) Self::new_with_props(app, ())
} }
@@ -258,7 +258,7 @@ impl VirtualDom {
/// let mut dom = VirtualDom::new_with_props(Example, SomeProps { name: "jane" }); /// let mut dom = VirtualDom::new_with_props(Example, SomeProps { name: "jane" });
/// let mutations = dom.rebuild(); /// let mutations = dom.rebuild();
/// ``` /// ```
pub fn new_with_props<P: 'static>(root: fn(Scope<P>) -> Element, root_props: P) -> Self { pub fn new_with_props<P: 'static>(root: fn(P) -> Element, root_props: P) -> Self {
let (tx, rx) = futures_channel::mpsc::unbounded(); let (tx, rx) = futures_channel::mpsc::unbounded();
let scheduler = Scheduler::new(tx); let scheduler = Scheduler::new(tx);
let mut dom = Self { let mut dom = Self {
@@ -567,7 +567,7 @@ impl VirtualDom {
/// ``` /// ```
pub fn rebuild(&mut self) -> Mutations { pub fn rebuild(&mut self) -> Mutations {
let _runtime = RuntimeGuard::new(self.runtime.clone()); let _runtime = RuntimeGuard::new(self.runtime.clone());
match unsafe { self.run_scope(ScopeId::ROOT).extend_lifetime_ref() } { match unsafe { self.run_scope(ScopeId::ROOT) } {
// Rebuilding implies we append the created elements to the root // Rebuilding implies we append the created elements to the root
RenderReturn::Ready(node) => { RenderReturn::Ready(node) => {
let m = self.create_scope(ScopeId::ROOT, node); let m = self.create_scope(ScopeId::ROOT, node);
+1 -1
View File
@@ -142,7 +142,7 @@ fn create_components() {
#[derive(Props)] #[derive(Props)]
struct ChildProps<'a> { struct ChildProps<'a> {
children: Element<'a>, children: Element,
} }
fn Child<'a>(cx: Scope<'a, ChildProps<'a>>) -> Element { fn Child<'a>(cx: Scope<'a, ChildProps<'a>>) -> Element {
+2 -2
View File
@@ -19,7 +19,7 @@ fn nested_passthru_creates() {
} }
#[component] #[component]
fn PassThru<'a>(cx: Scope<'a>, children: Element<'a>) -> Element { fn PassThru<'a>(cx: Scope<'a>, children: Element) -> Element {
cx.render(rsx!(children)) cx.render(rsx!(children))
} }
@@ -59,7 +59,7 @@ fn nested_passthru_creates_add() {
} }
#[component] #[component]
fn ChildComp<'a>(cx: Scope, children: Element<'a>) -> Element { fn ChildComp<'a>(cx: Scope, children: Element) -> Element {
cx.render(rsx! { children }) cx.render(rsx! { children })
} }
+2 -2
View File
@@ -15,7 +15,7 @@ fn random_ns() -> Option<&'static str> {
} }
} }
fn create_random_attribute(attr_idx: &mut usize) -> TemplateAttribute<'static> { fn create_random_attribute(attr_idx: &mut usize) -> TemplateAttribute {
match rand::random::<u8>() % 2 { match rand::random::<u8>() % 2 {
0 => TemplateAttribute::Static { 0 => TemplateAttribute::Static {
name: Box::leak(format!("attr{}", rand::random::<usize>()).into_boxed_str()), name: Box::leak(format!("attr{}", rand::random::<usize>()).into_boxed_str()),
@@ -238,7 +238,7 @@ struct BorrowedDepthProps<'a> {
inner: DepthProps, inner: DepthProps,
} }
fn create_random_element_borrowed<'a>(cx: Scope<'a, BorrowedDepthProps<'a>>) -> Element<'a> { fn create_random_element_borrowed<'a>(cx: Scope<'a, BorrowedDepthProps<'a>>) -> Element {
println!("{}", cx.props.borrow); println!("{}", cx.props.borrow);
let bump = cx.bump(); let bump = cx.bump();
let allocated = bump.alloc(Scoped { scope: cx, props: &cx.props.inner }); let allocated = bump.alloc(Scoped { scope: cx, props: &cx.props.inner });