fix render macro

This commit is contained in:
Evan Almloff 2023-12-07 13:21:47 -06:00 committed by Jonathan Kelley
parent a0ce5493ea
commit 0a35b5a670
No known key found for this signature in database
GPG key ID: 1FBB50F7EB0A08BE
3 changed files with 53 additions and 4 deletions

View file

@ -1,4 +1,4 @@
use std::ptr::NonNull;
use crate::ScopeState;use std::ptr::NonNull;
use crate::{
innerlude::DirtyScope, nodes::RenderReturn, nodes::VNode, virtual_dom::VirtualDom,
@ -174,7 +174,14 @@ impl VirtualDom {
scope.borrowed_props.borrow_mut().clear();
// Now that all the references are gone, we can safely drop our own references in our listeners.
let mut listeners = scope.attributes_to_drop_before_render.borrow_mut();
scope.drop_listeners();
}
}
impl ScopeState {
/// Drop all listeners that were allocated in the bump allocator.
pub(crate) fn drop_listeners(&self) {
let mut listeners = self.attributes_to_drop_before_render.borrow_mut();
listeners.drain(..).for_each(|listener| {
let listener = unsafe { &*listener };
if let AttributeValue::Listener(l) = &listener.value {

View file

@ -102,6 +102,7 @@ pub struct ScopeState {
impl Drop for ScopeState {
fn drop(&mut self) {
self.drop_listeners();
self.runtime.remove_context(self.context_id);
}
}
@ -345,7 +346,7 @@ impl<'src> ScopeState {
/// // Actually build the tree and allocate it
/// cx.render(lazy_tree)
/// }
///```
/// ```
pub fn render(&'src self, rsx: LazyNodes<'src, '_>) -> Element<'src> {
let element = rsx.call(self);
@ -387,6 +388,45 @@ impl<'src> ScopeState {
Some(element)
}
#[doc(hidden)]
/// Take a [`crate::VNode`] and link it to a [`ScopeState`]
///
/// This is used internally in the render macro
pub fn link_node(&'src self, element: &crate::VNode<'src>) {
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);
}
}
}
/// Create a dynamic text node using [`Arguments`] and the [`ScopeState`]'s internal [`Bump`] allocator
pub fn text_node(&'src self, args: Arguments) -> DynamicNode<'src> {
DynamicNode::Text(VText {

View file

@ -139,7 +139,9 @@ impl ToTokens for RenderCallBody {
out_tokens.append_all(quote! {
Some({
let __cx = cx;
#body
let __element = { #body };
cx.link_node(&__element);
__element
})
})
}