wip: remove old create

This commit is contained in:
Jonathan Kelley 2021-08-20 10:44:58 -04:00
parent 64f289a61c
commit 7b068202ce

View file

@ -103,6 +103,11 @@ pub struct DiffMachine<'bump> {
pub seen_scopes: FxHashSet<ScopeId>,
}
/// The stack instructions we use to diff and create new nodes.
///
/// Right now, we insert an instruction for every child node we want to create and diff. This can be less efficient than
/// a custom iterator type - but this is current easier to implement. In the future, let's try interact with the stack less.
pub enum DiffInstruction<'a> {
DiffNode {
old: &'a VNode<'a>,
@ -111,6 +116,7 @@ pub enum DiffInstruction<'a> {
},
Append {},
Replace {
with: usize,
},
@ -189,76 +195,14 @@ impl<'bump> DiffMachine<'bump> {
}
DiffInstruction::Create { node, .. } => {
// defer to individual functions so the compiler produces better code
// large functions tend to be difficult for the compiler to work with
match &node {
VNode::Text(text) => {
let real_id = self.vdom.reserve_node();
self.edit_create_text_node(text.text, real_id);
text.dom_id.set(Some(real_id));
*self.nodes_created_stack.last_mut().unwrap() += 1;
}
VNode::Suspended(suspended) => {
let real_id = self.vdom.reserve_node();
self.edit_create_placeholder(real_id);
suspended.node.set(Some(real_id));
*self.nodes_created_stack.last_mut().unwrap() += 1;
}
VNode::Anchor(anchor) => {
let real_id = self.vdom.reserve_node();
self.edit_create_placeholder(real_id);
anchor.dom_id.set(Some(real_id));
*self.nodes_created_stack.last_mut().unwrap() += 1;
}
VNode::Element(el) => {
let VElement {
tag_name,
listeners,
attributes,
children,
namespace,
static_attrs: _,
static_children: _,
static_listeners: _,
dom_id,
key,
} = el;
let real_id = self.vdom.reserve_node();
self.edit_create_element(tag_name, *namespace, real_id);
dom_id.set(Some(real_id));
let cur_scope = self.current_scope().unwrap();
listeners.iter().for_each(|listener| {
self.fix_listener(listener);
listener.mounted_node.set(Some(real_id));
self.edit_new_event_listener(listener, cur_scope.clone());
// if the node has an event listener, then it must be visited ?
});
for attr in *attributes {
self.edit_set_attribute(attr);
}
// TODO: the append child edit
*self.nodes_created_stack.last_mut().unwrap() += 1;
// push every child onto the stack
self.nodes_created_stack.push(0);
for child in *children {
self.node_stack
.push(DiffInstruction::Create { node: child })
}
}
VNode::Fragment(frag) => {
for node in frag.children {
self.node_stack.push(DiffInstruction::Create { node })
}
}
VNode::Text(vtext) => self.create_text_node(vtext),
VNode::Suspended(suspended) => self.create_suspended_node(suspended),
VNode::Anchor(anchor) => self.create_anchor_node(anchor),
VNode::Element(element) => self.create_element_node(element),
VNode::Fragment(frag) => self.create_fragment_node(frag),
VNode::Component(_) => {
//
}
@ -270,44 +214,142 @@ impl<'bump> DiffMachine<'bump> {
Ok(())
}
fn create_text_node(&mut self) {}
fn create_text_node(&mut self, vtext: &'bump VText<'bump>) {
let real_id = self.vdom.reserve_node();
self.edit_create_text_node(vtext.text, real_id);
vtext.dom_id.set(Some(real_id));
*self.nodes_created_stack.last_mut().unwrap() += 1;
}
/// Create the new node, pushing instructions on our instruction stack to create any further children
///
///
pub fn create_iterative(&mut self, node: &'bump VNode<'bump>) {
match &node {
// singles
// update the parent
VNode::Text(text) => {
let real_id = self.vdom.reserve_node();
self.edit_create_text_node(text.text, real_id);
text.dom_id.set(Some(real_id));
*self.nodes_created_stack.last_mut().unwrap() += 1;
}
VNode::Suspended(suspended) => {
let real_id = self.vdom.reserve_node();
self.edit_create_placeholder(real_id);
suspended.node.set(Some(real_id));
*self.nodes_created_stack.last_mut().unwrap() += 1;
}
VNode::Anchor(anchor) => {
let real_id = self.vdom.reserve_node();
self.edit_create_placeholder(real_id);
anchor.dom_id.set(Some(real_id));
*self.nodes_created_stack.last_mut().unwrap() += 1;
}
fn create_suspended_node(&mut self, suspended: &'bump VSuspended) {
let real_id = self.vdom.reserve_node();
self.edit_create_placeholder(real_id);
suspended.node.set(Some(real_id));
*self.nodes_created_stack.last_mut().unwrap() += 1;
}
VNode::Element(el) => {
//
fn create_anchor_node(&mut self, anchor: &'bump VAnchor) {
let real_id = self.vdom.reserve_node();
self.edit_create_placeholder(real_id);
anchor.dom_id.set(Some(real_id));
*self.nodes_created_stack.last_mut().unwrap() += 1;
}
fn create_element_node(&mut self, element: &'bump VElement<'bump>) {
let VElement {
tag_name,
listeners,
attributes,
children,
namespace,
static_attrs: _,
static_children: _,
static_listeners: _,
dom_id,
key,
} = element;
let real_id = self.vdom.reserve_node();
self.edit_create_element(tag_name, *namespace, real_id);
dom_id.set(Some(real_id));
let cur_scope = self.current_scope().unwrap();
listeners.iter().for_each(|listener| {
self.fix_listener(listener);
listener.mounted_node.set(Some(real_id));
self.edit_new_event_listener(listener, cur_scope.clone());
// if the node has an event listener, then it must be visited ?
});
for attr in *attributes {
self.edit_set_attribute(attr);
}
// TODO: the append child edit
*self.nodes_created_stack.last_mut().unwrap() += 1;
// push every child onto the stack
self.nodes_created_stack.push(0);
for child in *children {
self.node_stack
.push(DiffInstruction::Create { node: child })
}
}
fn create_fragment_node(&mut self, frag: &'bump VFragment<'bump>) {
for node in frag.children {
self.node_stack.push(DiffInstruction::Create { node })
}
}
fn create_component_node(&mut self, vcomponent: &'bump VComponent<'bump>) {
let caller = vcomponent.caller.clone();
let parent_idx = self.scope_stack.last().unwrap().clone();
// Insert a new scope into our component list
let new_idx = self.vdom.insert_scope_with_key(|new_idx| {
let parent_scope = self.get_scope(&parent_idx).unwrap();
let height = parent_scope.height + 1;
Scope::new(
caller,
new_idx,
Some(parent_idx),
height,
ScopeChildren(vcomponent.children),
self.vdom.clone(),
)
});
// Actually initialize the caller's slot with the right address
vcomponent.ass_scope.set(Some(new_idx));
if !vcomponent.can_memoize {
let cur_scope = self.get_scope_mut(&parent_idx).unwrap();
let extended = vcomponent as *const VComponent;
let extended: *const VComponent<'static> = unsafe { std::mem::transmute(extended) };
cur_scope.borrowed_props.borrow_mut().push(extended);
}
// TODO:
// add noderefs to current noderef list Noderefs
// add effects to current effect list Effects
let new_component = self.get_scope_mut(&new_idx).unwrap();
// Run the scope for one iteration to initialize it
match new_component.run_scope() {
Ok(_) => {
// all good, new nodes exist
}
VNode::Fragment(frag) => {
//
}
VNode::Component(comp) => {
//
Err(err) => {
// failed to run. this is the first time the component ran, and it failed
// we manually set its head node to an empty fragment
panic!("failing components not yet implemented");
}
}
// Take the node that was just generated from running the component
let nextnode = new_component.frames.fin_head();
// Push the new scope onto the stack
self.scope_stack.push(new_idx);
// Run the creation algorithm with this scope on the stack
let meta = self.create_vnode(nextnode);
// pop the scope off the stack
self.scope_stack.pop();
if meta.added_to_stack == 0 {
panic!("Components should *always* generate nodes - even if they fail");
}
// Finally, insert this scope as a seen node.
self.seen_scopes.insert(new_idx);
}
pub fn diff_iterative(&mut self, old_node: &'bump VNode<'bump>, new_node: &'bump VNode<'bump>) {
@ -734,184 +776,6 @@ impl<'bump> DiffMachine<'bump> {
}
}
// Emit instructions to create the given virtual node.
//
// The change list stack may have any shape upon entering this function:
//
// [...]
//
// When this function returns, the new node is on top of the change list stack:
//
// [... node]
pub fn create_vnode(&mut self, node: &'bump VNode<'bump>) -> CreateMeta {
match &node {
VNode::Text(text) => {
let real_id = self.vdom.reserve_node();
self.edit_create_text_node(text.text, real_id);
text.dom_id.set(Some(real_id));
CreateMeta::new(text.is_static, 1)
}
VNode::Anchor(anchor) => {
let real_id = self.vdom.reserve_node();
self.edit_create_placeholder(real_id);
anchor.dom_id.set(Some(real_id));
CreateMeta::new(false, 1)
}
VNode::Element(el) => {
// we have the potential to completely eliminate working on this node in the future(!)
//
// This can only be done if all of the elements properties (attrs, children, listeners, etc) are static
// While creating these things, keep track if we can memoize this element.
// At the end, we'll set this flag on the element to skip it
let mut is_static: bool = true;
let VElement {
tag_name,
listeners,
attributes,
children,
namespace,
static_attrs: _,
static_children: _,
static_listeners: _,
dom_id,
key,
} = el;
let real_id = self.vdom.reserve_node();
self.edit_create_element(tag_name, *namespace, real_id);
dom_id.set(Some(real_id));
let cur_scope = self.current_scope().unwrap();
listeners.iter().for_each(|listener| {
self.fix_listener(listener);
listener.mounted_node.set(Some(real_id));
self.edit_new_event_listener(listener, cur_scope.clone());
// if the node has an event listener, then it must be visited ?
is_static = false;
});
for attr in *attributes {
is_static = is_static && attr.is_static;
self.edit_set_attribute(attr);
}
// Fast path: if there is a single text child, it is faster to
// create-and-append the text node all at once via setting the
// parent's `textContent` in a single change list instruction than
// to emit three instructions to (1) create a text node, (2) set its
// text content, and finally (3) append the text node to this
// parent.
//
// Notice: this is a web-specific optimization and may be changed in the future
//
// TODO move over
// if children.len() == 1 {
// if let VNodeKind::Text(text) = &children[0] {
// self.set_text(text.text);
// return CreateMeta::new(is_static, 1);
// }
// }
for child in *children {
let child_meta = self.create_vnode(child);
is_static = is_static && child_meta.is_static;
// append whatever children were generated by this call
self.edit_append_children(child_meta.added_to_stack);
}
CreateMeta::new(is_static, 1)
}
VNode::Component(vcomponent) => {
let caller = vcomponent.caller.clone();
let parent_idx = self.scope_stack.last().unwrap().clone();
// Insert a new scope into our component list
let new_idx = self.vdom.insert_scope_with_key(|new_idx| {
let parent_scope = self.get_scope(&parent_idx).unwrap();
let height = parent_scope.height + 1;
Scope::new(
caller,
new_idx,
Some(parent_idx),
height,
ScopeChildren(vcomponent.children),
self.vdom.clone(),
)
});
// Actually initialize the caller's slot with the right address
vcomponent.ass_scope.set(Some(new_idx));
if !vcomponent.can_memoize {
let cur_scope = self.get_scope_mut(&parent_idx).unwrap();
let extended = *vcomponent as *const VComponent;
let extended: *const VComponent<'static> =
unsafe { std::mem::transmute(extended) };
cur_scope.borrowed_props.borrow_mut().push(extended);
}
// TODO:
// add noderefs to current noderef list Noderefs
// add effects to current effect list Effects
let new_component = self.get_scope_mut(&new_idx).unwrap();
// Run the scope for one iteration to initialize it
match new_component.run_scope() {
Ok(_) => {
// all good, new nodes exist
}
Err(err) => {
// failed to run. this is the first time the component ran, and it failed
// we manually set its head node to an empty fragment
panic!("failing components not yet implemented");
}
}
// Take the node that was just generated from running the component
let nextnode = new_component.frames.fin_head();
// Push the new scope onto the stack
self.scope_stack.push(new_idx);
// Run the creation algorithm with this scope on the stack
let meta = self.create_vnode(nextnode);
// pop the scope off the stack
self.scope_stack.pop();
if meta.added_to_stack == 0 {
panic!("Components should *always* generate nodes - even if they fail");
}
// Finally, insert this scope as a seen node.
self.seen_scopes.insert(new_idx);
CreateMeta::new(vcomponent.is_static, meta.added_to_stack)
}
// Fragments are the only nodes that can contain dynamic content (IE through curlies or iterators).
// We can never ignore their contents, so the prescence of a fragment indicates that we need always diff them.
// Fragments will just put all their nodes onto the stack after creation
VNode::Fragment(frag) => self.create_children(frag.children),
VNode::Suspended(VSuspended { node: real_node }) => {
let id = self.vdom.reserve_node();
self.edit_create_placeholder(id);
real_node.set(Some(id));
CreateMeta::new(false, 1)
}
}
}
fn create_children(&mut self, children: &'bump [VNode<'bump>]) -> CreateMeta {
let mut is_static = true;
let mut added_to_stack = 0;