chore: get create working and simplify dynamic nodes

This commit is contained in:
Jonathan Kelley committed 2022-11-30 11:24:13 -05:00
1 parent 16a521a601
commit 3c19def550
16 files changed
+168 -173

No files matched your search

+2 -2
View File
@@ -1,6 +1,6 @@
use crate::{
factory::RenderReturn, nodes::VNode, virtual_dom::VirtualDom, AttributeValue, DynamicNode,
ScopeId, VFragment,
ScopeId,
};
use bumpalo::boxed::Box as BumpBox;
@@ -101,7 +101,7 @@ impl VirtualDom {
for (idx, _) in node.template.roots.iter().enumerate() {
match node.dynamic_root(idx) {
Some(DynamicNode::Component(c)) => self.drop_scope(c.scope.get().unwrap()),
Some(DynamicNode::Fragment(VFragment::NonEmpty(nodes))) => {
Some(DynamicNode::Fragment(nodes)) => {
for node in *nodes {
self.drop_scope_inner(node);
}
+24 -26
View File
@@ -1,11 +1,13 @@
use std::cell::Cell;
use crate::factory::RenderReturn;
use crate::innerlude::{VComponent, VFragment, VText};
use crate::innerlude::{VComponent, VText};
use crate::mutations::Mutation;
use crate::mutations::Mutation::*;
use crate::nodes::VNode;
use crate::nodes::{DynamicNode, TemplateNode};
use crate::virtual_dom::VirtualDom;
use crate::{AttributeValue, ScopeId, SuspenseContext, TemplateAttribute};
use crate::{AttributeValue, ElementId, ScopeId, SuspenseContext, TemplateAttribute};
impl<'b> VirtualDom {
/// Create a new template [`VNode`] and write it to the [`Mutations`] buffer.
@@ -55,15 +57,14 @@ impl<'b> VirtualDom {
1
}
DynamicNode::Fragment(VFragment::Empty(slot)) => {
DynamicNode::Placeholder(slot) => {
let id = self.next_element(template, template.template.node_paths[*id]);
slot.set(id);
self.mutations.push(CreatePlaceholder { id });
1
}
DynamicNode::Fragment(VFragment::NonEmpty(_))
| DynamicNode::Component { .. } => {
DynamicNode::Fragment(_) | DynamicNode::Component { .. } => {
self.create_dynamic_node(template, &template.dynamic_nodes[*id], *id)
}
}
@@ -309,7 +310,8 @@ impl<'b> VirtualDom {
use DynamicNode::*;
match node {
Text(text) => self.create_dynamic_text(template, text, idx),
Fragment(frag) => self.create_fragment(frag, template, idx),
Fragment(frag) => self.create_fragment(frag),
Placeholder(frag) => self.create_placeholder(frag, template, idx),
Component(component) => self.create_component_node(template, component, idx),
}
}
@@ -340,34 +342,30 @@ impl<'b> VirtualDom {
0
}
pub(crate) fn create_fragment(
pub(crate) fn create_placeholder(
&mut self,
frag: &'b VFragment<'b>,
slot: &Cell<ElementId>,
template: &'b VNode<'b>,
idx: usize,
) -> usize {
match frag {
VFragment::NonEmpty(nodes) => {
nodes.iter().fold(0, |acc, child| acc + self.create(child))
}
// Allocate a dynamic element reference for this text node
let id = self.next_element(template, template.template.node_paths[idx]);
VFragment::Empty(slot) => {
// Allocate a dynamic element reference for this text node
let id = self.next_element(template, template.template.node_paths[idx]);
// Make sure the text node is assigned to the correct element
slot.set(id);
// Make sure the text node is assigned to the correct element
slot.set(id);
// Assign the ID to the existing node in the template
self.mutations.push(AssignId {
path: &template.template.node_paths[idx][1..],
id,
});
// Assign the ID to the existing node in the template
self.mutations.push(AssignId {
path: &template.template.node_paths[idx][1..],
id,
});
// Since the placeholder is already in the DOM, we don't create any new nodes
0
}
// Since the placeholder is already in the DOM, we don't create any new nodes
0
}
}
pub(crate) fn create_fragment(&mut self, nodes: &'b [VNode<'b>]) -> usize {
nodes.iter().fold(0, |acc, child| acc + self.create(child))
}
pub(super) fn create_component_node(
+17 -54
View File
@@ -1,7 +1,7 @@
use crate::{
arena::ElementId,
factory::RenderReturn,
innerlude::{DirtyScope, VComponent, VFragment, VText},
innerlude::{DirtyScope, VComponent, VText},
mutations::Mutation,
nodes::{DynamicNode, VNode},
scopes::ScopeId,
@@ -10,7 +10,6 @@ use crate::{
};
use fxhash::{FxHashMap, FxHashSet};
use std::cell::Cell;
use DynamicNode::*;
impl<'b> VirtualDom {
@@ -101,7 +100,7 @@ impl<'b> VirtualDom {
{
match (left_node, right_node) {
(Text(left), Text(right)) => self.diff_vtext(left, right),
(Fragment(left), Fragment(right)) => self.diff_vfragment(left, right),
(Fragment(left), Fragment(right)) => self.diff_non_empty_fragment(left, right),
(Component(left), Component(right)) => {
self.diff_vcomponent(left, right, right_template, idx)
}
@@ -231,40 +230,6 @@ impl<'b> VirtualDom {
}
}
fn diff_vfragment(&mut self, left: &'b VFragment<'b>, right: &'b VFragment<'b>) {
use VFragment::*;
match (left, right) {
(Empty(l), Empty(r)) => r.set(l.get()),
(Empty(l), NonEmpty(r)) => self.replace_placeholder_with_nodes(l, r),
(NonEmpty(l), Empty(r)) => self.replace_nodes_with_placeholder(l, r),
(NonEmpty(old), NonEmpty(new)) => self.diff_non_empty_fragment(new, old),
}
}
fn replace_placeholder_with_nodes(&mut self, l: &'b Cell<ElementId>, r: &'b [VNode<'b>]) {
let m = self.create_children(r);
let id = l.get();
self.mutations.push(Mutation::ReplaceWith { id, m });
self.reclaim(id);
}
fn replace_nodes_with_placeholder(&mut self, l: &'b [VNode<'b>], r: &'b Cell<ElementId>) {
// Create the placeholder first, ensuring we get a dedicated ID for the placeholder
let placeholder = self.next_element(&l[0], &[]);
r.set(placeholder);
self.mutations
.push(Mutation::CreatePlaceholder { id: placeholder });
// Remove the old nodes, except for onea
let first = self.replace_inner(&l[0]);
self.remove_nodes(&l[1..]);
self.mutations
.push(Mutation::ReplaceWith { id: first, m: 1 });
self.try_reclaim(first);
}
/// Remove all the top-level nodes, returning the firstmost root ElementId
///
/// All IDs will be garbage collected
@@ -272,8 +237,8 @@ impl<'b> VirtualDom {
let id = match node.dynamic_root(0) {
None => node.root_ids[0].get(),
Some(Text(t)) => t.id.get(),
Some(Fragment(VFragment::Empty(e))) => e.get(),
Some(Fragment(VFragment::NonEmpty(nodes))) => {
Some(Placeholder(e)) => e.get(),
Some(Fragment(nodes)) => {
let id = self.replace_inner(&nodes[0]);
self.remove_nodes(&nodes[1..]);
id
@@ -317,10 +282,8 @@ impl<'b> VirtualDom {
};
}
Text(t) => self.reclaim(t.id.get()),
Fragment(VFragment::Empty(t)) => self.reclaim(t.get()),
Fragment(VFragment::NonEmpty(nodes)) => {
nodes.iter().for_each(|node| self.clean_up_node(node))
}
Placeholder(t) => self.reclaim(t.get()),
Fragment(nodes) => nodes.iter().for_each(|node| self.clean_up_node(node)),
};
}
@@ -351,12 +314,12 @@ impl<'b> VirtualDom {
self.mutations.push(Mutation::Remove { id });
self.reclaim(id);
}
Some(Fragment(VFragment::Empty(e))) => {
Some(Placeholder(e)) => {
let id = e.get();
self.mutations.push(Mutation::Remove { id });
self.reclaim(id);
}
Some(Fragment(VFragment::NonEmpty(nodes))) => self.remove_nodes(nodes),
Some(Fragment(nodes)) => self.remove_nodes(nodes),
Some(Component(comp)) => {
let scope = comp.scope.get().unwrap();
match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } {
@@ -750,8 +713,8 @@ impl<'b> VirtualDom {
for (idx, _) in node.template.roots.iter().enumerate() {
let id = match node.dynamic_root(idx) {
Some(Text(t)) => t.id.get(),
Some(Fragment(VFragment::Empty(t))) => t.get(),
Some(Fragment(VFragment::NonEmpty(t))) => return self.remove_nodes(t),
Some(Placeholder(t)) => t.get(),
Some(Fragment(t)) => return self.remove_nodes(t),
Some(Component(comp)) => return self.remove_component(comp.scope.get().unwrap()),
None => node.root_ids[idx].get(),
};
@@ -793,12 +756,12 @@ impl<'b> VirtualDom {
self.mutations.push(Mutation::PushRoot { id: t.id.get() });
onstack += 1;
}
Some(Fragment(VFragment::Empty(t))) => {
Some(Placeholder(t)) => {
self.mutations.push(Mutation::PushRoot { id: t.get() });
onstack += 1;
}
Some(Fragment(VFragment::NonEmpty(t))) => {
for node in *t {
Some(Fragment(nodes)) => {
for node in *nodes {
onstack += self.push_all_real_nodes(node);
}
}
@@ -842,8 +805,8 @@ impl<'b> VirtualDom {
match node.dynamic_root(0) {
None => node.root_ids[0].get(),
Some(Text(t)) => t.id.get(),
Some(Fragment(VFragment::NonEmpty(t))) => self.find_first_element(&t[0]),
Some(Fragment(VFragment::Empty(t))) => t.get(),
Some(Fragment(t)) => self.find_first_element(&t[0]),
Some(Placeholder(t)) => t.get(),
Some(Component(comp)) => {
let scope = comp.scope.get().unwrap();
match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } {
@@ -858,8 +821,8 @@ impl<'b> VirtualDom {
match node.dynamic_root(node.template.roots.len() - 1) {
None => node.root_ids.last().unwrap().get(),
Some(Text(t)) => t.id.get(),
Some(Fragment(VFragment::NonEmpty(t))) => self.find_last_element(t.last().unwrap()),
Some(Fragment(VFragment::Empty(t))) => t.get(),
Some(Fragment(t)) => self.find_last_element(t.last().unwrap()),
Some(Placeholder(t)) => t.get(),
Some(Component(comp)) => {
let scope = comp.scope.get().unwrap();
match unsafe { self.scopes[scope.0].root_node().extend_lifetime_ref() } {
+18 -10
View File
@@ -10,7 +10,7 @@ use std::future::Future;
use crate::{
any_props::{AnyProps, VProps},
arena::ElementId,
innerlude::{DynamicNode, EventHandler, VComponent, VFragment, VText},
innerlude::{DynamicNode, EventHandler, VComponent, VText},
Attribute, AttributeValue, Element, LazyNodes, Properties, Scope, ScopeState, VNode,
};
@@ -148,12 +148,20 @@ pub trait IntoDynNode<'a, A = ()> {
impl<'a> IntoDynNode<'a> for () {
fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> {
DynamicNode::Fragment(VFragment::Empty(Cell::new(ElementId(0))))
DynamicNode::placeholder()
}
}
impl<'a> IntoDynNode<'a> for VNode<'a> {
fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> {
DynamicNode::Fragment(VFragment::NonEmpty(_cx.bump().alloc([self])))
DynamicNode::Fragment(_cx.bump().alloc([self]))
}
}
impl<'a> IntoDynNode<'a> for Element<'a> {
fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> {
match self {
Ok(val) => val.into_vnode(_cx),
_ => DynamicNode::placeholder(),
}
}
}
@@ -161,7 +169,7 @@ impl<'a, T: IntoDynNode<'a>> IntoDynNode<'a> for Option<T> {
fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> {
match self {
Some(val) => val.into_vnode(_cx),
None => DynamicNode::Fragment(VFragment::Empty(Cell::new(ElementId(0)))),
None => DynamicNode::placeholder(),
}
}
}
@@ -170,14 +178,14 @@ impl<'a> IntoDynNode<'a> for &Element<'a> {
fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> {
match self.as_ref() {
Ok(val) => val.clone().into_vnode(_cx),
_ => DynamicNode::Fragment(VFragment::Empty(Cell::new(ElementId(0)))),
_ => DynamicNode::placeholder(),
}
}
}
impl<'a, 'b> IntoDynNode<'a> for LazyNodes<'a, 'b> {
fn into_vnode(self, cx: &'a ScopeState) -> DynamicNode<'a> {
DynamicNode::Fragment(VFragment::NonEmpty(cx.bump().alloc([self.call(cx)])))
DynamicNode::Fragment(cx.bump().alloc([self.call(cx)]))
}
}
@@ -201,14 +209,14 @@ impl<'b> IntoDynNode<'b> for Arguments<'_> {
impl<'a> IntoDynNode<'a> for &'a VNode<'a> {
fn into_vnode(self, _cx: &'a ScopeState) -> DynamicNode<'a> {
DynamicNode::Fragment(VFragment::NonEmpty(_cx.bump().alloc([VNode {
DynamicNode::Fragment(_cx.bump().alloc([VNode {
parent: self.parent,
template: self.template,
root_ids: self.root_ids,
key: self.key,
dynamic_nodes: self.dynamic_nodes,
dynamic_attrs: self.dynamic_attrs,
}])))
}]))
}
}
@@ -243,8 +251,8 @@ where
let children = nodes.into_bump_slice();
match children.len() {
0 => DynamicNode::Fragment(VFragment::Empty(Cell::new(ElementId(0)))),
_ => DynamicNode::Fragment(VFragment::NonEmpty(children)),
0 => DynamicNode::placeholder(),
_ => DynamicNode::Fragment(children),
}
}
}
+2 -1
View File
@@ -24,6 +24,7 @@ pub(crate) mod innerlude {
pub use crate::dirty_scope::*;
pub use crate::error_boundary::*;
pub use crate::events::*;
pub use crate::factory::RenderReturn;
pub use crate::fragment::*;
pub use crate::lazynodes::*;
pub use crate::mutations::*;
@@ -87,6 +88,7 @@ pub use crate::innerlude::{
Mutations,
NodeFactory,
Properties,
RenderReturn,
Scope,
ScopeId,
ScopeState,
@@ -99,7 +101,6 @@ pub use crate::innerlude::{
TemplateNode,
UiEvent,
VComponent,
VFragment,
VNode,
VText,
VirtualDom,
-4
View File
@@ -150,10 +150,6 @@ pub enum Mutation<'a> {
id: ElementId,
},
SetInnerText {
value: &'a str,
},
SetText {
value: &'a str,
id: ElementId,
+5 -7
View File
@@ -89,13 +89,17 @@ pub enum TemplateNode<'a> {
pub enum DynamicNode<'a> {
Component(VComponent<'a>),
Text(VText<'a>),
Fragment(VFragment<'a>),
Placeholder(Cell<ElementId>),
Fragment(&'a [VNode<'a>]),
}
impl<'a> DynamicNode<'a> {
pub fn is_component(&self) -> bool {
matches!(self, DynamicNode::Component(_))
}
pub fn placeholder() -> Self {
Self::Placeholder(Cell::new(ElementId(0)))
}
}
pub struct VComponent<'a> {
@@ -122,12 +126,6 @@ pub struct VText<'a> {
pub value: &'a str,
}
#[derive(Debug)]
pub enum VFragment<'a> {
Empty(Cell<ElementId>),
NonEmpty(&'a [VNode<'a>]),
}
#[derive(Debug)]
pub enum TemplateAttribute<'a> {
Static {
+2 -2
View File
@@ -7,7 +7,7 @@ use crate::{
scheduler::RcWake,
scopes::{ScopeId, ScopeState},
virtual_dom::VirtualDom,
AttributeValue, DynamicNode, VFragment, VNode,
AttributeValue, DynamicNode, VNode,
};
use futures_util::FutureExt;
use std::{
@@ -75,7 +75,7 @@ impl VirtualDom {
c.props.set(None);
}
}
DynamicNode::Fragment(VFragment::NonEmpty(f)) => {
DynamicNode::Fragment(f) => {
for node in *f {
self.ensure_drop_safety_inner(node);
}