Browse Source

wip: moving to imperative method of dom

Jonathan Kelley 4 years ago
parent
commit
45ee803

+ 4 - 0
packages/core/.vscode/spellright.dict

@@ -1,2 +1,6 @@
 Dodrio
 Dodrio
 VDoms
 VDoms
+dom
+virtualdom
+ns
+nohasher

+ 4 - 4
packages/core/Cargo.toml

@@ -11,13 +11,13 @@ description = "Core functionality for Dioxus - a concurrent renderer-agnostic Vi
 
 
 [dependencies]
 [dependencies]
 # todo: use wast for faster load/compile
 # todo: use wast for faster load/compile
-dioxus-core-macro = { path = "../core-macro", version = "0.1.1" }
+dioxus-core-macro = { path="../core-macro", version="0.1.1" }
 
 
 # Backs scopes and graphs between parent and children
 # Backs scopes and graphs between parent and children
-generational-arena = { version = "0.2.8" }
+generational-arena = { version="0.2.8" }
 
 
 # Bumpalo backs the VNode creation
 # Bumpalo backs the VNode creation
-bumpalo = { version = "3.6.0", features = ["collections", "boxed"] }
+bumpalo = { version="3.6.0", features=["collections", "boxed"] }
 
 
 # custom error type
 # custom error type
 thiserror = "1"
 thiserror = "1"
@@ -32,7 +32,7 @@ longest-increasing-subsequence = "0.1.0"
 log = "0.4"
 log = "0.4"
 
 
 # Serialize the Edits for use in Webview/Liveview instances
 # Serialize the Edits for use in Webview/Liveview instances
-serde = { version = "1", features = ["derive"], optional = true }
+serde = { version="1", features=["derive"], optional=true }
 
 
 [features]
 [features]
 default = []
 default = []

+ 41 - 7
packages/core/architecture.md

@@ -1,23 +1,57 @@
 # This module includes all life-cycle related mechanics, including the virtual DOM, scopes, properties, and lifecycles.
 # This module includes all life-cycle related mechanics, including the virtual DOM, scopes, properties, and lifecycles.
+
 ---
 ---
+
 The VirtualDom is designed as so:
 The VirtualDom is designed as so:
 
 
 VDOM contains:
 VDOM contains:
+
 - An arena of component scopes.
 - An arena of component scopes.
-    - A scope contains
-        - lifecycle data
-        - hook data
+  - A scope contains
+    - lifecycle data
+    - hook data
 - Event queue
 - Event queue
-    - An event
+  - An event
 
 
 A VDOM is
 A VDOM is
+
 - constructed from anything that implements "component"
 - constructed from anything that implements "component"
 
 
 A "Component" is anything (normally functions) that can be ran with a context to produce VNodes
 A "Component" is anything (normally functions) that can be ran with a context to produce VNodes
+
 - Must implement properties-builder trait which produces a properties builder
 - Must implement properties-builder trait which produces a properties builder
 
 
 A Context
 A Context
+
 - Is a consumable struct
 - Is a consumable struct
-    - Made of references to properties
-    - Holds a reference (lockable) to the underlying scope
-    - Is partially thread-safe
+  - Made of references to properties
+  - Holds a reference (lockable) to the underlying scope
+  - Is partially thread-safe
+
+# How to interact with the real dom?
+
+## idea: use only u32
+
+pros:
+
+- allows for 4,294,967,295 nodes (enough)
+- u32 is relatively small
+- doesn't add type noise
+- allows virtualdom to stay completely generic
+
+cons:
+
+- cost of querying individual nodes (about 7ns per node query for all sizes w/ nohasher)
+- old IDs need to be manually freed when subtrees are destroyed
+  - can be collected as garbage after every render
+- loss of ids between renders........................
+  - each new render doesn't know which node the old one was connected to unless it is visited
+  - When are nodes _not_ visited during diffing?
+    - They are predetermined to be removed (a parent was probed)
+    - something with keys?
+    - I think all nodes must be visited between diffs
+  -
+
+## idea: leak raw nodes and then reclaim them on drop
+
+## idea: bind

+ 217 - 159
packages/core/src/diff.rs

@@ -9,15 +9,10 @@
 //! Implementation Details:
 //! Implementation Details:
 //! -----------------------
 //! -----------------------
 //!
 //!
-//! Diff the `old` node with the `new` node. Emits instructions to modify a
-//! physical DOM node that reflects `old` into something that reflects `new`.
+//! All nodes are addressed by their IDs. The RealDom provides an imperative interface for making changes to these nodes.
+//! We don't necessarily intend for changes to happen exactly during the diffing process, so the implementor may choose
+//! to batch nodes if it is more performant for their application. The u32 should be a no-op to hash,
 //!
 //!
-//! Upon entry to this function, the physical DOM node must be on the top of the
-//! change list stack:
-//!
-//!     [... node]
-//!
-//! The change list stack is in the same state when this function exits.
 //!
 //!
 //! Further Reading and Thoughts
 //! Further Reading and Thoughts
 //! ----------------------------
 //! ----------------------------
@@ -30,11 +25,58 @@ use crate::{arena::ScopeArena, innerlude::*};
 use fxhash::{FxHashMap, FxHashSet};
 use fxhash::{FxHashMap, FxHashSet};
 
 
 use std::{
 use std::{
+    any::Any,
+    cell::Cell,
     cmp::Ordering,
     cmp::Ordering,
     rc::{Rc, Weak},
     rc::{Rc, Weak},
-    sync::atomic::AtomicU32,
 };
 };
 
 
+/// The accompanying "real dom" exposes an imperative API for controlling the UI layout
+///
+/// Instead of having handles directly over nodes, Dioxus uses simple u32s as node IDs.
+/// This allows layouts with up to 4,294,967,295 nodes. If we
+pub trait RealDom {
+    fn delete_root(&mut self, root: RealDomNode);
+
+    // ===========
+    //  Create
+    // ===========
+    /// Create a new text node and push it on to the top of the stack
+    fn create_text_node(&mut self, text: &str) -> RealDomNode;
+
+    /// Create a new text node and push it on to the top of the stack
+    fn create_element(&mut self, tag: &str) -> RealDomNode;
+
+    /// Create a new namespaced element and push it on to the top of the stack
+    fn create_element_ns(&mut self, tag: &str, namespace: &str) -> RealDomNode;
+
+    fn append_node(&self, child: RealDomNode, parent: RealDomNode);
+
+    // ===========
+    //  Remove
+    // ===========
+    fn remove_node(&mut self, node: RealDomNode);
+
+    fn remove_all_children(&mut self, node: RealDomNode);
+
+    // ===========
+    //  Replace
+    // ===========
+    fn replace_node_with(&mut self, old: RealDomNode, new: RealDomNode);
+
+    fn new_event_listener(&mut self, node: RealDomNode, event: &str);
+
+    fn set_inner_text(&mut self, node: RealDomNode, text: &str);
+
+    fn set_class(&mut self, node: RealDomNode);
+
+    fn set_attr(&mut self, node: RealDomNode, name: &str, value: &str);
+
+    fn remove_attr(&mut self, node: RealDomNode);
+
+    fn raw_node_as_any_mut(&mut self) -> &mut dyn Any;
+}
+
 /// The DiffState is a cursor internal to the VirtualDOM's diffing algorithm that allows persistence of state while
 /// The DiffState is a cursor internal to the VirtualDOM's diffing algorithm that allows persistence of state while
 /// diffing trees of components. This means we can "re-enter" a subtree of a component by queuing a "NeedToDiff" event.
 /// diffing trees of components. This means we can "re-enter" a subtree of a component by queuing a "NeedToDiff" event.
 ///
 ///
