Browse Source

wip: remove old create

Jonathan Kelley 3 years ago
parent
commit
7b068202ce
1 changed files with 144 additions and 280 deletions
  1. 144 280
      packages/core/src/diff.rs

+ 144 - 280
packages/core/src/diff.rs

@@ -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;