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