@@ -47,39 +89,39 @@ use std::{
 /// The order of these re-entrances is stored in the DiffState itself. The DiffState comes pre-loaded with a set of components
 /// The order of these re-entrances is stored in the DiffState itself. The DiffState comes pre-loaded with a set of components
 /// that were modified by the eventtrigger. This prevents doubly evaluating components if they were both updated via
 /// that were modified by the eventtrigger. This prevents doubly evaluating components if they were both updated via
 /// subscriptions and props changes.
 /// subscriptions and props changes.
-pub struct DiffMachine<'a> {
-    pub create_diffs: bool,
+pub struct DiffMachine {
     pub cur_idx: ScopeIdx,
     pub cur_idx: ScopeIdx,
-    pub change_list: EditMachine<'a>,
     pub diffed: FxHashSet<ScopeIdx>,
     pub diffed: FxHashSet<ScopeIdx>,
     pub components: ScopeArena,
     pub components: ScopeArena,
     pub event_queue: EventQueue,
     pub event_queue: EventQueue,
     pub seen_nodes: FxHashSet<ScopeIdx>,
     pub seen_nodes: FxHashSet<ScopeIdx>,
 }
 }
 
 
-static COUNTER: AtomicU32 = AtomicU32::new(1);
+// todo: see if unsafe works better
+static COUNTER: Cell<u32> = Cell::new(1);
 fn next_id() -> u32 {
 fn next_id() -> u32 {
-    COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
+    let out = COUNTER.get();
+    COUNTER.set(out + 1);
+    out
 }
 }
 
 
