From 0a35b5a6705ee7528b47c81b1c6293ee768649c1 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 7 Dec 2023 13:21:47 -0600 Subject: [PATCH 1/4] fix render macro --- packages/core/src/arena.rs | 11 ++++++++-- packages/core/src/scopes.rs | 42 ++++++++++++++++++++++++++++++++++++- packages/rsx/src/lib.rs | 4 +++- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/packages/core/src/arena.rs b/packages/core/src/arena.rs index ffdd4656b..ecefe20f7 100644 --- a/packages/core/src/arena.rs +++ b/packages/core/src/arena.rs @@ -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 { diff --git a/packages/core/src/scopes.rs b/packages/core/src/scopes.rs index 64a60b112..e3c42f515 100644 --- a/packages/core/src/scopes.rs +++ b/packages/core/src/scopes.rs @@ -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 { diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index aee1bb431..915d2bd2a 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -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 }) }) } From 44a27bf8a3eafd7b950eddf59dd71effe535aaf5 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 8 Jan 2024 19:04:25 -0800 Subject: [PATCH 2/4] Fix leak in render macro --- packages/core/src/arena.rs | 3 +- packages/core/src/fragment.rs | 17 ++- packages/core/src/lazynodes.rs | 20 +-- packages/core/src/nodes.rs | 38 +++--- packages/core/src/scopes.rs | 122 +++++++++++------- packages/core/tests/fuzzing.rs | 35 ++++- .../examples/many_small_edit_stress.rs | 2 +- packages/native-core/tests/fuzzing.rs | 56 ++++++-- packages/rsx/src/lib.rs | 18 ++- 9 files changed, 197 insertions(+), 114 deletions(-) diff --git a/packages/core/src/arena.rs b/packages/core/src/arena.rs index ecefe20f7..d1b6f9290 100644 --- a/packages/core/src/arena.rs +++ b/packages/core/src/arena.rs @@ -1,4 +1,5 @@ -use crate::ScopeState;use std::ptr::NonNull; +use crate::ScopeState; +use std::ptr::NonNull; use crate::{ innerlude::DirtyScope, nodes::RenderReturn, nodes::VNode, virtual_dom::VirtualDom, diff --git a/packages/core/src/fragment.rs b/packages/core/src/fragment.rs index 4a775a57c..1403f41b9 100644 --- a/packages/core/src/fragment.rs +++ b/packages/core/src/fragment.rs @@ -28,15 +28,14 @@ use crate::innerlude::*; #[allow(non_upper_case_globals, non_snake_case)] pub fn Fragment<'a>(cx: Scope<'a, FragmentProps<'a>>) -> Element { let children = cx.props.0.as_ref()?; - Some(VNode { - key: children.key, - parent: children.parent.clone(), - stable_id: children.stable_id.clone(), - template: children.template.clone(), - root_ids: children.root_ids.clone(), - dynamic_nodes: children.dynamic_nodes, - dynamic_attrs: children.dynamic_attrs, - }) + Some(cx.vnode( + children.parent.clone(), + children.key, + children.template.clone(), + children.root_ids.clone(), + children.dynamic_nodes, + children.dynamic_attrs, + )) } pub struct FragmentProps<'a>(Element<'a>); diff --git a/packages/core/src/lazynodes.rs b/packages/core/src/lazynodes.rs index ae1bd2109..a7e6906dc 100644 --- a/packages/core/src/lazynodes.rs +++ b/packages/core/src/lazynodes.rs @@ -24,7 +24,7 @@ use crate::{innerlude::VNode, ScopeState}; /// /// ```rust, ignore /// LazyNodes::new(|f| { -/// static TEMPLATE: dioxus::core::Template = dioxus::core::Template { +/// static TEMPLATE: dioxus::core::Template = dioxus::core::Template { /// name: "main.rs:5:5:20", // Source location of the template for hot reloading /// roots: &[ /// dioxus::core::TemplateNode::Element { @@ -37,19 +37,19 @@ use crate::{innerlude::VNode, ScopeState}; /// node_paths: &[], /// attr_paths: &[], /// }; -/// dioxus::core::VNode { -/// parent: None, -/// key: None, -/// template: std::cell::Cell::new(TEMPLATE), -/// root_ids: dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in( +/// f.vnode( +/// None, +/// None, +/// std::cell::Cell::new(TEMPLATE), +/// dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in( /// 1usize, /// f.bump(), /// ) /// .into(), -/// dynamic_nodes: f.bump().alloc([]), -/// dynamic_attrs: f.bump().alloc([]), -/// }) -/// } +/// f.bump().alloc([]), +/// f.bump().alloc([]), +/// ) +/// }) /// ``` /// /// Find more information about how to construct [`VNode`] at diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index 6396504a4..98964e948 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -40,6 +40,7 @@ impl<'a> Default for RenderReturn<'a> { /// /// The dynamic parts of the template are stored separately from the static parts. This allows faster diffing by skipping /// static parts of the template. +#[non_exhaustive] #[derive(Debug, Clone)] pub struct VNode<'a> { /// The key given to the root of this template. @@ -70,20 +71,19 @@ pub struct VNode<'a> { impl<'a> VNode<'a> { /// Create a template with no nodes that will be skipped over during diffing pub fn empty(cx: &'a ScopeState) -> Element<'a> { - Some(VNode { - key: None, - parent: Default::default(), - stable_id: Default::default(), - root_ids: RefCell::new(bumpalo::collections::Vec::new_in(cx.bump())), - dynamic_nodes: &[], - dynamic_attrs: &[], - template: Cell::new(Template { + Some(cx.vnode( + Cell::new(None), + None, + Cell::new(Template { name: "dioxus-empty", roots: &[], node_paths: &[], attr_paths: &[], }), - }) + RefCell::new(bumpalo::collections::Vec::new_in(cx.bump())), + &[], + &[], + )) } /// Create a new VNode @@ -820,16 +820,16 @@ impl<'b> IntoDynNode<'b> for Arguments<'_> { } impl<'a> IntoDynNode<'a> for &'a VNode<'a> { - fn into_dyn_node(self, _cx: &'a ScopeState) -> DynamicNode<'a> { - 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, - }])) + fn into_dyn_node(self, cx: &'a ScopeState) -> DynamicNode<'a> { + let vnode = cx.vnode( + self.parent.clone(), + self.key, + self.template.clone(), + self.root_ids.clone(), + self.dynamic_nodes, + self.dynamic_attrs, + ); + DynamicNode::Fragment(cx.bump().alloc([vnode])) } } diff --git a/packages/core/src/scopes.rs b/packages/core/src/scopes.rs index e3c42f515..11d45d5c1 100644 --- a/packages/core/src/scopes.rs +++ b/packages/core/src/scopes.rs @@ -2,13 +2,13 @@ use crate::{ any_props::AnyProps, any_props::VProps, bump_frame::BumpFrame, - innerlude::{DynamicNode, EventHandler, VComponent, VNodeId, VText}, + innerlude::{DynamicNode, ElementRef, EventHandler, VComponent, VNodeId, VText}, lazynodes::LazyNodes, nodes::{IntoAttributeValue, IntoDynNode, RenderReturn}, runtime::Runtime, scope_context::ScopeContext, - AnyValue, Attribute, AttributeType, AttributeValue, Element, Event, MountedAttribute, - Properties, TaskId, + AnyValue, Attribute, AttributeType, AttributeValue, Element, ElementId, Event, + MountedAttribute, Properties, TaskId, Template, VNode, }; use bumpalo::{boxed::Box as BumpBox, Bump}; use std::{ @@ -348,17 +348,76 @@ impl<'src> ScopeState { /// } /// ``` pub fn render(&'src self, rsx: LazyNodes<'src, '_>) -> Element<'src> { - let element = rsx.call(self); + // <<<<<<< HEAD + // let element = rsx.call(self); + // let mut listeners = self.attributes_to_drop_before_render.borrow_mut(); + // for attr in element.dynamic_attrs { + // attr.ty.for_each(|attr| { + // 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) + // ======= + // Note: We can't do anything in this function related to safety because the user could always circumvent it by creating a VNode manually and return it without calling this function + Some(rsx.call(self)) + // >>>>>>> 9fe172e9 (Fix leak in render macro) + } + + /// Create a [`crate::VNode`] from the component parts + pub fn vnode( + &'src self, + parent: Cell>, + key: Option<&'src str>, + template: Cell>, + root_ids: RefCell>, + dynamic_nodes: &'src [DynamicNode<'src>], + dynamic_attrs: &'src [MountedAttribute<'src>], + ) -> VNode<'src> { let mut listeners = self.attributes_to_drop_before_render.borrow_mut(); - for attr in element.dynamic_attrs { - attr.ty.for_each(|attr| { + for attr in dynamic_attrs { + let attrs = match attr.ty { + AttributeType::Single(ref attr) => std::slice::from_ref(attr), + AttributeType::Many(attrs) => attrs, + }; + + for attr in 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) }; @@ -367,7 +426,7 @@ impl<'src> ScopeState { _ => (), } - }) + } } let mut props = self.borrowed_props.borrow_mut(); @@ -375,7 +434,7 @@ impl<'src> ScopeState { .previous_frame() .props_to_drop_before_reset .borrow_mut(); - for node in element.dynamic_nodes { + for node in dynamic_nodes { if let DynamicNode::Component(comp) = node { let unbounded = unsafe { std::mem::transmute(comp as *const VComponent) }; if !comp.static_props { @@ -385,45 +444,14 @@ 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); - } + VNode { + stable_id: Default::default(), + key, + parent, + template, + root_ids, + dynamic_nodes, + dynamic_attrs, } } diff --git a/packages/core/tests/fuzzing.rs b/packages/core/tests/fuzzing.rs index af5e9d05c..303ef768d 100644 --- a/packages/core/tests/fuzzing.rs +++ b/packages/core/tests/fuzzing.rs @@ -171,15 +171,27 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode { match rand::random::() % range { 0 => DynamicNode::Placeholder(Default::default()), 1 => cx.make_node((0..(rand::random::() % 5)).map(|_| { - VNode::new( + // <<<<<<< HEAD + // VNode::new( + // None, + // Template { + // ======= + cx.vnode( None, - Template { + Default::default(), + Cell::new(Template { + // >>>>>>> 9fe172e9 (Fix leak in render macro) name: concat!(file!(), ":", line!(), ":", column!(), ":0"), roots: &[TemplateNode::Dynamic { id: 0 }], node_paths: &[&[0]], attr_paths: &[], - }, - bumpalo::collections::Vec::new_in(cx.bump()), + // <<<<<<< HEAD + // }, + // bumpalo::collections::Vec::new_in(cx.bump()), + // ======= + }), + bumpalo::collections::Vec::new_in(cx.bump()).into(), + // >>>>>>> 9fe172e9 (Fix leak in render macro) cx.bump().alloc([cx.component( create_random_element, DepthProps { depth, root: false }, @@ -273,10 +285,19 @@ fn create_random_element(cx: Scope) -> Element { ) .into_boxed_str(), )); - let node = VNode::new( + // <<<<<<< HEAD + // let node = VNode::new( + // None, + // template, + // bumpalo::collections::Vec::new_in(cx.bump()), + // ======= + // println!("{template:#?}"); + let node = cx.vnode( None, - template, - bumpalo::collections::Vec::new_in(cx.bump()), + None, + Cell::new(template), + bumpalo::collections::Vec::new_in(cx.bump()).into(), + // >>>>>>> 9fe172e9 (Fix leak in render macro) { let dynamic_nodes: Vec<_> = dynamic_node_types .iter() diff --git a/packages/dioxus-tui/examples/many_small_edit_stress.rs b/packages/dioxus-tui/examples/many_small_edit_stress.rs index 0668077cd..5f9d9d76f 100644 --- a/packages/dioxus-tui/examples/many_small_edit_stress.rs +++ b/packages/dioxus-tui/examples/many_small_edit_stress.rs @@ -83,7 +83,7 @@ fn Grid(cx: Scope) -> Element { let alpha = y as f32*100.0/size as f32 + counts.read()[x*size + y] as f32; let key = format!("{}-{}", x, y); rsx! { - Box{ + Box { x: x, y: y, alpha: 100.0, diff --git a/packages/native-core/tests/fuzzing.rs b/packages/native-core/tests/fuzzing.rs index 4abcc2351..652ad301f 100644 --- a/packages/native-core/tests/fuzzing.rs +++ b/packages/native-core/tests/fuzzing.rs @@ -178,15 +178,27 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode { match rand::random::() % range { 0 => DynamicNode::Placeholder(Default::default()), 1 => cx.make_node((0..(rand::random::() % 5)).map(|_| { - VNode::new( + // <<<<<<< HEAD + // VNode::new( + // None, + // Template { + // ======= + cx.vnode( None, - Template { + Default::default(), + Cell::new(Template { + // >>>>>>> 9fe172e9 (Fix leak in render macro) name: concat!(file!(), ":", line!(), ":", column!(), ":0"), roots: &[TemplateNode::Dynamic { id: 0 }], node_paths: &[&[0]], attr_paths: &[], - }, - dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()), + // <<<<<<< HEAD + // }, + // dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()), + // ======= + }), + dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()).into(), + // >>>>>>> 9fe172e9 (Fix leak in render macro) cx.bump().alloc([cx.component( create_random_element, DepthProps { depth, root: false }, @@ -266,10 +278,18 @@ fn create_random_element(cx: Scope) -> Element { .into_boxed_str(), )); println!("{template:#?}"); - let node = VNode::new( + // <<<<<<< HEAD + // let node = VNode::new( + // None, + // template, + // dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()), + // ======= + let node = cx.vnode( None, - template, - dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()), + None, + Cell::new(template), + dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()).into(), + // >>>>>>> 9fe172e9 (Fix leak in render macro) { let dynamic_nodes: Vec<_> = dynamic_node_types .iter() @@ -284,13 +304,21 @@ fn create_random_element(cx: Scope) -> Element { .collect(); cx.bump().alloc(dynamic_nodes) }, - cx.bump() - .alloc( - (0..template.attr_paths.len()) - .map(|_| create_random_dynamic_mounted_attr(cx)) - .collect::>(), - ) - .as_slice(), + // <<<<<<< HEAD + // cx.bump() + // .alloc( + // (0..template.attr_paths.len()) + // .map(|_| create_random_dynamic_mounted_attr(cx)) + // .collect::>(), + // ) + // .as_slice(), + // ======= + cx.bump().alloc( + (0..template.attr_paths.len()) + .map(|_| create_random_dynamic_attr(cx)) + .collect::>(), + ), + // >>>>>>> 9fe172e9 (Fix leak in render macro) ); Some(node) } diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index 915d2bd2a..1680e338d 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -139,9 +139,7 @@ impl ToTokens for RenderCallBody { out_tokens.append_all(quote! { Some({ let __cx = cx; - let __element = { #body }; - cx.link_node(&__element); - __element + #body }) }) } @@ -256,10 +254,18 @@ impl<'a> ToTokens for TemplateRenderer<'a> { node_paths: &[ #(#node_paths),* ], attr_paths: &[ #(#attr_paths),* ], }; - ::dioxus::core::VNode::new( +// <<<<<<< HEAD +// ::dioxus::core::VNode::new( +// #key_tokens, +// TEMPLATE, +// dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in(#root_count, __cx.bump()), +// ======= + __cx.vnode( + None, #key_tokens, - TEMPLATE, - dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in(#root_count, __cx.bump()), + std::cell::Cell::new(TEMPLATE), + dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in(#root_count, __cx.bump()).into(), +// >>>>>>> 9fe172e9 (Fix leak in render macro) __cx.bump().alloc([ #( #node_printer ),* ]), __cx.bump().alloc([ #( #dyn_attr_printer ),* ]), ) From 23f7a37b0623766be90d55dc25bc5da1c5e52329 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 8 Jan 2024 19:31:57 -0800 Subject: [PATCH 3/4] Clean up merge conflicts --- packages/core/tests/fuzzing.rs | 6 +-- packages/native-core/tests/fuzzing.rs | 61 ++++++--------------------- packages/rsx/src/lib.rs | 2 +- 3 files changed, 16 insertions(+), 53 deletions(-) diff --git a/packages/core/tests/fuzzing.rs b/packages/core/tests/fuzzing.rs index 303ef768d..b16d9b3bb 100644 --- a/packages/core/tests/fuzzing.rs +++ b/packages/core/tests/fuzzing.rs @@ -2,7 +2,7 @@ use dioxus::prelude::Props; use dioxus_core::{MountedAttribute, *}; -use std::{cfg, collections::HashSet}; +use std::{cell::Cell, cfg, collections::HashSet}; fn random_ns() -> Option<&'static str> { let namespace = rand::random::() % 2; @@ -177,7 +177,7 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode { // Template { // ======= cx.vnode( - None, + None.into(), Default::default(), Cell::new(Template { // >>>>>>> 9fe172e9 (Fix leak in render macro) @@ -293,7 +293,7 @@ fn create_random_element(cx: Scope) -> Element { // ======= // println!("{template:#?}"); let node = cx.vnode( - None, + None.into(), None, Cell::new(template), bumpalo::collections::Vec::new_in(cx.bump()).into(), diff --git a/packages/native-core/tests/fuzzing.rs b/packages/native-core/tests/fuzzing.rs index 652ad301f..2496b1f1c 100644 --- a/packages/native-core/tests/fuzzing.rs +++ b/packages/native-core/tests/fuzzing.rs @@ -1,3 +1,5 @@ +use std::cell::Cell; + use dioxus::prelude::Props; use dioxus_core::*; use dioxus_native_core::prelude::*; @@ -178,27 +180,16 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode { match rand::random::() % range { 0 => DynamicNode::Placeholder(Default::default()), 1 => cx.make_node((0..(rand::random::() % 5)).map(|_| { - // <<<<<<< HEAD - // VNode::new( - // None, - // Template { - // ======= cx.vnode( - None, + None.into(), Default::default(), Cell::new(Template { - // >>>>>>> 9fe172e9 (Fix leak in render macro) name: concat!(file!(), ":", line!(), ":", column!(), ":0"), roots: &[TemplateNode::Dynamic { id: 0 }], node_paths: &[&[0]], attr_paths: &[], - // <<<<<<< HEAD - // }, - // dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()), - // ======= }), dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()).into(), - // >>>>>>> 9fe172e9 (Fix leak in render macro) cx.bump().alloc([cx.component( create_random_element, DepthProps { depth, root: false }, @@ -216,20 +207,6 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode { } } -fn create_random_dynamic_mounted_attr(cx: &ScopeState) -> MountedAttribute { - match rand::random::() % 2 { - 0 => MountedAttribute::from( - &*cx.bump().alloc( - (0..(rand::random::() % 3) as usize) - .map(|_| create_random_dynamic_attr(cx)) - .collect::>(), - ), - ), - 1 => MountedAttribute::from(create_random_dynamic_attr(cx)), - _ => unreachable!(), - } -} - fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute { let value = match rand::random::() % 6 { 0 => AttributeValue::Text(Box::leak( @@ -242,6 +219,7 @@ fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute { 5 => AttributeValue::None, _ => unreachable!(), }; + Attribute::new( Box::leak(format!("attr{}", rand::random::()).into_boxed_str()), value, @@ -278,18 +256,11 @@ fn create_random_element(cx: Scope) -> Element { .into_boxed_str(), )); println!("{template:#?}"); - // <<<<<<< HEAD - // let node = VNode::new( - // None, - // template, - // dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()), - // ======= let node = cx.vnode( - None, + None.into(), None, Cell::new(template), dioxus::core::exports::bumpalo::collections::Vec::new_in(cx.bump()).into(), - // >>>>>>> 9fe172e9 (Fix leak in render macro) { let dynamic_nodes: Vec<_> = dynamic_node_types .iter() @@ -304,21 +275,13 @@ fn create_random_element(cx: Scope) -> Element { .collect(); cx.bump().alloc(dynamic_nodes) }, - // <<<<<<< HEAD - // cx.bump() - // .alloc( - // (0..template.attr_paths.len()) - // .map(|_| create_random_dynamic_mounted_attr(cx)) - // .collect::>(), - // ) - // .as_slice(), - // ======= - cx.bump().alloc( - (0..template.attr_paths.len()) - .map(|_| create_random_dynamic_attr(cx)) - .collect::>(), - ), - // >>>>>>> 9fe172e9 (Fix leak in render macro) + cx.bump() + .alloc( + (0..template.attr_paths.len()) + .map(|_| create_random_dynamic_attr(cx).into()) + .collect::>(), + ) + .as_slice(), ); Some(node) } diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index 1680e338d..5e685680d 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -261,7 +261,7 @@ impl<'a> ToTokens for TemplateRenderer<'a> { // dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in(#root_count, __cx.bump()), // ======= __cx.vnode( - None, + None.into(), #key_tokens, std::cell::Cell::new(TEMPLATE), dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in(#root_count, __cx.bump()).into(), From b8fac44537c1dc80f0416491a62d093c258e7376 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 8 Jan 2024 19:33:39 -0800 Subject: [PATCH 4/4] Clean up merge comments --- packages/core/src/scopes.rs | 41 ---------------------------------- packages/core/tests/fuzzing.rs | 20 +---------------- packages/rsx/src/lib.rs | 8 +------ 3 files changed, 2 insertions(+), 67 deletions(-) diff --git a/packages/core/src/scopes.rs b/packages/core/src/scopes.rs index 11d45d5c1..63a9144f2 100644 --- a/packages/core/src/scopes.rs +++ b/packages/core/src/scopes.rs @@ -348,49 +348,8 @@ impl<'src> ScopeState { /// } /// ``` pub fn render(&'src self, rsx: LazyNodes<'src, '_>) -> Element<'src> { - // <<<<<<< HEAD - // let element = rsx.call(self); - - // let mut listeners = self.attributes_to_drop_before_render.borrow_mut(); - // for attr in element.dynamic_attrs { - // attr.ty.for_each(|attr| { - // 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) - // ======= // Note: We can't do anything in this function related to safety because the user could always circumvent it by creating a VNode manually and return it without calling this function Some(rsx.call(self)) - // >>>>>>> 9fe172e9 (Fix leak in render macro) } /// Create a [`crate::VNode`] from the component parts diff --git a/packages/core/tests/fuzzing.rs b/packages/core/tests/fuzzing.rs index b16d9b3bb..76065ccc1 100644 --- a/packages/core/tests/fuzzing.rs +++ b/packages/core/tests/fuzzing.rs @@ -171,27 +171,16 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode { match rand::random::() % range { 0 => DynamicNode::Placeholder(Default::default()), 1 => cx.make_node((0..(rand::random::() % 5)).map(|_| { - // <<<<<<< HEAD - // VNode::new( - // None, - // Template { - // ======= cx.vnode( None.into(), Default::default(), Cell::new(Template { - // >>>>>>> 9fe172e9 (Fix leak in render macro) name: concat!(file!(), ":", line!(), ":", column!(), ":0"), roots: &[TemplateNode::Dynamic { id: 0 }], node_paths: &[&[0]], attr_paths: &[], - // <<<<<<< HEAD - // }, - // bumpalo::collections::Vec::new_in(cx.bump()), - // ======= }), bumpalo::collections::Vec::new_in(cx.bump()).into(), - // >>>>>>> 9fe172e9 (Fix leak in render macro) cx.bump().alloc([cx.component( create_random_element, DepthProps { depth, root: false }, @@ -285,19 +274,12 @@ fn create_random_element(cx: Scope) -> Element { ) .into_boxed_str(), )); - // <<<<<<< HEAD - // let node = VNode::new( - // None, - // template, - // bumpalo::collections::Vec::new_in(cx.bump()), - // ======= - // println!("{template:#?}"); + println!("{template:#?}"); let node = cx.vnode( None.into(), None, Cell::new(template), bumpalo::collections::Vec::new_in(cx.bump()).into(), - // >>>>>>> 9fe172e9 (Fix leak in render macro) { let dynamic_nodes: Vec<_> = dynamic_node_types .iter() diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index 5e685680d..70d03fc52 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -254,18 +254,12 @@ impl<'a> ToTokens for TemplateRenderer<'a> { node_paths: &[ #(#node_paths),* ], attr_paths: &[ #(#attr_paths),* ], }; -// <<<<<<< HEAD -// ::dioxus::core::VNode::new( -// #key_tokens, -// TEMPLATE, -// dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in(#root_count, __cx.bump()), -// ======= + __cx.vnode( None.into(), #key_tokens, std::cell::Cell::new(TEMPLATE), dioxus::core::exports::bumpalo::collections::Vec::with_capacity_in(#root_count, __cx.bump()).into(), -// >>>>>>> 9fe172e9 (Fix leak in render macro) __cx.bump().alloc([ #( #node_printer ),* ]), __cx.bump().alloc([ #( #dyn_attr_printer ),* ]), )