feat: enable children properly

This commit is contained in:
Jonathan Kelley committed 2021-12-21 00:46:10 -05:00
1 parent dbb981d500
commit b997b8ebbb
10 files changed
+128 -131

No files matched your search

+1 -1
View File
@@ -17,7 +17,7 @@ pub fn format_args_f(input: TokenStream) -> TokenStream {
.into() .into()
} }
#[proc_macro_derive(Props, attributes(builder))] #[proc_macro_derive(Props, attributes(props))]
pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::TokenStream { pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as syn::DeriveInput); let input = parse_macro_input!(input as syn::DeriveInput);
match props::impl_my_derive(&input) { match props::impl_my_derive(&input) {
+19 -5
View File
@@ -3,8 +3,8 @@
//! However, it has been adopted to fit the Dioxus Props builder pattern. //! However, it has been adopted to fit the Dioxus Props builder pattern.
//! //!
//! For dioxus, we make a few changes: //! For dioxus, we make a few changes:
//! - automatically implement Into<Option> on the setters (IE the strip setter option) //! - [ ] automatically implement Into<Option> on the setters (IE the strip setter option)
//! - automatically implement a default of none for optional fields (those explicitly wrapped with Option<T>) //! - [ ] automatically implement a default of none for optional fields (those explicitly wrapped with Option<T>)
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
@@ -194,6 +194,14 @@ mod field_info {
field_defaults: FieldBuilderAttr, field_defaults: FieldBuilderAttr,
) -> Result<FieldInfo, Error> { ) -> Result<FieldInfo, Error> {
if let Some(ref name) = field.ident { if let Some(ref name) = field.ident {
let mut builder_attr = field_defaults.with(&field.attrs)?;
// children field is automatically defaulted to None
if name == "children" {
builder_attr.default =
Some(syn::parse(quote!(Default::default()).into()).unwrap());
}
Ok(FieldInfo { Ok(FieldInfo {
ordinal, ordinal,
name, name,
@@ -202,7 +210,7 @@ mod field_info {
proc_macro2::Span::call_site(), proc_macro2::Span::call_site(),
), ),
ty: &field.ty, ty: &field.ty,
builder_attr: field_defaults.with(&field.attrs)?, builder_attr,
}) })
} else { } else {
Err(Error::new(field.span(), "Nameless field in struct")) Err(Error::new(field.span(), "Nameless field in struct"))
@@ -285,7 +293,7 @@ mod field_info {
pub fn with(mut self, attrs: &[syn::Attribute]) -> Result<Self, Error> { pub fn with(mut self, attrs: &[syn::Attribute]) -> Result<Self, Error> {
let mut skip_tokens = None; let mut skip_tokens = None;
for attr in attrs { for attr in attrs {
if path_to_single_string(&attr.path).as_deref() != Some("builder") { if path_to_single_string(&attr.path).as_deref() != Some("props") {
continue; continue;
} }
@@ -316,7 +324,7 @@ mod field_info {
if self.setter.skip && self.default.is_none() { if self.setter.skip && self.default.is_none() {
return Err(Error::new_spanned( return Err(Error::new_spanned(
skip_tokens.unwrap(), skip_tokens.unwrap(),
"#[builder(skip)] must be accompanied by default or default_code", "#[props(skip)] must be accompanied by default or default_code",
)); ));
} }
@@ -325,6 +333,7 @@ mod field_info {
pub fn apply_meta(&mut self, expr: syn::Expr) -> Result<(), Error> { pub fn apply_meta(&mut self, expr: syn::Expr) -> Result<(), Error> {
match expr { match expr {
// #[props(default = "...")]
syn::Expr::Assign(assign) => { syn::Expr::Assign(assign) => {
let name = expr_to_single_string(&assign.left) let name = expr_to_single_string(&assign.left)
.ok_or_else(|| Error::new_spanned(&assign.left, "Expected identifier"))?; .ok_or_else(|| Error::new_spanned(&assign.left, "Expected identifier"))?;
@@ -356,6 +365,8 @@ mod field_info {
)), )),
} }
} }
// uh not sure
syn::Expr::Path(path) => { syn::Expr::Path(path) => {
let name = path_to_single_string(&path.path) let name = path_to_single_string(&path.path)
.ok_or_else(|| Error::new_spanned(&path, "Expected identifier"))?; .ok_or_else(|| Error::new_spanned(&path, "Expected identifier"))?;
@@ -371,6 +382,8 @@ mod field_info {
)), )),
} }
} }
//
syn::Expr::Call(call) => { syn::Expr::Call(call) => {
let subsetting_name = if let syn::Expr::Path(path) = &*call.func { let subsetting_name = if let syn::Expr::Path(path) = &*call.func {
path_to_single_string(&path.path) path_to_single_string(&path.path)
@@ -398,6 +411,7 @@ mod field_info {
)), )),
} }
} }
syn::Expr::Unary(syn::ExprUnary { syn::Expr::Unary(syn::ExprUnary {
op: syn::UnOp::Not(_), op: syn::UnOp::Not(_),
expr, expr,
@@ -0,0 +1,40 @@
#![allow(non_snake_case)]
use dioxus::prelude::*;
use dioxus_core as dioxus;
use dioxus_core_macro::*;
use dioxus_html as dioxus_elements;
fn main() {
let mut dom = VirtualDom::new(parent);
let edits = dom.rebuild();
dbg!(edits);
}
fn parent(cx: Scope<()>) -> Element {
let value = cx.use_hook(|_| String::new(), |f| f);
cx.render(rsx! {
div {
child(
name: value,
h1 {"hi"}
)
}
})
}
#[derive(Props)]
struct ChildProps<'a> {
name: &'a str,
children: Element<'a>,
}
fn child<'a>(cx: Scope<'a, ChildProps<'a>>) -> Element {
cx.render(rsx! {
div {
"it's nested {cx.props.name}"
{&cx.props.children}
}
})
}
+23 -25
View File
@@ -88,8 +88,6 @@
//! More info on how to improve this diffing algorithm: //! More info on how to improve this diffing algorithm:
//! - https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/ //! - https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/
use std::borrow::BorrowMut;
use crate::innerlude::*; use crate::innerlude::*;
use fxhash::{FxHashMap, FxHashSet}; use fxhash::{FxHashMap, FxHashSet};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
@@ -295,7 +293,7 @@ impl<'bump> DiffState<'bump> {
for child in el.children.iter() { for child in el.children.iter() {
num_on_stack += self.push_all_nodes(child); num_on_stack += self.push_all_nodes(child);
} }
self.mutations.push_root(el.dom_id.get().unwrap()); self.mutations.push_root(el.id.get().unwrap());
num_on_stack + 1 num_on_stack + 1
} }
@@ -351,7 +349,7 @@ impl<'bump> DiffState<'bump> {
let real_id = self.scopes.reserve_node(node); let real_id = self.scopes.reserve_node(node);
self.mutations.create_text_node(vtext.text, real_id); self.mutations.create_text_node(vtext.text, real_id);
vtext.dom_id.set(Some(real_id)); vtext.id.set(Some(real_id));
self.stack.add_child_count(1); self.stack.add_child_count(1);
} }
@@ -359,20 +357,20 @@ impl<'bump> DiffState<'bump> {
let real_id = self.scopes.reserve_node(node); let real_id = self.scopes.reserve_node(node);
self.mutations.create_placeholder(real_id); self.mutations.create_placeholder(real_id);
anchor.dom_id.set(Some(real_id)); anchor.id.set(Some(real_id));
self.stack.add_child_count(1); self.stack.add_child_count(1);
} }
fn create_element_node(&mut self, element: &'bump VElement<'bump>, node: &'bump VNode<'bump>) { fn create_element_node(&mut self, element: &'bump VElement<'bump>, node: &'bump VNode<'bump>) {
let VElement { let VElement {
tag_name, tag: tag_name,
listeners, listeners,
attributes, attributes,
children, children,
namespace, namespace,
dom_id, id: dom_id,
parent_id, parent: parent_id,
.. ..
} = element; } = element;
@@ -479,9 +477,9 @@ impl<'bump> DiffState<'bump> {
} }
(Element(old), Element(new)) => self.diff_element_nodes(old, new, old_node, new_node), (Element(old), Element(new)) => self.diff_element_nodes(old, new, old_node, new_node),
(Placeholder(old), Placeholder(new)) => { (Placeholder(old), Placeholder(new)) => {
if let Some(root) = old.dom_id.get() { if let Some(root) = old.id.get() {
self.scopes.update_node(new_node, root); self.scopes.update_node(new_node, root);
new.dom_id.set(Some(root)) new.id.set(Some(root))
} }
} }
@@ -515,13 +513,13 @@ impl<'bump> DiffState<'bump> {
_old_node: &'bump VNode<'bump>, _old_node: &'bump VNode<'bump>,
new_node: &'bump VNode<'bump>, new_node: &'bump VNode<'bump>,
) { ) {
if let Some(root) = old.dom_id.get() { if let Some(root) = old.id.get() {
if old.text != new.text { if old.text != new.text {
self.mutations.set_text(new.text, root.as_u64()); self.mutations.set_text(new.text, root.as_u64());
} }
self.scopes.update_node(new_node, root); self.scopes.update_node(new_node, root);
new.dom_id.set(Some(root)); new.id.set(Some(root));
} }
} }
@@ -532,13 +530,13 @@ impl<'bump> DiffState<'bump> {
old_node: &'bump VNode<'bump>, old_node: &'bump VNode<'bump>,
new_node: &'bump VNode<'bump>, new_node: &'bump VNode<'bump>,
) { ) {
let root = old.dom_id.get().unwrap(); let root = old.id.get().unwrap();
// If the element type is completely different, the element needs to be re-rendered completely // If the element type is completely different, the element needs to be re-rendered completely
// This is an optimization React makes due to how users structure their code // This is an optimization React makes due to how users structure their code
// //
// This case is rather rare (typically only in non-keyed lists) // This case is rather rare (typically only in non-keyed lists)
if new.tag_name != old.tag_name || new.namespace != old.namespace { if new.tag != old.tag || new.namespace != old.namespace {
// maybe make this an instruction? // maybe make this an instruction?
// issue is that we need the "vnode" but this method only has the velement // issue is that we need the "vnode" but this method only has the velement
self.stack.push_nodes_created(0); self.stack.push_nodes_created(0);
@@ -551,8 +549,8 @@ impl<'bump> DiffState<'bump> {
self.scopes.update_node(new_node, root); self.scopes.update_node(new_node, root);
new.dom_id.set(Some(root)); new.id.set(Some(root));
new.parent_id.set(old.parent_id.get()); new.parent.set(old.parent.get());
// todo: attributes currently rely on the element on top of the stack, but in theory, we only need the id of the // todo: attributes currently rely on the element on top of the stack, but in theory, we only need the id of the
// element to modify its attributes. // element to modify its attributes.
@@ -1182,9 +1180,9 @@ impl<'bump> DiffState<'bump> {
loop { loop {
match &search_node.take().unwrap() { match &search_node.take().unwrap() {
VNode::Text(t) => break t.dom_id.get(), VNode::Text(t) => break t.id.get(),
VNode::Element(t) => break t.dom_id.get(), VNode::Element(t) => break t.id.get(),
VNode::Placeholder(t) => break t.dom_id.get(), VNode::Placeholder(t) => break t.id.get(),
VNode::Fragment(frag) => { VNode::Fragment(frag) => {
search_node = frag.children.last(); search_node = frag.children.last();
} }
@@ -1209,9 +1207,9 @@ impl<'bump> DiffState<'bump> {
let scope_id = el.scope.get().unwrap(); let scope_id = el.scope.get().unwrap();
search_node = Some(self.scopes.root_node(scope_id)); search_node = Some(self.scopes.root_node(scope_id));
} }
VNode::Text(t) => break t.dom_id.get(), VNode::Text(t) => break t.id.get(),
VNode::Element(t) => break t.dom_id.get(), VNode::Element(t) => break t.id.get(),
VNode::Placeholder(t) => break t.dom_id.get(), VNode::Placeholder(t) => break t.id.get(),
} }
} }
} }
@@ -1263,7 +1261,7 @@ impl<'bump> DiffState<'bump> {
match node { match node {
VNode::Text(t) => { VNode::Text(t) => {
// this check exists because our null node will be removed but does not have an ID // this check exists because our null node will be removed but does not have an ID
if let Some(id) = t.dom_id.get() { if let Some(id) = t.id.get() {
self.scopes.collect_garbage(id); self.scopes.collect_garbage(id);
if gen_muts { if gen_muts {
@@ -1272,7 +1270,7 @@ impl<'bump> DiffState<'bump> {
} }
} }
VNode::Placeholder(a) => { VNode::Placeholder(a) => {
let id = a.dom_id.get().unwrap(); let id = a.id.get().unwrap();
self.scopes.collect_garbage(id); self.scopes.collect_garbage(id);
if gen_muts { if gen_muts {
@@ -1280,7 +1278,7 @@ impl<'bump> DiffState<'bump> {
} }
} }
VNode::Element(e) => { VNode::Element(e) => {
let id = e.dom_id.get().unwrap(); let id = e.id.get().unwrap();
if gen_muts { if gen_muts {
self.mutations.remove(id.as_u64()); self.mutations.remove(id.as_u64());
-1
View File
@@ -16,7 +16,6 @@ pub(crate) mod innerlude {
pub use crate::mutations::*; pub use crate::mutations::*;
pub use crate::nodes::*; pub use crate::nodes::*;
pub use crate::scopes::*; pub use crate::scopes::*;
pub(crate) use crate::scopes::*;
pub use crate::virtual_dom::*; pub use crate::virtual_dom::*;
/// An [`Element`] is a possibly-none [`VNode`] created by calling `render` on [`Scope`] or [`ScopeState`]. /// An [`Element`] is a possibly-none [`VNode`] created by calling `render` on [`Scope`] or [`ScopeState`].
+27 -80
View File
@@ -141,9 +141,9 @@ impl<'src> VNode<'src> {
/// Returns None if the VNode is not mounted, or if the VNode cannot be presented by a mounted ID (Fragment/Component) /// Returns None if the VNode is not mounted, or if the VNode cannot be presented by a mounted ID (Fragment/Component)
pub fn try_mounted_id(&self) -> Option<ElementId> { pub fn try_mounted_id(&self) -> Option<ElementId> {
match &self { match &self {
VNode::Text(el) => el.dom_id.get(), VNode::Text(el) => el.id.get(),
VNode::Element(el) => el.dom_id.get(), VNode::Element(el) => el.id.get(),
VNode::Placeholder(el) => el.dom_id.get(), VNode::Placeholder(el) => el.id.get(),
VNode::Fragment(_) => None, VNode::Fragment(_) => None,
VNode::Component(_) => None, VNode::Component(_) => None,
} }
@@ -176,7 +176,7 @@ impl Debug for VNode<'_> {
match &self { match &self {
VNode::Element(el) => s VNode::Element(el) => s
.debug_struct("VNode::VElement") .debug_struct("VNode::VElement")
.field("name", &el.tag_name) .field("name", &el.tag)
.field("key", &el.key) .field("key", &el.key)
.field("attrs", &el.attributes) .field("attrs", &el.attributes)
.field("children", &el.children) .field("children", &el.children)
@@ -187,7 +187,6 @@ impl Debug for VNode<'_> {
write!(s, "VNode::VFragment {{ children: {:?} }}", frag.children) write!(s, "VNode::VFragment {{ children: {:?} }}", frag.children)
} }
VNode::Component(comp) => write!(s, "VNode::VComponent {{ fc: {:?}}}", comp.user_fc), VNode::Component(comp) => write!(s, "VNode::VComponent {{ fc: {:?}}}", comp.user_fc),
// VNode::Component(comp) => write!(s, "VNode::VComponent {{ fc: {:?}}}", comp.user_fc),
} }
} }
} }
@@ -216,13 +215,13 @@ fn empty_cell() -> Cell<Option<ElementId>> {
/// A placeholder node only generated when Fragments don't have any children. /// A placeholder node only generated when Fragments don't have any children.
pub struct VPlaceholder { pub struct VPlaceholder {
pub dom_id: Cell<Option<ElementId>>, pub id: Cell<Option<ElementId>>,
} }
/// A bump-allocated string slice and metadata. /// A bump-allocated string slice and metadata.
pub struct VText<'src> { pub struct VText<'src> {
pub text: &'src str, pub text: &'src str,
pub dom_id: Cell<Option<ElementId>>, pub id: Cell<Option<ElementId>>,
pub is_static: bool, pub is_static: bool,
} }
@@ -238,11 +237,11 @@ pub struct VFragment<'src> {
/// An element like a "div" with children, listeners, and attributes. /// An element like a "div" with children, listeners, and attributes.
pub struct VElement<'a> { pub struct VElement<'a> {
pub tag_name: &'static str, pub tag: &'static str,
pub namespace: Option<&'static str>, pub namespace: Option<&'static str>,
pub key: Option<&'a str>, pub key: Option<&'a str>,
pub dom_id: Cell<Option<ElementId>>, pub id: Cell<Option<ElementId>>,
pub parent_id: Cell<Option<ElementId>>, pub parent: Cell<Option<ElementId>>,
pub listeners: &'a [Listener<'a>], pub listeners: &'a [Listener<'a>],
pub attributes: &'a [Attribute<'a>], pub attributes: &'a [Attribute<'a>],
pub children: &'a [VNode<'a>], pub children: &'a [VNode<'a>],
@@ -251,11 +250,11 @@ pub struct VElement<'a> {
impl Debug for VElement<'_> { impl Debug for VElement<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("VElement") f.debug_struct("VElement")
.field("tag_name", &self.tag_name) .field("tag_name", &self.tag)
.field("namespace", &self.namespace) .field("namespace", &self.namespace)
.field("key", &self.key) .field("key", &self.key)
.field("dom_id", &self.dom_id) .field("id", &self.id)
.field("parent_id", &self.parent_id) .field("parent", &self.parent)
.field("listeners", &self.listeners.len()) .field("listeners", &self.listeners.len())
.field("attributes", &self.attributes) .field("attributes", &self.attributes)
.field("children", &self.children) .field("children", &self.children)
@@ -363,20 +362,13 @@ pub struct VComponent<'src> {
} }
pub(crate) struct VComponentProps<P> { pub(crate) struct VComponentProps<P> {
// Props start local
// If they are static, then they can get promoted onto the heap
pub render_fn: Component<P>, pub render_fn: Component<P>,
pub props: P,
pub memo: unsafe fn(&P, &P) -> bool, pub memo: unsafe fn(&P, &P) -> bool,
pub props: P,
} }
pub trait AnyProps { pub trait AnyProps {
fn as_ptr(&self) -> *const (); fn as_ptr(&self) -> *const ();
fn release(&self);
fn replace_heap(&self, new: Box<dyn Any>);
// move the props from the bump arena onto the heap
fn promote(&self);
fn render<'a>(&'a self, bump: &'a ScopeState) -> Element<'a>; fn render<'a>(&'a self, bump: &'a ScopeState) -> Element<'a>;
unsafe fn memoize(&self, other: &dyn AnyProps) -> bool; unsafe fn memoize(&self, other: &dyn AnyProps) -> bool;
} }
@@ -384,16 +376,9 @@ pub trait AnyProps {
impl<P> AnyProps for VComponentProps<P> { impl<P> AnyProps for VComponentProps<P> {
fn as_ptr(&self) -> *const () { fn as_ptr(&self) -> *const () {
&self.props as *const _ as *const () &self.props as *const _ as *const ()
// // todo: maybe move this into an enum
// let heap_props = self.heap_props.borrow();
// if let Some(b) = heap_props.as_ref() {
// b.as_ref() as *const _ as *const ()
// } else {
// let local_props = self.local_props.borrow();
// local_props.as_ref().unwrap() as *const _ as *const ()
// }
} }
// Safety:
// this will downcat the other ptr as our swallowed type! // this will downcat the other ptr as our swallowed type!
// you *must* make this check *before* calling this method // 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) // if your functions are not the same, then you will downcast a pointer into a different type (UB)
@@ -403,41 +388,9 @@ impl<P> AnyProps for VComponentProps<P> {
(self.memo)(real_us, real_other) (self.memo)(real_us, real_other)
} }
fn release(&self) {
panic!("don't release props anymore");
// if let Some(heap_props) = self.heap_props.borrow_mut().take() {
// dbg!("releasing heap");
// drop(heap_props)
// } else if let Some(local_props) = self.local_props.borrow_mut().take() {
// dbg!("releasing local");
// drop(local_props)
// } else {
// dbg!("trying to do a double release");
// }
}
fn promote(&self) {
panic!("don't promote props anymore");
// dbg!("promoting props");
// if let Some(props) = self.local_props.borrow_mut().take() {
// let mut heap_slot = self.heap_props.borrow_mut();
// *heap_slot = Some(Box::new(props));
// }
}
fn render<'a>(&'a self, scope: &'a ScopeState) -> Element<'a> { fn render<'a>(&'a self, scope: &'a ScopeState) -> Element<'a> {
let props: &P = &self.props; let props = unsafe { std::mem::transmute::<&P, &P>(&self.props) };
let inline_props = unsafe { std::mem::transmute::<&P, &P>(props) }; (self.render_fn)(Scope { scope, props })
(self.render_fn)(Scope {
scope,
props: inline_props,
})
}
fn replace_heap(&self, new: Box<dyn Any>) {
// let new = new.downcast::<P>().unwrap();
// self.heap_props.borrow_mut().replace(new);
} }
} }
@@ -463,7 +416,7 @@ impl<'a> NodeFactory<'a> {
/// Directly pass in text blocks without the need to use the format_args macro. /// Directly pass in text blocks without the need to use the format_args macro.
pub fn static_text(&self, text: &'static str) -> VNode<'a> { pub fn static_text(&self, text: &'static str) -> VNode<'a> {
VNode::Text(self.bump.alloc(VText { VNode::Text(self.bump.alloc(VText {
dom_id: empty_cell(), id: empty_cell(),
text, text,
is_static: true, is_static: true,
})) }))
@@ -492,7 +445,7 @@ impl<'a> NodeFactory<'a> {
VNode::Text(self.bump.alloc(VText { VNode::Text(self.bump.alloc(VText {
text, text,
is_static, is_static,
dom_id: empty_cell(), id: empty_cell(),
})) }))
} }
@@ -545,14 +498,14 @@ impl<'a> NodeFactory<'a> {
let key = key.map(|f| self.raw_text(f).0); let key = key.map(|f| self.raw_text(f).0);
VNode::Element(self.bump.alloc(VElement { VNode::Element(self.bump.alloc(VElement {
tag_name, tag: tag_name,
key, key,
namespace, namespace,
listeners, listeners,
attributes, attributes,
children, children,
dom_id: empty_cell(), id: empty_cell(),
parent_id: empty_cell(), parent: empty_cell(),
})) }))
} }
@@ -621,9 +574,7 @@ impl<'a> NodeFactory<'a> {
} }
if nodes.is_empty() { if nodes.is_empty() {
VNode::Placeholder(self.bump.alloc(VPlaceholder { VNode::Placeholder(self.bump.alloc(VPlaceholder { id: empty_cell() }))
dom_id: empty_cell(),
}))
} else { } else {
VNode::Fragment(VFragment { VNode::Fragment(VFragment {
children: nodes.into_bump_slice(), children: nodes.into_bump_slice(),
@@ -643,9 +594,7 @@ impl<'a> NodeFactory<'a> {
} }
if nodes.is_empty() { if nodes.is_empty() {
VNode::Placeholder(self.bump.alloc(VPlaceholder { VNode::Placeholder(self.bump.alloc(VPlaceholder { id: empty_cell() }))
dom_id: empty_cell(),
}))
} else { } else {
let children = nodes.into_bump_slice(); let children = nodes.into_bump_slice();
@@ -686,9 +635,9 @@ impl<'a> NodeFactory<'a> {
} }
if nodes.is_empty() { if nodes.is_empty() {
Some(VNode::Placeholder(self.bump.alloc(VPlaceholder { Some(VNode::Placeholder(
dom_id: empty_cell(), self.bump.alloc(VPlaceholder { id: empty_cell() }),
}))) ))
} else { } else {
let children = nodes.into_bump_slice(); let children = nodes.into_bump_slice();
@@ -766,9 +715,7 @@ impl<'a> IntoVNode<'a> for Option<LazyNodes<'a, '_>> {
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> { fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
match self { match self {
Some(lazy) => lazy.call(cx), Some(lazy) => lazy.call(cx),
None => VNode::Placeholder(cx.bump.alloc(VPlaceholder { None => VNode::Placeholder(cx.bump.alloc(VPlaceholder { id: empty_cell() })),
dom_id: empty_cell(),
})),
} }
} }
} }
+7 -7
View File
@@ -44,11 +44,11 @@ impl ScopeArena {
// this will *never* show up in the diffing process // this will *never* show up in the diffing process
// todo: figure out why this is necessary. i forgot. whoops. // todo: figure out why this is necessary. i forgot. whoops.
let el = bump.alloc(VElement { let el = bump.alloc(VElement {
tag_name: "root", tag: "root",
namespace: None, namespace: None,
key: None, key: None,
dom_id: Cell::new(Some(ElementId(0))), id: Cell::new(Some(ElementId(0))),
parent_id: Default::default(), parent: Default::default(),
listeners: &[], listeners: &[],
attributes: &[], attributes: &[],
children: &[], children: &[],
@@ -279,7 +279,7 @@ impl ScopeArena {
let node = frame let node = frame
.bump .bump
.alloc(VNode::Placeholder(frame.bump.alloc(VPlaceholder { .alloc(VNode::Placeholder(frame.bump.alloc(VPlaceholder {
dom_id: Default::default(), id: Default::default(),
}))); })));
frame.node.set(unsafe { extend_vnode(node) }); frame.node.set(unsafe { extend_vnode(node) });
} }
@@ -310,7 +310,7 @@ impl ScopeArena {
} }
} }
cur_el = real_el.parent_id.get(); cur_el = real_el.parent.get();
} }
} }
} }
@@ -869,7 +869,7 @@ impl BumpFrame {
let node = &*bump.alloc(VText { let node = &*bump.alloc(VText {
text: "placeholdertext", text: "placeholdertext",
dom_id: Default::default(), id: Default::default(),
is_static: false, is_static: false,
}); });
let node = bump.alloc(VNode::Text(unsafe { std::mem::transmute(node) })); let node = bump.alloc(VNode::Text(unsafe { std::mem::transmute(node) }));
@@ -881,7 +881,7 @@ impl BumpFrame {
self.bump.reset(); self.bump.reset();
let node = self.bump.alloc(VText { let node = self.bump.alloc(VText {
text: "placeholdertext", text: "placeholdertext",
dom_id: Default::default(), id: Default::default(),
is_static: false, is_static: false,
}); });
let node = self let node = self
+8 -9
View File
@@ -109,14 +109,14 @@ fn components_generate() {
*render_phase += 1; *render_phase += 1;
cx.render(match *render_phase { cx.render(match *render_phase {
0 => rsx!("Text0"), 1 => rsx!("Text0"),
1 => rsx!(div {}), 2 => rsx!(div {}),
2 => rsx!("Text2"), 3 => rsx!("Text2"),
3 => rsx!(Child {}), 4 => rsx!(Child {}),
4 => rsx!({ None as Option<()> }), 5 => rsx!({ None as Option<()> }),
5 => rsx!("text 3"), 6 => rsx!("text 3"),
6 => rsx!({ (0..2).map(|f| rsx!("text {f}")) }), 7 => rsx!({ (0..2).map(|f| rsx!("text {f}")) }),
7 => rsx!(Child {}), 8 => rsx!(Child {}),
_ => todo!(), _ => todo!(),
}) })
}; };
@@ -220,7 +220,6 @@ fn components_generate() {
#[test] #[test]
fn component_swap() { fn component_swap() {
// simple_logger::init();
static App: Component<()> = |cx| { static App: Component<()> = |cx| {
let render_phase = cx.use_hook(|_| 0, |f| f); let render_phase = cx.use_hook(|_| 0, |f| f);
*render_phase += 1; *render_phase += 1;
+1 -1
View File
@@ -132,7 +132,7 @@ impl DesktopController {
runtime.block_on(async move { runtime.block_on(async move {
// LocalSet::new().block_on(&runtime, async move { // LocalSet::new().block_on(&runtime, async move {
let mut dom = let mut dom =
VirtualDom::new_with_props_and_scheduler(root, props, sender, receiver); VirtualDom::new_with_props_and_scheduler(root, props, (sender, receiver));
let edits = dom.rebuild(); let edits = dom.rebuild();
+2 -2
View File
@@ -168,7 +168,7 @@ impl<'a> TextRenderer<'a, '_> {
} }
} }
write!(f, "<{}", el.tag_name)?; write!(f, "<{}", el.tag)?;
let mut inner_html = None; let mut inner_html = None;
let mut attr_iter = el.attributes.iter().peekable(); let mut attr_iter = el.attributes.iter().peekable();
@@ -233,7 +233,7 @@ impl<'a> TextRenderer<'a, '_> {
} }
} }
write!(f, "</{}>", el.tag_name)?; write!(f, "</{}>", el.tag)?;
if self.cfg.newline { if self.cfg.newline {
writeln!(f)?; writeln!(f)?;
} }