remove more lifetimes

This commit is contained in:
Evan Almloff 2024-01-05 08:39:22 -06:00
parent 3ad16ddd37
commit f42ef3ef9d
18 changed files with 241 additions and 421 deletions

View file

@ -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"));

View file

@ -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:?}" }
})

View file

@ -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 {

View file

@ -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();

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.
///
/// 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

View file

@ -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)
}

View file

@ -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([]),
}
}),

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(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.

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.
#[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)

View file

@ -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,
};
}

View file

@ -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,
}
}

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
/// 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()
}

View file

@ -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();

View file

@ -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,

View file

@ -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);

View file

@ -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 {

View file

@ -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 })
}

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 {
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 });