-impl<'a> DiffMachine<'a> {
+impl DiffMachine {
     pub fn new(components: ScopeArena, cur_idx: ScopeIdx, event_queue: EventQueue) -> Self {
     pub fn new(components: ScopeArena, cur_idx: ScopeIdx, event_queue: EventQueue) -> Self {
         Self {
         Self {
             components,
             components,
             cur_idx,
             cur_idx,
             event_queue,
             event_queue,
-            create_diffs: true,
-            change_list: EditMachine::new(),
             diffed: FxHashSet::default(),
             diffed: FxHashSet::default(),
             seen_nodes: FxHashSet::default(),
             seen_nodes: FxHashSet::default(),
         }
         }
     }
     }
 
 
-    pub fn consume(self) -> EditList<'a> {
-        self.change_list.emitter
-    }
-
-    pub fn diff_node(&mut self, old_node: &VNode<'a>, new_node: &VNode<'a>) {
+    pub fn diff_node<'a, Dom: RealDom>(
+        &mut self,
+        dom: &mut Dom,
+        old_node: &mut VNode<'a>,
+        new_node: &mut VNode<'a>,
+    ) {
         // pub fn diff_node(&mut self, old: &VNode<'a>, new: &VNode<'a>) {
         // pub fn diff_node(&mut self, old: &VNode<'a>, new: &VNode<'a>) {
         /*
         /*
         For each valid case, we "commit traversal", meaning we save this current position in the tree.
         For each valid case, we "commit traversal", meaning we save this current position in the tree.
@@ -87,61 +129,64 @@ impl<'a> DiffMachine<'a> {
         When re-entering, we reuse the EditList in DiffState
         When re-entering, we reuse the EditList in DiffState
         */
         */
         match (old_node, new_node) {
         match (old_node, new_node) {
-            (VNode::Text(old_text), VNode::Text(new_text)) => {
-                if old_text != new_text {
-                    self.change_list.commit_traversal();
-                    self.change_list.set_text(new_text);
+            (VNode::Text(old), VNode::Text(new)) => {
+                new.dom_id = old.dom_id;
+                if old.text != new.text {
+                    self.realdom.set_inner_text(new.dom_id, new.text);
                 }
                 }
             }
             }
 
 
-            (VNode::Text(_), VNode::Element(_)) => {
-                self.change_list.commit_traversal();
+            (VNode::Text(old), VNode::Element(new)) => {
+                // // self.realdom.commit_traversal();
                 self.create(new_node);
                 self.create(new_node);
-                self.change_list.replace_with();
+                self.realdom.replace_node_with(old.dom_id, old.dom_id);
+                // self.realdom.replace_with();
             }
             }
 
 
-            (VNode::Element(_), VNode::Text(_)) => {
-                self.change_list.commit_traversal();
+            (VNode::Element(old), VNode::Text(new)) => {
+                // // self.realdom.commit_traversal();
                 self.create(new_node);
                 self.create(new_node);
-                self.change_list.replace_with();
+                self.realdom.replace_node_with(old.dom_id, new.dom_id);
+                // self.realdom.replace_with();
             }
             }
 
 
-            (VNode::Element(eold), VNode::Element(enew)) => {
+            (VNode::Element(old), VNode::Element(new)) => {
                 // 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
-                if enew.tag_name != eold.tag_name || enew.namespace != eold.namespace {
-                    self.change_list.commit_traversal();
-                    self.change_list.replace_with();
+                if new.tag_name != old.tag_name || new.namespace != old.namespace {
+                    // // self.realdom.commit_traversal();
+                    // self.realdom.replace_with();
+                    self.realdom.replace_node_with(old.dom_id, new.dom_id);
                     return;
                     return;
                 }
                 }
 
 
-                self.diff_listeners(eold.listeners, enew.listeners);
-                self.diff_attr(eold.attributes, enew.attributes, enew.namespace.is_some());
-                self.diff_children(eold.children, enew.children);
+                self.diff_listeners(old.listeners, new.listeners);
+                self.diff_attr(old.attributes, new.attributes, new.namespace.is_some());
+                self.diff_children(old.children, new.children);
             }
             }
 
 
-            (VNode::Component(cold), VNode::Component(cnew)) => {
+            (VNode::Component(old), VNode::Component(new)) => {
                 // Make sure we're dealing with the same component (by function pointer)
                 // Make sure we're dealing with the same component (by function pointer)
-                if cold.user_fc == cnew.user_fc {
+                if old.user_fc == new.user_fc {
                     // Make sure the new component vnode is referencing the right scope id
                     // Make sure the new component vnode is referencing the right scope id
-                    let scope_id = cold.ass_scope.borrow().clone();
-                    *cnew.ass_scope.borrow_mut() = scope_id;
+                    let scope_id = old.ass_scope.borrow().clone();
+                    *new.ass_scope.borrow_mut() = scope_id;
 
 
                     // make sure the component's caller function is up to date
                     // make sure the component's caller function is up to date
                     self.components
                     self.components
                         .with_scope(scope_id.unwrap(), |scope| {
                         .with_scope(scope_id.unwrap(), |scope| {
-                            scope.caller = Rc::downgrade(&cnew.caller)
+                            scope.caller = Rc::downgrade(&new.caller)
                         })
                         })
                         .unwrap();
                         .unwrap();
 
 
                     // React doesn't automatically memoize, but we do.
                     // React doesn't automatically memoize, but we do.
                     // The cost is low enough to make it worth checking
                     // The cost is low enough to make it worth checking
-                    let should_render = match cold.comparator {
-                        Some(comparator) => comparator(cnew),
+                    let should_render = match old.comparator {
+                        Some(comparator) => comparator(new),
                         None => true,
                         None => true,
                     };
                     };
 
 
                     if should_render {
                     if should_render {
-                        self.change_list.commit_traversal();
+                        // // self.realdom.commit_traversal();
                         self.components
                         self.components
                             .with_scope(scope_id.unwrap(), |f| {
                             .with_scope(scope_id.unwrap(), |f| {
                                 f.run_scope().unwrap();
                                 f.run_scope().unwrap();
@@ -159,28 +204,29 @@ impl<'a> DiffMachine<'a> {
                     // A new component has shown up! We need to destroy the old node
                     // A new component has shown up! We need to destroy the old node
 
 
                     // Wipe the old one and plant the new one
                     // Wipe the old one and plant the new one
-                    self.change_list.commit_traversal();
+                    // self.realdom.commit_traversal();
                     self.create(new_node);
                     self.create(new_node);
-                    self.change_list.replace_with();
+                    // self.realdom.replace_node_with(old.dom_id, new.dom_id);
+                    self.realdom.replace_with();
 
 
                     // Now we need to remove the old scope and all of its descendents
                     // Now we need to remove the old scope and all of its descendents
-                    let old_scope = cold.ass_scope.borrow().as_ref().unwrap().clone();
+                    let old_scope = old.ass_scope.borrow().as_ref().unwrap().clone();
                     self.destroy_scopes(old_scope);
                     self.destroy_scopes(old_scope);
                 }
                 }
             }
             }
 
 
             // todo: knock out any listeners
             // todo: knock out any listeners
             (_, VNode::Component(_)) => {
             (_, VNode::Component(_)) => {
-                self.change_list.commit_traversal();
+                // self.realdom.commit_traversal();
                 self.create(new_node);
                 self.create(new_node);
-                self.change_list.replace_with();
+                self.realdom.replace_with();
             }
             }
 
 
             // A component is being torn down in favor of a non-component node
             // A component is being torn down in favor of a non-component node
             (VNode::Component(_old), _) => {
             (VNode::Component(_old), _) => {
-                self.change_list.commit_traversal();
+                // self.realdom.commit_traversal();
                 self.create(new_node);
                 self.create(new_node);
-                self.change_list.replace_with();
+                self.realdom.replace_with();
 
 
                 // Destroy the original scope and any of its children
                 // Destroy the original scope and any of its children
                 self.destroy_scopes(_old.ass_scope.borrow().unwrap());
                 self.destroy_scopes(_old.ass_scope.borrow().unwrap());
@@ -223,35 +269,46 @@ impl<'a> DiffMachine<'a> {
     // When this function returns, the new node is on top of the change list stack:
     // When this function returns, the new node is on top of the change list stack:
     //
     //
     //     [... node]
     //     [... node]
-    fn create(&mut self, node: &VNode<'a>) {
-        debug_assert!(self.change_list.traversal_is_committed());
+    fn create<'a, Dom: RealDom>(
+        &mut self,
+        dom: &mut Dom,
+        node: &mut VNode<'a>,
+        parent: RealDomNode,
+    ) {
+        // debug_assert!(self.realdom.traversal_is_committed());
         match node {
         match node {
             VNode::Text(text) => {
             VNode::Text(text) => {
-                self.change_list.create_text_node(text);
+                let real_id = self.realdom.create_text_node(text.text);
+                text.dom_id = real_id;
             }
             }
-            VNode::Element(&VElement {
-                key,
-                tag_name,
-                listeners,
-                attributes,
-                children,
-                namespace,
-            }) => {
+            VNode::Element(&el) => {
+                let VElement {
+                    key,
+                    tag_name,
+                    listeners,
+                    attributes,
+                    children,
+                    namespace,
+                    dom_id,
+                } = el;
                 // log::info!("Creating {:#?}", node);
                 // log::info!("Creating {:#?}", node);
-                if let Some(namespace) = namespace {
-                    self.change_list.create_element_ns(tag_name, namespace);
+                let real_id = if let Some(namespace) = namespace {
+                    self.realdom.create_element_ns(tag_name, namespace)
                 } else {
                 } else {
-                    self.change_list.create_element(tag_name);
-                }
+                    self.realdom.create_element(tag_name)
+                };
+                el.dom_id = real_id;
 
 
                 listeners.iter().enumerate().for_each(|(_id, listener)| {
                 listeners.iter().enumerate().for_each(|(_id, listener)| {
-                    self.change_list
-                        .new_event_listener(listener.event, listener.scope, listener.id)
+                    todo!()
+                    // self.realdom
+                    //     .new_event_listener(listener.event, listener.scope, listener.id)
                 });
                 });
 
 
                 for attr in attributes {
                 for attr in attributes {
-                    self.change_list
-                        .set_attribute(&attr.name, &attr.value, namespace.is_some());
+                    todo!()
+                    // self.realdom
+                    //     .set_attribute(&attr.name, &attr.value, namespace.is_some());
                 }
                 }
 
 
                 // Fast path: if there is a single text child, it is faster to
                 // Fast path: if there is a single text child, it is faster to
@@ -262,28 +319,27 @@ impl<'a> DiffMachine<'a> {
                 // parent.
                 // parent.
                 if children.len() == 1 {
                 if children.len() == 1 {
                     if let VNode::Text(text) = children[0] {
                     if let VNode::Text(text) = children[0] {
-                        self.change_list.set_text(text);
+                        self.realdom.set_inner_text(real_id, text.text);
                         return;
                         return;
                     }
                     }
                 }
                 }
 
 
                 for child in children {
                 for child in children {
-                    self.create(child);
+                    self.create(child, real_id);
                     if let VNode::Fragment(_) = child {
                     if let VNode::Fragment(_) = child {
                         // do nothing
                         // do nothing
                         // fragments append themselves
                         // fragments append themselves
                     } else {
                     } else {
-                        self.change_list.append_child();
+                        self.realdom.append_child();
                     }
                     }
                 }
                 }
             }
             }
 
 
             VNode::Component(component) => {
             VNode::Component(component) => {
-                self.change_list
-                    .create_text_node("placeholder for vcomponent");
+                self.realdom.create_text_node("placeholder for vcomponent");
 
 
-                let root_id = next_id();
-                self.change_list.save_known_root(root_id);
+                // let root_id = next_id();
+                // self.realdom.save_known_root(root_id);
 
 
                 log::debug!("Mounting a new component");
                 log::debug!("Mounting a new component");
                 let caller: Weak<OpaqueComponent> = Rc::downgrade(&component.caller);
                 let caller: Weak<OpaqueComponent> = Rc::downgrade(&component.caller);
@@ -333,7 +389,8 @@ impl<'a> DiffMachine<'a> {
                 new_component.run_scope().unwrap();
                 new_component.run_scope().unwrap();
 
 
                 // And then run the diff algorithm
                 // And then run the diff algorithm
-                self.diff_node(new_component.old_frame(), new_component.next_frame());
+                todo!();
+                // self.diff_node(new_component.old_frame(), new_component.next_frame());
 
 
                 // Finally, insert this node as a seen node.
                 // Finally, insert this node as a seen node.
                 self.seen_nodes.insert(idx);
                 self.seen_nodes.insert(idx);
@@ -343,8 +400,9 @@ impl<'a> DiffMachine<'a> {
             VNode::Fragment(frag) => {
             VNode::Fragment(frag) => {
                 // create the children directly in the space
                 // create the children directly in the space
                 for child in frag.children {
                 for child in frag.children {
-                    self.create(child);
-                    self.change_list.append_child();
+                    todo!()
+                    // self.create(child);
+                    // self.realdom.append_child();
                 }
                 }
             }
             }
 
 
@@ -395,7 +453,7 @@ impl<'a> DiffMachine<'a> {
     // The change list stack is left unchanged.
     // The change list stack is left unchanged.
     fn diff_listeners(&mut self, old: &[Listener<'_>], new: &[Listener<'_>]) {
     fn diff_listeners(&mut self, old: &[Listener<'_>], new: &[Listener<'_>]) {
         if !old.is_empty() || !new.is_empty() {
         if !old.is_empty() || !new.is_empty() {
-            self.change_list.commit_traversal();
+            // self.realdom.commit_traversal();
         }
         }
 
 
         'outer1: for (_l_idx, new_l) in new.iter().enumerate() {
         'outer1: for (_l_idx, new_l) in new.iter().enumerate() {
@@ -410,8 +468,8 @@ impl<'a> DiffMachine<'a> {
             for old_l in old {
             for old_l in old {
                 if new_l.event == old_l.event {
                 if new_l.event == old_l.event {
                     if new_l.id != old_l.id {
                     if new_l.id != old_l.id {
-                        self.change_list.remove_event_listener(event_type);
-                        self.change_list
+                        self.realdom.remove_event_listener(event_type);
+                        self.realdom
                             .update_event_listener(event_type, new_l.scope, new_l.id)
                             .update_event_listener(event_type, new_l.scope, new_l.id)
                     }
                     }
 
 
@@ -419,7 +477,7 @@ impl<'a> DiffMachine<'a> {
                 }
                 }
             }
             }
 
 
-            self.change_list
+            self.realdom
                 .new_event_listener(event_type, new_l.scope, new_l.id);
                 .new_event_listener(event_type, new_l.scope, new_l.id);
         }
         }
 
 
@@ -429,7 +487,7 @@ impl<'a> DiffMachine<'a> {
                     continue 'outer2;
                     continue 'outer2;
                 }
                 }
             }
             }
-            self.change_list.remove_event_listener(old_l.event);
+            self.realdom.remove_event_listener(old_l.event);
         }
         }
     }
     }
 
 
@@ -440,7 +498,7 @@ impl<'a> DiffMachine<'a> {
     //     [... node]
     //     [... node]
     //
     //
     // The change list stack is left unchanged.
     // The change list stack is left unchanged.
-    fn diff_attr(
+    fn diff_attr<'a>(
         &mut self,
         &mut self,
         old: &'a [Attribute<'a>],
         old: &'a [Attribute<'a>],
         new: &'a [Attribute<'a>],
         new: &'a [Attribute<'a>],
@@ -453,15 +511,15 @@ impl<'a> DiffMachine<'a> {
         // With the Rsx and Html macros, this will almost always be the case
         // With the Rsx and Html macros, this will almost always be the case
         'outer: for new_attr in new {
         'outer: for new_attr in new {
             if new_attr.is_volatile() {
             if new_attr.is_volatile() {
-                self.change_list.commit_traversal();
-                self.change_list
+                // self.realdom.commit_traversal();
+                self.realdom
                     .set_attribute(new_attr.name, new_attr.value, is_namespaced);
                     .set_attribute(new_attr.name, new_attr.value, is_namespaced);
             } else {
             } else {
                 for old_attr in old {
                 for old_attr in old {
                     if old_attr.name == new_attr.name {
                     if old_attr.name == new_attr.name {
                         if old_attr.value != new_attr.value {
                         if old_attr.value != new_attr.value {
-                            self.change_list.commit_traversal();
-                            self.change_list.set_attribute(
+                            // self.realdom.commit_traversal();
+                            self.realdom.set_attribute(
                                 new_attr.name,
                                 new_attr.name,
                                 new_attr.value,
                                 new_attr.value,
                                 is_namespaced,
                                 is_namespaced,
@@ -473,8 +531,8 @@ impl<'a> DiffMachine<'a> {
                     }
                     }
                 }
                 }
 
 
-                self.change_list.commit_traversal();
-                self.change_list
+                // self.realdom.commit_traversal();
+                self.realdom
                     .set_attribute(new_attr.name, new_attr.value, is_namespaced);
                     .set_attribute(new_attr.name, new_attr.value, is_namespaced);
             }
             }
         }
         }
@@ -486,8 +544,8 @@ impl<'a> DiffMachine<'a> {
                 }
                 }
             }
             }
 
 
-            self.change_list.commit_traversal();
-            self.change_list.remove_attribute(old_attr.name);
+            // self.realdom.commit_traversal();
+            self.realdom.remove_attribute(old_attr.name);
         }
         }
     }
     }
 
 
@@ -499,10 +557,10 @@ impl<'a> DiffMachine<'a> {
     //     [... parent]
     //     [... parent]
     //
     //
     // the change list stack is in the same state when this function returns.
     // the change list stack is in the same state when this function returns.
-    fn diff_children(&mut self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) {
+    fn diff_children<'a>(&mut self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) {
         if new.is_empty() {
         if new.is_empty() {
             if !old.is_empty() {
             if !old.is_empty() {
-                self.change_list.commit_traversal();
+                // self.realdom.commit_traversal();
                 self.remove_all_children(old);
                 self.remove_all_children(old);
             }
             }
             return;
             return;
@@ -515,8 +573,8 @@ impl<'a> DiffMachine<'a> {
                 }
                 }
 
 
                 (_, &VNode::Text(text)) => {
                 (_, &VNode::Text(text)) => {
-                    self.change_list.commit_traversal();
-                    self.change_list.set_text(text);
+                    // self.realdom.commit_traversal();
+                    self.realdom.set_text(text);
                     return;
                     return;
                 }
                 }
 
 
@@ -527,7 +585,7 @@ impl<'a> DiffMachine<'a> {
 
 
         if old.is_empty() {
         if old.is_empty() {
             if !new.is_empty() {
             if !new.is_empty() {
-                self.change_list.commit_traversal();
+                // self.realdom.commit_traversal();
                 self.create_and_append_children(new);
                 self.create_and_append_children(new);
             }
             }
             return;
             return;
@@ -546,9 +604,9 @@ impl<'a> DiffMachine<'a> {
         );
         );
 
 
         if new_is_keyed && old_is_keyed {
         if new_is_keyed && old_is_keyed {
-            let t = self.change_list.next_temporary();
+            let t = self.realdom.next_temporary();
             self.diff_keyed_children(old, new);
             self.diff_keyed_children(old, new);
-            self.change_list.set_next_temporary(t);
+            self.realdom.set_next_temporary(t);
         } else {
         } else {
             self.diff_non_keyed_children(old, new);
             self.diff_non_keyed_children(old, new);
         }
         }
@@ -575,7 +633,7 @@ impl<'a> DiffMachine<'a> {
     //     [... parent]
     //     [... parent]
     //
     //
     // Upon exiting, the change list stack is in the same state.
     // Upon exiting, the change list stack is in the same state.
-    fn diff_keyed_children(&mut self, old: &[VNode<'a>], new: &[VNode<'a>]) {
+    fn diff_keyed_children<'a>(&mut self, old: &[VNode<'a>], new: &[VNode<'a>]) {
         // if cfg!(debug_assertions) {
         // if cfg!(debug_assertions) {
         //     let mut keys = fxhash::FxHashSet::default();
         //     let mut keys = fxhash::FxHashSet::default();
         //     let mut assert_unique_keys = |children: &[VNode]| {
         //     let mut assert_unique_keys = |children: &[VNode]| {
@@ -658,8 +716,8 @@ impl<'a> DiffMachine<'a> {
     //     [... parent]
     //     [... parent]
     //
     //
     // Upon exit, the change list stack is the same.
     // Upon exit, the change list stack is the same.
-    fn diff_keyed_prefix(&mut self, old: &[VNode<'a>], new: &[VNode<'a>]) -> KeyedPrefixResult {
-        self.change_list.go_down();
+    fn diff_keyed_prefix<'a>(&mut self, old: &[VNode<'a>], new: &[VNode<'a>]) -> KeyedPrefixResult {
+        // self.realdom.go_down();
         let mut shared_prefix_count = 0;
         let mut shared_prefix_count = 0;
 
 
         for (i, (old, new)) in old.iter().zip(new.iter()).enumerate() {
         for (i, (old, new)) in old.iter().zip(new.iter()).enumerate() {
@@ -667,7 +725,7 @@ impl<'a> DiffMachine<'a> {
                 break;
                 break;
             }
             }
 
 
-            self.change_list.go_to_sibling(i);
+            self.realdom.go_to_sibling(i);
 
 
             self.diff_node(old, new);
             self.diff_node(old, new);
 
 
@@ -677,8 +735,8 @@ impl<'a> DiffMachine<'a> {
         // If that was all of the old children, then create and append the remaining
         // If that was all of the old children, then create and append the remaining
         // new children and we're finished.
         // new children and we're finished.
         if shared_prefix_count == old.len() {
         if shared_prefix_count == old.len() {
-            self.change_list.go_up();
-            self.change_list.commit_traversal();
+            self.realdom.go_up();
+            // self.realdom.commit_traversal();
             self.create_and_append_children(&new[shared_prefix_count..]);
             self.create_and_append_children(&new[shared_prefix_count..]);
             return KeyedPrefixResult::Finished;
             return KeyedPrefixResult::Finished;
         }
         }
@@ -686,13 +744,13 @@ impl<'a> DiffMachine<'a> {
         // And if that was all of the new children, then remove all of the remaining
         // And if that was all of the new children, then remove all of the remaining
         // old children and we're finished.
         // old children and we're finished.
         if shared_prefix_count == new.len() {
         if shared_prefix_count == new.len() {
-            self.change_list.go_to_sibling(shared_prefix_count);
-            self.change_list.commit_traversal();
+            self.realdom.go_to_sibling(shared_prefix_count);
+            // self.realdom.commit_traversal();
             self.remove_self_and_next_siblings(&old[shared_prefix_count..]);
             self.remove_self_and_next_siblings(&old[shared_prefix_count..]);
             return KeyedPrefixResult::Finished;
             return KeyedPrefixResult::Finished;
         }
         }
 
 
-        self.change_list.go_up();
+        self.realdom.go_up();
         KeyedPrefixResult::MoreWorkToDo(shared_prefix_count)
         KeyedPrefixResult::MoreWorkToDo(shared_prefix_count)
     }
     }
 
 
@@ -709,7 +767,7 @@ impl<'a> DiffMachine<'a> {
     //     [... parent]
     //     [... parent]
     //
     //
     // Upon exit from this function, it will be restored to that same state.
     // Upon exit from this function, it will be restored to that same state.
-    fn diff_keyed_middle(
+    fn diff_keyed_middle<'a>(
         &mut self,
         &mut self,
         old: &[VNode<'a>],
         old: &[VNode<'a>],
         mut new: &[VNode<'a>],
         mut new: &[VNode<'a>],
@@ -753,11 +811,11 @@ impl<'a> DiffMachine<'a> {
         // afresh.
         // afresh.
         if shared_suffix_count == 0 && shared_keys.is_empty() {
         if shared_suffix_count == 0 && shared_keys.is_empty() {
             if shared_prefix_count == 0 {
             if shared_prefix_count == 0 {
-                self.change_list.commit_traversal();
+                // self.realdom.commit_traversal();
                 self.remove_all_children(old);
                 self.remove_all_children(old);
             } else {
             } else {
-                self.change_list.go_down_to_child(shared_prefix_count);
-                self.change_list.commit_traversal();
+                self.realdom.go_down_to_child(shared_prefix_count);
+                // self.realdom.commit_traversal();
                 self.remove_self_and_next_siblings(&old[shared_prefix_count..]);
                 self.remove_self_and_next_siblings(&old[shared_prefix_count..]);
             }
             }
 
 
@@ -779,8 +837,8 @@ impl<'a> DiffMachine<'a> {
                 .unwrap_or(old.len());
                 .unwrap_or(old.len());
 
 
             if end - start > 0 {
             if end - start > 0 {
-                self.change_list.commit_traversal();
-                let mut t = self.change_list.save_children_to_temporaries(
+                // self.realdom.commit_traversal();
+                let mut t = self.realdom.save_children_to_temporaries(
                     shared_prefix_count + start,
                     shared_prefix_count + start,
                     shared_prefix_count + end,
                     shared_prefix_count + end,
                 );
                 );
@@ -805,8 +863,8 @@ impl<'a> DiffMachine<'a> {
             if !shared_keys.contains(&old_child.key()) {
             if !shared_keys.contains(&old_child.key()) {
                 // registry.remove_subtree(old_child);
                 // registry.remove_subtree(old_child);
                 // todo
                 // todo
-                self.change_list.commit_traversal();
-                self.change_list.remove_child(i + shared_prefix_count);
+                // self.realdom.commit_traversal();
+                self.realdom.remove_child(i + shared_prefix_count);
                 removed_count += 1;
                 removed_count += 1;
             }
             }
         }
         }
@@ -849,7 +907,7 @@ impl<'a> DiffMachine<'a> {
             // shared suffix to the change list stack.
             // shared suffix to the change list stack.
             //
             //
             // [... parent]
             // [... parent]
-            self.change_list
+            self.realdom
                 .go_down_to_child(old_shared_suffix_start - removed_count);
                 .go_down_to_child(old_shared_suffix_start - removed_count);
         // [... parent first_child_of_shared_suffix]
         // [... parent first_child_of_shared_suffix]
         } else {
         } else {
@@ -865,29 +923,29 @@ impl<'a> DiffMachine<'a> {
                 let old_index = new_index_to_old_index[last_index];
                 let old_index = new_index_to_old_index[last_index];
                 let temp = old_index_to_temp[old_index];
                 let temp = old_index_to_temp[old_index];
                 // [... parent]
                 // [... parent]
-                self.change_list.go_down_to_temp_child(temp);
+                self.realdom.go_down_to_temp_child(temp);
                 // [... parent last]
                 // [... parent last]
                 self.diff_node(&old[old_index], last);
                 self.diff_node(&old[old_index], last);
 
 
                 if new_index_is_in_lis.contains(&last_index) {
                 if new_index_is_in_lis.contains(&last_index) {
                     // Don't move it, since it is already where it needs to be.
                     // Don't move it, since it is already where it needs to be.
                 } else {
                 } else {
-                    self.change_list.commit_traversal();
+                    // self.realdom.commit_traversal();
                     // [... parent last]
                     // [... parent last]
-                    self.change_list.append_child();
+                    self.realdom.append_child();
                     // [... parent]
                     // [... parent]
-                    self.change_list.go_down_to_temp_child(temp);
+                    self.realdom.go_down_to_temp_child(temp);
                     // [... parent last]
                     // [... parent last]
                 }
                 }
             } else {
             } else {
-                self.change_list.commit_traversal();
+                // self.realdom.commit_traversal();
                 // [... parent]
                 // [... parent]
                 self.create(last);
                 self.create(last);
 
 
                 // [... parent last]
                 // [... parent last]
-                self.change_list.append_child();
+                self.realdom.append_child();
                 // [... parent]
                 // [... parent]
-                self.change_list.go_down_to_reverse_child(0);
+                self.realdom.go_down_to_reverse_child(0);
                 // [... parent last]
                 // [... parent last]
             }
             }
         }
         }
@@ -896,11 +954,11 @@ impl<'a> DiffMachine<'a> {
             let old_index = new_index_to_old_index[new_index];
             let old_index = new_index_to_old_index[new_index];
             if old_index == u32::MAX as usize {
             if old_index == u32::MAX as usize {
                 debug_assert!(!shared_keys.contains(&new_child.key()));
                 debug_assert!(!shared_keys.contains(&new_child.key()));
-                self.change_list.commit_traversal();
+                // self.realdom.commit_traversal();
                 // [... parent successor]
                 // [... parent successor]
                 self.create(new_child);
                 self.create(new_child);
                 // [... parent successor new_child]
                 // [... parent successor new_child]
-                self.change_list.insert_before();
+                self.realdom.insert_before();
             // [... parent new_child]
             // [... parent new_child]
             } else {
             } else {
                 debug_assert!(shared_keys.contains(&new_child.key()));
                 debug_assert!(shared_keys.contains(&new_child.key()));
@@ -909,14 +967,14 @@ impl<'a> DiffMachine<'a> {
 
 
                 if new_index_is_in_lis.contains(&new_index) {
                 if new_index_is_in_lis.contains(&new_index) {
                     // [... parent successor]
                     // [... parent successor]
-                    self.change_list.go_to_temp_sibling(temp);
+                    self.realdom.go_to_temp_sibling(temp);
                 // [... parent new_child]
                 // [... parent new_child]
                 } else {
                 } else {
-                    self.change_list.commit_traversal();
+                    // self.realdom.commit_traversal();
                     // [... parent successor]
                     // [... parent successor]
-                    self.change_list.push_temporary(temp);
+                    self.realdom.push_temporary(temp);
                     // [... parent successor new_child]
                     // [... parent successor new_child]
-                    self.change_list.insert_before();
+                    self.realdom.insert_before();
                     // [... parent new_child]
                     // [... parent new_child]
                 }
                 }
 
 
@@ -925,7 +983,7 @@ impl<'a> DiffMachine<'a> {
         }
         }
 
 
         // [... parent child]
         // [... parent child]
-        self.change_list.go_up();
+        self.realdom.go_up();
         // [... parent]
         // [... parent]
     }
     }
 
 
@@ -936,7 +994,7 @@ impl<'a> DiffMachine<'a> {
     //     [... parent]
     //     [... parent]
     //
     //
     // When this function exits, the change list stack remains the same.
     // When this function exits, the change list stack remains the same.
-    fn diff_keyed_suffix(
+    fn diff_keyed_suffix<'a>(
         &mut self,
         &mut self,
         old: &[VNode<'a>],
         old: &[VNode<'a>],
         new: &[VNode<'a>],
         new: &[VNode<'a>],
@@ -946,16 +1004,16 @@ impl<'a> DiffMachine<'a> {
         debug_assert!(!old.is_empty());
         debug_assert!(!old.is_empty());
 
 
         // [... parent]
         // [... parent]
-        self.change_list.go_down();
+        self.realdom.go_down();
         // [... parent new_child]
         // [... parent new_child]
 
 
         for (i, (old_child, new_child)) in old.iter().zip(new.iter()).enumerate() {
         for (i, (old_child, new_child)) in old.iter().zip(new.iter()).enumerate() {
-            self.change_list.go_to_sibling(new_shared_suffix_start + i);
+            self.realdom.go_to_sibling(new_shared_suffix_start + i);
             self.diff_node(old_child, new_child);
             self.diff_node(old_child, new_child);
         }
         }
 
 
         // [... parent]
         // [... parent]
-        self.change_list.go_up();
+        self.realdom.go_up();
     }
     }
 
 
     // Diff children that are not keyed.
     // Diff children that are not keyed.
@@ -966,18 +1024,18 @@ impl<'a> DiffMachine<'a> {
     //     [... parent]
     //     [... parent]
     //
     //
     // the change list stack is in the same state when this function returns.
     // the change list stack is in the same state when this function returns.
-    fn diff_non_keyed_children(&mut self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) {
+    fn diff_non_keyed_children<'a>(&mut self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) {
         // Handled these cases in `diff_children` before calling this function.
         // Handled these cases in `diff_children` before calling this function.
         debug_assert!(!new.is_empty());
         debug_assert!(!new.is_empty());
         debug_assert!(!old.is_empty());
         debug_assert!(!old.is_empty());
 
 
         //     [... parent]
         //     [... parent]
-        self.change_list.go_down();
+        self.realdom.go_down();
         //     [... parent child]
         //     [... parent child]
 
 
         for (i, (new_child, old_child)) in new.iter().zip(old.iter()).enumerate() {
         for (i, (new_child, old_child)) in new.iter().zip(old.iter()).enumerate() {
             // [... parent prev_child]
             // [... parent prev_child]
-            self.change_list.go_to_sibling(i);
+            self.realdom.go_to_sibling(i);
             // [... parent this_child]
             // [... parent this_child]
             self.diff_node(old_child, new_child);
             self.diff_node(old_child, new_child);
         }
         }
@@ -986,9 +1044,9 @@ impl<'a> DiffMachine<'a> {
             // old.len > new.len -> removing some nodes
             // old.len > new.len -> removing some nodes
             Ordering::Greater => {
             Ordering::Greater => {
                 // [... parent prev_child]
                 // [... parent prev_child]
-                self.change_list.go_to_sibling(new.len());
+                self.realdom.go_to_sibling(new.len());
                 // [... parent first_child_to_remove]
                 // [... parent first_child_to_remove]
-                self.change_list.commit_traversal();
+                // self.realdom.commit_traversal();
                 // support::remove_self_and_next_siblings(state, &old[new.len()..]);
                 // support::remove_self_and_next_siblings(state, &old[new.len()..]);
                 self.remove_self_and_next_siblings(&old[new.len()..]);
                 self.remove_self_and_next_siblings(&old[new.len()..]);
                 // [... parent]
                 // [... parent]
@@ -996,15 +1054,15 @@ impl<'a> DiffMachine<'a> {
             // old.len < new.len -> adding some nodes
             // old.len < new.len -> adding some nodes
             Ordering::Less => {
             Ordering::Less => {
                 // [... parent last_child]
                 // [... parent last_child]
-                self.change_list.go_up();
+                self.realdom.go_up();
                 // [... parent]
                 // [... parent]
-                self.change_list.commit_traversal();
+                // self.realdom.commit_traversal();
                 self.create_and_append_children(&new[old.len()..]);
                 self.create_and_append_children(&new[old.len()..]);
             }
             }
             // old.len == new.len -> no nodes added/removed, but πerhaps changed
             // old.len == new.len -> no nodes added/removed, but πerhaps changed
             Ordering::Equal => {
             Ordering::Equal => {
                 // [... parent child]
                 // [... parent child]
-                self.change_list.go_up();
+                self.realdom.go_up();
                 // [... parent]
                 // [... parent]
             }
             }
         }
         }
@@ -1021,15 +1079,15 @@ impl<'a> DiffMachine<'a> {
     //     [... parent]
     //     [... parent]
     //
     //
     // When this function returns, the change list stack is in the same state.
     // When this function returns, the change list stack is in the same state.
-    pub fn remove_all_children(&mut self, old: &[VNode<'a>]) {
-        debug_assert!(self.change_list.traversal_is_committed());
+    pub fn remove_all_children<'a>(&mut self, old: &[VNode<'a>]) {
+        // debug_assert!(self.realdom.traversal_is_committed());
         log::debug!("REMOVING CHILDREN");
         log::debug!("REMOVING CHILDREN");
         for _child in old {
         for _child in old {
             // registry.remove_subtree(child);
             // registry.remove_subtree(child);
         }
         }
         // Fast way to remove all children: set the node's textContent to an empty
         // Fast way to remove all children: set the node's textContent to an empty
         // string.
         // string.
-        self.change_list.set_text("");
+        self.realdom.set_text("");
     }
     }
 
 
     // Create the given children and append them to the parent node.
     // Create the given children and append them to the parent node.
@@ -1039,11 +1097,11 @@ impl<'a> DiffMachine<'a> {
     //     [... parent]
     //     [... parent]
     //
     //
     // When this function returns, the change list stack is in the same state.
     // When this function returns, the change list stack is in the same state.
-    pub fn create_and_append_children(&mut self, new: &[VNode<'a>]) {
-        debug_assert!(self.change_list.traversal_is_committed());
+    pub fn create_and_append_children<'a>(&mut self, new: &[VNode<'a>]) {
+        // debug_assert!(self.realdom.traversal_is_committed());
         for child in new {
         for child in new {
             self.create(child);
             self.create(child);
-            self.change_list.append_child();
+            self.realdom.append_child();
         }
         }
     }
     }
 
 
@@ -1056,11 +1114,11 @@ impl<'a> DiffMachine<'a> {
     // After the function returns, the child is no longer on the change list stack:
     // After the function returns, the child is no longer on the change list stack:
     //
     //
     //     [... parent]
     //     [... parent]
-    pub fn remove_self_and_next_siblings(&mut self, old: &[VNode<'a>]) {
-        debug_assert!(self.change_list.traversal_is_committed());
+    pub fn remove_self_and_next_siblings<'a>(&mut self, old: &[VNode<'a>]) {
+        // debug_assert!(self.realdom.traversal_is_committed());
         for child in old {
         for child in old {
             if let VNode::Component(vcomp) = child {
             if let VNode::Component(vcomp) = child {
-                // self.change_list
+                // self.realdom
                 //     .create_text_node("placeholder for vcomponent");
                 //     .create_text_node("placeholder for vcomponent");
 
 
                 todo!()
                 todo!()
@@ -1071,7 +1129,7 @@ impl<'a> DiffMachine<'a> {
                 // })
                 // })
                 // let id = get_id();
                 // let id = get_id();
                 // *component.stable_addr.as_ref().borrow_mut() = Some(id);
                 // *component.stable_addr.as_ref().borrow_mut() = Some(id);
-                // self.change_list.save_known_root(id);
+                // self.realdom.save_known_root(id);
                 // let scope = Rc::downgrade(&component.ass_scope);
                 // let scope = Rc::downgrade(&component.ass_scope);
                 // self.lifecycle_events.push_back(LifeCycleEvent::Mount {
                 // self.lifecycle_events.push_back(LifeCycleEvent::Mount {
                 //     caller: Rc::downgrade(&component.caller),
                 //     caller: Rc::downgrade(&component.caller),
@@ -1082,7 +1140,7 @@ impl<'a> DiffMachine<'a> {
 
 
             // registry.remove_subtree(child);
             // registry.remove_subtree(child);
         }
         }
-        self.change_list.remove_self_and_next_siblings();
+        self.realdom.remove_self_and_next_siblings();
     }
     }
 }
 }
 
 

+ 2 - 3
packages/core/src/lib.rs

@@ -11,7 +11,7 @@
 pub mod arena;
 pub mod arena;
 pub mod component; // Logic for extending FC
 pub mod component; // Logic for extending FC
 
 
-pub mod debug_renderer;
+// pub mod debug_renderer;
 pub mod diff;
 pub mod diff;
 pub mod patch; // An "edit phase" described by transitions and edit operations // Test harness for validating that lifecycles and diffs work appropriately
 pub mod patch; // An "edit phase" described by transitions and edit operations // Test harness for validating that lifecycles and diffs work appropriately
                // the diffing algorithm that builds the ChangeList
                // the diffing algorithm that builds the ChangeList
@@ -30,7 +30,6 @@ pub mod builder {
 pub(crate) mod innerlude {
 pub(crate) mod innerlude {
     pub use crate::component::*;
     pub use crate::component::*;
 
 
-    pub use crate::debug_renderer::*;
     pub use crate::diff::*;
     pub use crate::diff::*;
     pub use crate::error::*;
     pub use crate::error::*;
     pub use crate::events::*;
     pub use crate::events::*;
@@ -77,6 +76,6 @@ pub mod prelude {
     pub use crate::diff::DiffMachine;
     pub use crate::diff::DiffMachine;
     pub use crate::virtual_dom::ScopeIdx;
     pub use crate::virtual_dom::ScopeIdx;
 
 
-    pub use crate::debug_renderer::DebugRenderer;
+    // pub use crate::debug_renderer::DebugRenderer;
     pub use crate::hooks::*;
     pub use crate::hooks::*;
 }
 }

+ 19 - 9
packages/core/src/nodes.rs

@@ -7,13 +7,12 @@ use crate::{
     events::VirtualEvent,
     events::VirtualEvent,
     innerlude::{Context, Properties, Scope, ScopeIdx, FC},
     innerlude::{Context, Properties, Scope, ScopeIdx, FC},
     nodebuilder::text3,
     nodebuilder::text3,
-    virtual_dom::NodeCtx,
-    // support::NodeCtx,
+    virtual_dom::{NodeCtx, RealDomNode},
 };
 };
 use bumpalo::Bump;
 use bumpalo::Bump;
 use std::{
 use std::{
     any::Any,
     any::Any,
-    cell::RefCell,
+    cell::{Cell, RefCell},
     fmt::{Arguments, Debug},
     fmt::{Arguments, Debug},
     marker::PhantomData,
     marker::PhantomData,
     rc::Rc,
     rc::Rc,
@@ -29,7 +28,7 @@ pub enum VNode<'src> {
     Element(&'src VElement<'src>),
     Element(&'src VElement<'src>),
 
 
     /// A text node (node type `TEXT_NODE`).
     /// A text node (node type `TEXT_NODE`).
-    Text(&'src str),
+    Text(VText<'src>),
 
 
     /// A fragment is a "virtual position" in the DOM
     /// A fragment is a "virtual position" in the DOM
     /// Fragments may have children and keys
     /// Fragments may have children and keys
@@ -49,7 +48,7 @@ impl<'a> Clone for VNode<'a> {
     fn clone(&self) -> Self {
     fn clone(&self) -> Self {
         match self {
         match self {
             VNode::Element(element) => VNode::Element(element),
             VNode::Element(element) => VNode::Element(element),
-            VNode::Text(text) => VNode::Text(text),
+            VNode::Text(old) => VNode::Text(old.clone()),
             VNode::Fragment(fragment) => VNode::Fragment(fragment),
             VNode::Fragment(fragment) => VNode::Fragment(fragment),
             VNode::Component(component) => VNode::Component(component),
             VNode::Component(component) => VNode::Component(component),
             VNode::Suspended => VNode::Suspended,
             VNode::Suspended => VNode::Suspended,
@@ -81,6 +80,7 @@ impl<'a> VNode<'a> {
             attributes,
             attributes,
             children,
             children,
             namespace,
             namespace,
+            dom_id: Cell::new(RealDomNode::empty()),
         });
         });
         VNode::Element(element)
         VNode::Element(element)
     }
     }
@@ -88,7 +88,10 @@ impl<'a> VNode<'a> {
     /// Construct a new text node with the given text.
     /// Construct a new text node with the given text.
     #[inline]
     #[inline]
     pub fn text(text: &'a str) -> VNode<'a> {
     pub fn text(text: &'a str) -> VNode<'a> {
-        VNode::Text(text)
+        VNode::Text(VText {
+            text,
+            dom_id: Cell::new(RealDomNode::empty()),
+        })
     }
     }
 
 
     pub fn text_args(bump: &'a Bump, args: Arguments) -> VNode<'a> {
     pub fn text_args(bump: &'a Bump, args: Arguments) -> VNode<'a> {
@@ -98,7 +101,7 @@ impl<'a> VNode<'a> {
     #[inline]
     #[inline]
     pub(crate) fn key(&self) -> NodeKey {
     pub(crate) fn key(&self) -> NodeKey {
         match &self {
         match &self {
-            VNode::Text(_) => NodeKey::NONE,
+            VNode::Text { .. } => NodeKey::NONE,
             VNode::Element(e) => e.key,
             VNode::Element(e) => e.key,
             VNode::Fragment(frag) => frag.key,
             VNode::Fragment(frag) => frag.key,
             VNode::Component(c) => c.key,
             VNode::Component(c) => c.key,
@@ -109,6 +112,12 @@ impl<'a> VNode<'a> {
     }
     }
 }
 }
 
 
+#[derive(Clone)]
+pub struct VText<'src> {
+    pub text: &'src str,
+    pub dom_id: Cell<RealDomNode>,
+}
+
 // ========================================================
 // ========================================================
 //   VElement (div, h1, etc), attrs, keys, listener handle
 //   VElement (div, h1, etc), attrs, keys, listener handle
 // ========================================================
 // ========================================================
@@ -120,6 +129,7 @@ pub struct VElement<'a> {
     pub attributes: &'a [Attribute<'a>],
     pub attributes: &'a [Attribute<'a>],
     pub children: &'a [VNode<'a>],
     pub children: &'a [VNode<'a>],
     pub namespace: Option<&'a str>,
     pub namespace: Option<&'a str>,
+    pub dom_id: Cell<RealDomNode>,
 }
 }
 
 
 /// An attribute on a DOM node, such as `id="my-thing"` or
 /// An attribute on a DOM node, such as `id="my-thing"` or
@@ -224,7 +234,7 @@ pub type VCompAssociatedScope = Option<ScopeIdx>;
 pub struct VComponent<'src> {
 pub struct VComponent<'src> {
     pub key: NodeKey<'src>,
     pub key: NodeKey<'src>,
 
 
-    pub stable_addr: RefCell<StableScopeAddres>,
+    pub mounted_root: RealDomNode,
     pub ass_scope: RefCell<VCompAssociatedScope>,
     pub ass_scope: RefCell<VCompAssociatedScope>,
 
 
     // pub comparator: Rc<dyn Fn(&VComponent) -> bool + 'src>,
     // pub comparator: Rc<dyn Fn(&VComponent) -> bool + 'src>,
@@ -325,7 +335,7 @@ impl<'a> VComponent<'a> {
             raw_props,
             raw_props,
             children,
             children,
             caller,
             caller,
-            stable_addr: RefCell::new(None),
+            mounted_root: RealDomNode::empty(),
         }
         }
     }
     }
 }
 }

+ 34 - 15
packages/core/src/virtual_dom.rs

@@ -63,6 +63,14 @@ pub struct VirtualDom {
     _root_prop_type: std::any::TypeId,
     _root_prop_type: std::any::TypeId,
 }
 }
 
 
+#[derive(Clone, Copy)]
+pub struct RealDomNode(u32);
+impl RealDomNode {
+    pub fn empty() -> Self {
+        Self(u32::MIN)
+    }
+}
+
 // ======================================
 // ======================================
 // Public Methods for the VirtualDom
 // Public Methods for the VirtualDom
 // ======================================
 // ======================================
@@ -174,10 +182,15 @@ impl VirtualDom {
             _root_prop_type: TypeId::of::<P>(),
             _root_prop_type: TypeId::of::<P>(),
         }
         }
     }
     }
+}
 
 
+// ======================================
+// Private Methods for the VirtualDom
+// ======================================
+impl VirtualDom {
     /// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch
     /// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch
     /// Currently this doesn't do what we want it to do
     /// Currently this doesn't do what we want it to do
-    pub fn rebuild<'s>(&'s mut self) -> Result<EditList<'s>> {
+    pub fn rebuild<'s, Dom: RealDom>(&'s mut self, realdom: &mut Dom) -> Result<()> {
         let mut diff_machine = DiffMachine::new(
         let mut diff_machine = DiffMachine::new(
             self.components.clone(),
             self.components.clone(),
             self.base_scope,
             self.base_scope,
@@ -193,16 +206,10 @@ impl VirtualDom {
         let update = &base.event_channel;
         let update = &base.event_channel;
         update();
         update();
 
 
-        self.progress_completely(&mut diff_machine)?;
+        self.progress_completely(realdom, &mut diff_machine)?;
 
 
-        Ok(diff_machine.consume())
+        Ok(())
     }
     }
-}
-
-// ======================================
-// Private Methods for the VirtualDom
-// ======================================
-impl VirtualDom {
     /// This method is the most sophisticated way of updating the virtual dom after an external event has been triggered.
     /// This method is the most sophisticated way of updating the virtual dom after an external event has been triggered.
     ///  
     ///  
     /// Given a synthetic event, the component that triggered the event, and the index of the callback, this runs the virtual
     /// Given a synthetic event, the component that triggered the event, and the index of the callback, this runs the virtual
@@ -246,7 +253,11 @@ impl VirtualDom {
     // but the guarantees provide a safe, fast, and efficient abstraction for the VirtualDOM updating framework.
     // but the guarantees provide a safe, fast, and efficient abstraction for the VirtualDOM updating framework.
     //
     //
     // A good project would be to remove all unsafe from this crate and move the unsafety into safer abstractions.
     // A good project would be to remove all unsafe from this crate and move the unsafety into safer abstractions.
-    pub fn progress_with_event(&mut self, event: EventTrigger) -> Result<EditList> {
+    pub fn progress_with_event<Dom: RealDom>(
+        &mut self,
+        realdom: &mut Dom,
+        event: EventTrigger,
+    ) -> Result<()> {
         let id = event.component_id.clone();
         let id = event.component_id.clone();
 
 
         self.components.try_get_mut(id)?.call_listener(event)?;
         self.components.try_get_mut(id)?.call_listener(event)?;
@@ -254,18 +265,19 @@ impl VirtualDom {
         let mut diff_machine =
         let mut diff_machine =
             DiffMachine::new(self.components.clone(), id, self.event_queue.clone());
             DiffMachine::new(self.components.clone(), id, self.event_queue.clone());
 
 
-        self.progress_completely(&mut diff_machine)?;
+        self.progress_completely(realdom, &mut diff_machine)?;
 
 
-        Ok(diff_machine.consume())
+        Ok(())
     }
     }
 
 
     /// Consume the event queue, descending depth-first.
     /// Consume the event queue, descending depth-first.
     /// Only ever run each component once.
     /// Only ever run each component once.
     ///
     ///
     /// The DiffMachine logs its progress as it goes which might be useful for certain types of renderers.
     /// The DiffMachine logs its progress as it goes which might be useful for certain types of renderers.
-    pub(crate) fn progress_completely<'s>(
+    pub(crate) fn progress_completely<'s, Dom: RealDom>(
         &'s mut self,
         &'s mut self,
-        diff_machine: &'_ mut DiffMachine<'s>,
+        realdom: &mut Dom,
+        diff_machine: &'_ mut DiffMachine,
     ) -> Result<()> {
     ) -> Result<()> {
         // Add this component to the list of components that need to be difed
         // Add this component to the list of components that need to be difed
         // #[allow(unused_assignments)]
         // #[allow(unused_assignments)]
@@ -302,7 +314,8 @@ impl VirtualDom {
             cur_component.run_scope()?;
             cur_component.run_scope()?;
             // diff_machine.change_list.load_known_root(1);
             // diff_machine.change_list.load_known_root(1);
 
 
-            diff_machine.diff_node(cur_component.old_frame(), cur_component.next_frame());
+            let (old, new) = cur_component.get_frames_mut();
+            diff_machine.diff_node(realdom, old, new);
 
 
             // cur_height = cur_component.height;
             // cur_height = cur_component.height;
 
 
@@ -530,6 +543,12 @@ impl Scope {
         Ok(())
         Ok(())
     }
     }
 
 
+    fn get_frames_mut<'bump>(
+        &'bump mut self,
+    ) -> (&'bump mut VNode<'bump>, &'bump mut VNode<'bump>) {
+        todo!()
+    }
+
     pub fn next_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
     pub fn next_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
         self.frames.current_head_node()
         self.frames.current_head_node()
     }
     }