remove more lifetimes

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

No files matched your search

+16 -105
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,