Quellcode durchsuchen

wip: compiling again with runtime safety

Jonathan Kelley vor 3 Jahren
Ursprung
Commit
857c92f

+ 1 - 3
packages/core/Cargo.toml

@@ -40,8 +40,6 @@ indexmap = "1.7.0"
 # Serialize the Edits for use in Webview/Liveview instances
 serde = { version = "1", features = ["derive"], optional = true }
 
-serde_repr = { version = "0.1.7", optional = true }
-
 [dev-dependencies]
 anyhow = "1.0.42"
 dioxus-html = { path = "../html" }
@@ -54,7 +52,7 @@ dioxus-core-macro = { path = "../core-macro", version = "0.1.2" }
 
 [features]
 default = []
-serialize = ["serde", "serde_repr"]
+serialize = ["serde"]
 debug_vdom = []
 
 [[bench]]

+ 361 - 229
packages/core/src/diff.rs

@@ -104,11 +104,22 @@ use DomEdit::*;
 ///
 /// Funnily enough, this stack machine's entire job is to create instructions for another stack machine to execute. It's
 /// stack machines all the way down!
-pub(crate) struct DiffMachine<'bump> {
+pub struct DiffState<'bump> {
     pub mutations: Mutations<'bump>,
-    pub stack: DiffStack<'bump>,
+    pub(crate) stack: DiffStack<'bump>,
     pub seen_scopes: FxHashSet<ScopeId>,
-    pub cfg: DiffCfg,
+    pub(crate) cfg: DiffCfg,
+}
+
+impl<'bump> DiffState<'bump> {
+    pub(crate) fn new(mutations: Mutations<'bump>) -> Self {
+        Self {
+            mutations,
+            stack: DiffStack::new(),
+            seen_scopes: Default::default(),
+            cfg: Default::default(),
+        }
+    }
 }
 
 pub(crate) struct DiffCfg {
@@ -136,9 +147,9 @@ impl<'a> SavedDiffWork<'a> {
         std::mem::transmute(self)
     }
 
-    pub unsafe fn promote<'b>(self) -> DiffMachine<'b> {
+    pub unsafe fn promote<'b>(self) -> DiffState<'b> {
         let extended: SavedDiffWork<'b> = std::mem::transmute(self);
-        DiffMachine {
+        DiffState {
             cfg: DiffCfg::default(),
             mutations: extended.mutations,
             stack: extended.stack,
@@ -147,29 +158,30 @@ impl<'a> SavedDiffWork<'a> {
     }
 }
 
-impl<'bump> DiffMachine<'bump> {
-    pub(crate) fn new(mutations: Mutations<'bump>) -> Self {
-        Self {
-            mutations,
-            cfg: DiffCfg::default(),
-            stack: DiffStack::new(),
-            seen_scopes: FxHashSet::default(),
-        }
-    }
-
-    pub fn save(self) -> SavedDiffWork<'bump> {
-        SavedDiffWork {
-            mutations: self.mutations,
-            stack: self.stack,
-            seen_scopes: self.seen_scopes,
-        }
-    }
-
-    pub fn diff_scope(&mut self, id: ScopeId) {
-        if let Some(component) = self.vdom.get_scope_mut(&id) {
+impl<'bump> VirtualDom {
+    // impl<'bump> DiffState<'bump> {
+    // pub(crate) fn new(mutations: Mutations<'bump>) -> Self {
+    //     Self {
+    //         mutations,
+    //         cfg: DiffCfg::default(),
+    //         stack: DiffStack::new(),
+    //         seen_scopes: FxHashSet::default(),
+    //     }
+    // }
+
+    // pub fn save(self) -> SavedDiffWork<'bump> {
+    //     SavedDiffWork {
+    //         mutations: state.mutations,
+    //         stack: state.stack,
+    //         seen_scopes: self.seen_scopes,
+    //     }
+    // }
+
+    pub fn diff_scope(&'bump self, state: &mut DiffState<'bump>, id: ScopeId) {
+        if let Some(component) = self.get_scope_mut(&id) {
             let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
-            self.stack.push(DiffInstruction::Diff { new, old });
-            self.work(|| false);
+            state.stack.push(DiffInstruction::Diff { new, old });
+            self.work(state, || false);
         }
     }
 
@@ -180,17 +192,21 @@ impl<'bump> DiffMachine<'bump> {
     /// We do depth-first to maintain high cache locality (nodes were originally generated recursively).
     ///
     /// Returns a `bool` indicating that the work completed properly.
-    pub fn work(&mut self, mut deadline_expired: impl FnMut() -> bool) -> bool {
-        while let Some(instruction) = self.stack.pop() {
+    pub fn work(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        mut deadline_expired: impl FnMut() -> bool,
+    ) -> bool {
+        while let Some(instruction) = state.stack.pop() {
             match instruction {
-                DiffInstruction::Diff { old, new } => self.diff_node(old, new),
-                DiffInstruction::Create { node } => self.create_node(node),
-                DiffInstruction::Mount { and } => self.mount(and),
+                DiffInstruction::Diff { old, new } => self.diff_node(state, old, new),
+                DiffInstruction::Create { node } => self.create_node(state, node),
+                DiffInstruction::Mount { and } => self.mount(state, and),
                 DiffInstruction::PrepareMove { node } => {
-                    let num_on_stack = self.push_all_nodes(node);
-                    self.stack.add_child_count(num_on_stack);
+                    let num_on_stack = self.push_all_nodes(state, node);
+                    state.stack.add_child_count(num_on_stack);
                 }
-                DiffInstruction::PopScope => self.stack.pop_off_scope(),
+                DiffInstruction::PopScope => state.stack.pop_off_scope(),
             };
 
             if deadline_expired() {
@@ -203,66 +219,73 @@ impl<'bump> DiffMachine<'bump> {
     }
 
     // recursively push all the nodes of a tree onto the stack and return how many are there
-    fn push_all_nodes(&mut self, node: &'bump VNode<'bump>) -> usize {
+    fn push_all_nodes(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        node: &'bump VNode<'bump>,
+    ) -> usize {
         match node {
             VNode::Text(_) | VNode::Anchor(_) | VNode::Suspended(_) => {
-                self.mutations.push_root(node.mounted_id());
+                state.mutations.push_root(node.mounted_id());
                 1
             }
 
-            VNode::Fragment(_) | VNode::Component(_) => node
-                .children()
-                .iter()
-                .map(|child| self.push_all_nodes(child))
-                .sum(),
+            VNode::Fragment(_) | VNode::Component(_) => {
+                //
+                let mut added = 0;
+                for child in node.children() {
+                    added += self.push_all_nodes(state, child);
+                }
+                added
+            }
 
             VNode::Element(el) => {
                 let mut num_on_stack = 0;
                 for child in el.children.iter() {
-                    num_on_stack += self.push_all_nodes(child);
+                    num_on_stack += self.push_all_nodes(state, child);
                 }
-                self.mutations.push_root(el.dom_id.get().unwrap());
+                state.mutations.push_root(el.dom_id.get().unwrap());
 
                 num_on_stack + 1
             }
         }
     }
 
-    fn mount(&mut self, and: MountType<'bump>) {
-        let nodes_created = self.stack.pop_nodes_created();
+    fn mount(&'bump self, state: &mut DiffState<'bump>, and: MountType<'bump>) {
+        let nodes_created = state.stack.pop_nodes_created();
         match and {
             // add the nodes from this virtual list to the parent
             // used by fragments and components
             MountType::Absorb => {
-                self.stack.add_child_count(nodes_created);
+                state.stack.add_child_count(nodes_created);
             }
 
             MountType::Replace { old } => {
                 if let Some(old_id) = old.try_mounted_id() {
-                    self.mutations.replace_with(old_id, nodes_created as u32);
-                    self.remove_nodes(Some(old), true);
+                    state.mutations.replace_with(old_id, nodes_created as u32);
+                    self.remove_nodes(state, Some(old), true);
                 } else {
-                    if let Some(id) = self.find_first_element_id(old) {
-                        self.mutations.replace_with(id, nodes_created as u32);
+                    if let Some(id) = self.find_first_element_id(state, old) {
+                        state.mutations.replace_with(id, nodes_created as u32);
                     }
-                    self.remove_nodes(Some(old), true);
+                    self.remove_nodes(state, Some(old), true);
                 }
             }
 
             MountType::Append => {
-                self.mutations.edits.push(AppendChildren {
+                state.mutations.edits.push(AppendChildren {
                     many: nodes_created as u32,
                 });
             }
 
             MountType::InsertAfter { other_node } => {
-                let root = self.find_last_element(other_node).unwrap();
-                self.mutations.insert_after(root, nodes_created as u32);
+                let root = self.find_last_element(state, other_node).unwrap();
+                state.mutations.insert_after(root, nodes_created as u32);
             }
 
             MountType::InsertBefore { other_node } => {
-                let root = self.find_first_element_id(other_node).unwrap();
-                self.mutations.insert_before(root, nodes_created as u32);
+                let root = self.find_first_element_id(state, other_node).unwrap();
+                state.mutations.insert_before(root, nodes_created as u32);
             }
         }
     }
@@ -271,42 +294,62 @@ impl<'bump> DiffMachine<'bump> {
     //  Tools for creating new nodes
     // =================================
 
-    fn create_node(&mut self, node: &'bump VNode<'bump>) {
+    fn create_node(&'bump self, state: &mut DiffState<'bump>, node: &'bump VNode<'bump>) {
         match node {
-            VNode::Text(vtext) => self.create_text_node(vtext, node),
-            VNode::Suspended(suspended) => self.create_suspended_node(suspended, node),
-            VNode::Anchor(anchor) => self.create_anchor_node(anchor, node),
-            VNode::Element(element) => self.create_element_node(element, node),
-            VNode::Fragment(frag) => self.create_fragment_node(frag),
-            VNode::Component(component) => self.create_component_node(component),
+            VNode::Text(vtext) => self.create_text_node(state, vtext, node),
+            VNode::Suspended(suspended) => self.create_suspended_node(state, suspended, node),
+            VNode::Anchor(anchor) => self.create_anchor_node(state, anchor, node),
+            VNode::Element(element) => self.create_element_node(state, element, node),
+            VNode::Fragment(frag) => self.create_fragment_node(state, frag),
+            VNode::Component(component) => self.create_component_node(state, component),
         }
     }
 
-    fn create_text_node(&mut self, vtext: &'bump VText<'bump>, node: &'bump VNode<'bump>) {
-        let real_id = self.vdom.reserve_node(node);
-        self.mutations.create_text_node(vtext.text, real_id);
+    fn create_text_node(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        vtext: &'bump VText<'bump>,
+        node: &'bump VNode<'bump>,
+    ) {
+        let real_id = self.reserve_node(node);
+        state.mutations.create_text_node(vtext.text, real_id);
         vtext.dom_id.set(Some(real_id));
-        self.stack.add_child_count(1);
+        state.stack.add_child_count(1);
     }
 
-    fn create_suspended_node(&mut self, suspended: &'bump VSuspended, node: &'bump VNode<'bump>) {
-        let real_id = self.vdom.reserve_node(node);
-        self.mutations.create_placeholder(real_id);
+    fn create_suspended_node(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        suspended: &'bump VSuspended,
+        node: &'bump VNode<'bump>,
+    ) {
+        let real_id = self.reserve_node(node);
+        state.mutations.create_placeholder(real_id);
 
         suspended.dom_id.set(Some(real_id));
-        self.stack.add_child_count(1);
+        state.stack.add_child_count(1);
 
-        self.attach_suspended_node_to_scope(suspended);
+        self.attach_suspended_node_to_scope(state, suspended);
     }
 
-    fn create_anchor_node(&mut self, anchor: &'bump VAnchor, node: &'bump VNode<'bump>) {
-        let real_id = self.vdom.reserve_node(node);
-        self.mutations.create_placeholder(real_id);
+    fn create_anchor_node(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        anchor: &'bump VAnchor,
+        node: &'bump VNode<'bump>,
+    ) {
+        let real_id = self.reserve_node(node);
+        state.mutations.create_placeholder(real_id);
         anchor.dom_id.set(Some(real_id));
-        self.stack.add_child_count(1);
+        state.stack.add_child_count(1);
     }
 
-    fn create_element_node(&mut self, element: &'bump VElement<'bump>, node: &'bump VNode<'bump>) {
+    fn create_element_node(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        element: &'bump VElement<'bump>,
+        node: &'bump VNode<'bump>,
+    ) {
         let VElement {
             tag_name,
             listeners,
@@ -317,65 +360,81 @@ impl<'bump> DiffMachine<'bump> {
             ..
         } = element;
 
-        let real_id = self.vdom.reserve_node(node);
+        let real_id = self.reserve_node(node);
 
         dom_id.set(Some(real_id));
 
-        self.mutations.create_element(tag_name, *namespace, real_id);
+        state
+            .mutations
+            .create_element(tag_name, *namespace, real_id);
 
-        self.stack.add_child_count(1);
+        state.stack.add_child_count(1);
 
-        if let Some(cur_scope_id) = self.stack.current_scope() {
-            let scope = self.vdom.get_scope_mut(&cur_scope_id).unwrap();
+        if let Some(cur_scope_id) = state.stack.current_scope() {
+            let scope = self.get_scope_mut(&cur_scope_id).unwrap();
 
-            listeners.iter().for_each(|listener| {
-                self.attach_listener_to_scope(listener, scope);
+            for listener in *listeners {
+                self.attach_listener_to_scope(state, listener, scope);
                 listener.mounted_node.set(Some(real_id));
-                self.mutations.new_event_listener(listener, cur_scope_id);
-            });
+                state.mutations.new_event_listener(listener, cur_scope_id);
+            }
         } else {
             log::warn!("create element called with no scope on the stack - this is an error for a live dom");
         }
 
         for attr in *attributes {
-            self.mutations.set_attribute(attr, real_id.as_u64());
+            state.mutations.set_attribute(attr, real_id.as_u64());
         }
 
         if !children.is_empty() {
-            self.stack.create_children(children, MountType::Append);
+            state.stack.create_children(children, MountType::Append);
         }
     }
 
-    fn create_fragment_node(&mut self, frag: &'bump VFragment<'bump>) {
-        self.stack.create_children(frag.children, MountType::Absorb);
+    fn create_fragment_node(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        frag: &'bump VFragment<'bump>,
+    ) {
+        state
+            .stack
+            .create_children(frag.children, MountType::Absorb);
     }
 
-    fn create_component_node(&mut self, vcomponent: &'bump VComponent<'bump>) {
+    fn create_component_node(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        vcomponent: &'bump VComponent<'bump>,
+    ) {
         // let caller = vcomponent.caller;
 
-        let parent_idx = self.stack.current_scope().unwrap();
+        let parent_idx = state.stack.current_scope().unwrap();
 
-        let shared = self.vdom.channel.clone();
+        let shared = self.sender.clone();
 
         // Insert a new scope into our component list
-        let parent_scope = self.vdom.get_scope(&parent_idx).unwrap();
-
-        let new_idx = self.vdom.insert_scope_with_key(|new_idx| {
-            ScopeInner::new(
-                vcomponent,
-                new_idx,
-                Some(parent_idx),
-                parent_scope.height + 1,
-                parent_scope.subtree(),
-                shared,
-            )
-        });
+        let parent_scope = self.get_scope(&parent_idx).unwrap();
+
+        let new_idx: ScopeId = todo!();
+        // self.scopes
+        //     .new_with_key(fc_ptr, vcomp, parent_scope, height, subtree, sender);
+
+        // .(|new_idx| {
+        //     // ScopeInner::new(
+        //         vcomponent,
+        //         new_idx,
+        //         Some(parent_idx),
+        //         parent_scope.height + 1,
+        //         parent_scope.subtree(),
+        //         shared,
+        //     // )
+        // });
 
         // Actually initialize the caller's slot with the right address
         vcomponent.associated_scope.set(Some(new_idx));
 
         if !vcomponent.can_memoize {
-            let cur_scope = self.vdom.get_scope_mut(&parent_idx).unwrap();
+            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) };
 
@@ -386,7 +445,7 @@ impl<'bump> DiffMachine<'bump> {
         //  add noderefs to current noderef list Noderefs
         //  add effects to current effect list Effects
 
-        let new_component = self.vdom.get_scope_mut(&new_idx).unwrap();
+        let new_component = self.get_scope_mut(&new_idx).unwrap();
 
         log::debug!(
             "initializing component {:?} with height {:?}",
@@ -395,58 +454,72 @@ impl<'bump> DiffMachine<'bump> {
         );
 
         // Run the scope for one iteration to initialize it
-        if new_component.run_scope(self.vdom) {
-            // Take the node that was just generated from running the component
-            let nextnode = new_component.frames.fin_head();
-            self.stack.create_component(new_idx, nextnode);
+        //
+        todo!("run scope");
+        // if new_component.run_scope(self) {
+        //     // Take the node that was just generated from running the component
+        //     let nextnode = new_component.frames.fin_head();
+        //     state.stack.create_component(new_idx, nextnode);
 
-            //
-            /*
-            tree_item {
+        //     //
+        //     /*
+        //     tree_item {
 
-            }
+        //     }
 
-            */
-            if new_component.is_subtree_root.get() {
-                self.stack.push_subtree();
-            }
-        }
+        //     */
+        //     if new_component.is_subtree_root.get() {
+        //         state.stack.push_subtree();
+        //     }
+        // }
 
         // Finally, insert this scope as a seen node.
-        self.seen_scopes.insert(new_idx);
+        state.seen_scopes.insert(new_idx);
     }
 
     // =================================
     //  Tools for diffing nodes
     // =================================
 
-    pub fn diff_node(&mut self, old_node: &'bump VNode<'bump>, new_node: &'bump VNode<'bump>) {
+    pub fn diff_node(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        old_node: &'bump VNode<'bump>,
+        new_node: &'bump VNode<'bump>,
+    ) {
         use VNode::*;
         match (old_node, new_node) {
             // Check the most common cases first
-            (Text(old), Text(new)) => self.diff_text_nodes(old, new),
+            (Text(old), Text(new)) => self.diff_text_nodes(state, old, new),
             (Component(old), Component(new)) => {
-                self.diff_component_nodes(old_node, new_node, old, new)
+                self.diff_component_nodes(state, old_node, new_node, old, new)
             }
-            (Fragment(old), Fragment(new)) => self.diff_fragment_nodes(old, new),
+            (Fragment(old), Fragment(new)) => self.diff_fragment_nodes(state, old, new),
             (Anchor(old), Anchor(new)) => new.dom_id.set(old.dom_id.get()),
-            (Suspended(old), Suspended(new)) => self.diff_suspended_nodes(old, new),
-            (Element(old), Element(new)) => self.diff_element_nodes(old, new, old_node, new_node),
+            (Suspended(old), Suspended(new)) => self.diff_suspended_nodes(state, old, new),
+            (Element(old), Element(new)) => {
+                self.diff_element_nodes(state, old, new, old_node, new_node)
+            }
 
             // Anything else is just a basic replace and create
             (
                 Component(_) | Fragment(_) | Text(_) | Element(_) | Anchor(_) | Suspended(_),
                 Component(_) | Fragment(_) | Text(_) | Element(_) | Anchor(_) | Suspended(_),
-            ) => self
+            ) => state
                 .stack
                 .create_node(new_node, MountType::Replace { old: old_node }),
         }
     }
 
-    fn diff_text_nodes(&mut self, old: &'bump VText<'bump>, new: &'bump VText<'bump>) {
+    fn diff_text_nodes(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        old: &'bump VText<'bump>,
+        new: &'bump VText<'bump>,
+    ) {
         if let Some(root) = old.dom_id.get() {
             if old.text != new.text {
-                self.mutations.set_text(new.text, root.as_u64());
+                state.mutations.set_text(new.text, root.as_u64());
             }
 
             new.dom_id.set(Some(root));
@@ -454,7 +527,8 @@ impl<'bump> DiffMachine<'bump> {
     }
 
     fn diff_element_nodes(
-        &mut self,
+        &'bump self,
+        state: &mut DiffState<'bump>,
         old: &'bump VElement<'bump>,
         new: &'bump VElement<'bump>,
         old_node: &'bump VNode<'bump>,
@@ -469,11 +543,11 @@ impl<'bump> DiffMachine<'bump> {
         if new.tag_name != old.tag_name || new.namespace != old.namespace {
             // maybe make this an instruction?
             // issue is that we need the "vnode" but this method only has the velement
-            self.stack.push_nodes_created(0);
-            self.stack.push(DiffInstruction::Mount {
+            state.stack.push_nodes_created(0);
+            state.stack.push(DiffInstruction::Mount {
                 and: MountType::Replace { old: old_node },
             });
-            self.create_element_node(new, new_node);
+            self.create_element_node(state, new, new_node);
             return;
         }
 
@@ -493,15 +567,15 @@ impl<'bump> DiffMachine<'bump> {
         if old.attributes.len() == new.attributes.len() {
             for (old_attr, new_attr) in old.attributes.iter().zip(new.attributes.iter()) {
                 if old_attr.value != new_attr.value || new_attr.is_volatile {
-                    self.mutations.set_attribute(new_attr, root.as_u64());
+                    state.mutations.set_attribute(new_attr, root.as_u64());
                 }
             }
         } else {
             for attribute in old.attributes {
-                self.mutations.remove_attribute(attribute, root.as_u64());
+                state.mutations.remove_attribute(attribute, root.as_u64());
             }
             for attribute in new.attributes {
-                self.mutations.set_attribute(attribute, root.as_u64())
+                state.mutations.set_attribute(attribute, root.as_u64())
             }
         }
 
@@ -513,44 +587,47 @@ impl<'bump> DiffMachine<'bump> {
         // We also need to make sure that all listeners are properly attached to the parent scope (fix_listener)
         //
         // TODO: take a more efficient path than this
-        if let Some(cur_scope_id) = self.stack.current_scope() {
-            let scope = self.vdom.get_scope_mut(&cur_scope_id).unwrap();
+        if let Some(cur_scope_id) = state.stack.current_scope() {
+            let scope = self.get_scope_mut(&cur_scope_id).unwrap();
 
             if old.listeners.len() == new.listeners.len() {
                 for (old_l, new_l) in old.listeners.iter().zip(new.listeners.iter()) {
                     if old_l.event != new_l.event {
-                        self.mutations
+                        state
+                            .mutations
                             .remove_event_listener(old_l.event, root.as_u64());
-                        self.mutations.new_event_listener(new_l, cur_scope_id);
+                        state.mutations.new_event_listener(new_l, cur_scope_id);
                     }
                     new_l.mounted_node.set(old_l.mounted_node.get());
-                    self.attach_listener_to_scope(new_l, scope);
+                    self.attach_listener_to_scope(state, new_l, scope);
                 }
             } else {
                 for listener in old.listeners {
-                    self.mutations
+                    state
+                        .mutations
                         .remove_event_listener(listener.event, root.as_u64());
                 }
                 for listener in new.listeners {
                     listener.mounted_node.set(Some(root));
-                    self.mutations.new_event_listener(listener, cur_scope_id);
-                    self.attach_listener_to_scope(listener, scope);
+                    state.mutations.new_event_listener(listener, cur_scope_id);
+                    self.attach_listener_to_scope(state, listener, scope);
                 }
             }
         }
 
         if old.children.is_empty() && !new.children.is_empty() {
-            self.mutations.edits.push(PushRoot {
+            state.mutations.edits.push(PushRoot {
                 root: root.as_u64(),
             });
-            self.stack.create_children(new.children, MountType::Append);
+            state.stack.create_children(new.children, MountType::Append);
         } else {
-            self.diff_children(old.children, new.children);
+            self.diff_children(state, old.children, new.children);
         }
     }
 
     fn diff_component_nodes(
-        &mut self,
+        &'bump self,
+        state: &mut DiffState<'bump>,
         old_node: &'bump VNode<'bump>,
         new_node: &'bump VNode<'bump>,
 
@@ -563,13 +640,13 @@ impl<'bump> DiffMachine<'bump> {
         if old.user_fc == new.user_fc {
             log::debug!("Diffing component {:?} - {:?}", new.user_fc, scope_addr);
             //
-            self.stack.scope_stack.push(scope_addr);
+            state.stack.scope_stack.push(scope_addr);
 
             // Make sure the new component vnode is referencing the right scope id
             new.associated_scope.set(Some(scope_addr));
 
             // make sure the component's caller function is up to date
-            let scope = self.vdom.get_scope_mut(&scope_addr).unwrap();
+            let scope = self.get_scope_mut(&scope_addr).unwrap();
             scope.update_vcomp(new);
 
             // React doesn't automatically memoize, but we do.
@@ -578,37 +655,48 @@ impl<'bump> DiffMachine<'bump> {
             // let props_are_the_same = old.comparator.unwrap();
 
             // if self.cfg.force_diff || !props_are_the_same(new) {
-            //     let succeeded = scope.run_scope(self.vdom);
+            //     let succeeded = scope.run_scope(self);
 
             //     if succeeded {
             //         self.diff_node(scope.frames.wip_head(), scope.frames.fin_head());
             //     }
             // }
 
-            self.stack.scope_stack.pop();
+            state.stack.scope_stack.pop();
         } else {
-            self.stack
+            state
+                .stack
                 .create_node(new_node, MountType::Replace { old: old_node });
         }
     }
 
-    fn diff_fragment_nodes(&mut self, old: &'bump VFragment<'bump>, new: &'bump VFragment<'bump>) {
+    fn diff_fragment_nodes(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        old: &'bump VFragment<'bump>,
+        new: &'bump VFragment<'bump>,
+    ) {
         // This is the case where options or direct vnodes might be used.
         // In this case, it's faster to just skip ahead to their diff
         if old.children.len() == 1 && new.children.len() == 1 {
-            self.diff_node(&old.children[0], &new.children[0]);
+            self.diff_node(state, &old.children[0], &new.children[0]);
             return;
         }
 
         debug_assert!(!old.children.is_empty());
         debug_assert!(!new.children.is_empty());
 
-        self.diff_children(old.children, new.children);
+        self.diff_children(state, old.children, new.children);
     }
 
-    fn diff_suspended_nodes(&mut self, old: &'bump VSuspended, new: &'bump VSuspended) {
+    fn diff_suspended_nodes(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        old: &'bump VSuspended,
+        new: &'bump VSuspended,
+    ) {
         new.dom_id.set(old.dom_id.get());
-        self.attach_suspended_node_to_scope(new);
+        self.attach_suspended_node_to_scope(state, new);
     }
 
     // =============================================
@@ -630,26 +718,32 @@ impl<'bump> DiffMachine<'bump> {
     //
     // Fragment nodes cannot generate empty children lists, so we can assume that when a list is empty, it belongs only
     // to an element, and appending makes sense.
-    fn diff_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
+    fn diff_children(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        old: &'bump [VNode<'bump>],
+        new: &'bump [VNode<'bump>],
+    ) {
         // Remember, fragments can never be empty (they always have a single child)
         match (old, new) {
             ([], []) => {}
             ([], _) => {
                 // we need to push the
-                self.stack.create_children(new, MountType::Append);
+                state.stack.create_children(new, MountType::Append);
             }
             (_, []) => {
-                self.remove_nodes(old, true);
+                self.remove_nodes(state, old, true);
             }
             ([VNode::Anchor(old_anchor)], [VNode::Anchor(new_anchor)]) => {
                 old_anchor.dom_id.set(new_anchor.dom_id.get());
             }
             ([VNode::Anchor(_)], _) => {
-                self.stack
+                state
+                    .stack
                     .create_children(new, MountType::Replace { old: &old[0] });
             }
             (_, [VNode::Anchor(_)]) => {
-                self.replace_and_create_many_with_one(old, &new[0]);
+                self.replace_and_create_many_with_one(state, old, &new[0]);
             }
             _ => {
                 let new_is_keyed = new[0].key().is_some();
@@ -665,9 +759,9 @@ impl<'bump> DiffMachine<'bump> {
                 );
 
                 if new_is_keyed && old_is_keyed {
-                    self.diff_keyed_children(old, new);
+                    self.diff_keyed_children(state, old, new);
                 } else {
-                    self.diff_non_keyed_children(old, new);
+                    self.diff_non_keyed_children(state, old, new);
                 }
             }
         }
@@ -681,20 +775,25 @@ impl<'bump> DiffMachine<'bump> {
     //     [... parent]
     //
     // the change list stack is in the same state when this function returns.
-    fn diff_non_keyed_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
+    fn diff_non_keyed_children(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        old: &'bump [VNode<'bump>],
+        new: &'bump [VNode<'bump>],
+    ) {
         // Handled these cases in `diff_children` before calling this function.
         debug_assert!(!new.is_empty());
         debug_assert!(!old.is_empty());
 
         for (new, old) in new.iter().zip(old.iter()).rev() {
-            self.stack.push(DiffInstruction::Diff { new, old });
+            state.stack.push(DiffInstruction::Diff { new, old });
         }
 
         use std::cmp::Ordering;
         match old.len().cmp(&new.len()) {
-            Ordering::Greater => self.remove_nodes(&old[new.len()..], true),
+            Ordering::Greater => self.remove_nodes(state, &old[new.len()..], true),
             Ordering::Less => {
-                self.stack.create_children(
+                state.stack.create_children(
                     &new[old.len()..],
                     MountType::InsertAfter {
                         other_node: old.last().unwrap(),
@@ -723,7 +822,12 @@ impl<'bump> DiffMachine<'bump> {
     // https://github.com/infernojs/inferno/blob/36fd96/packages/inferno/src/DOM/patching.ts#L530-L739
     //
     // The stack is empty upon entry.
-    fn diff_keyed_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
+    fn diff_keyed_children(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        old: &'bump [VNode<'bump>],
+        new: &'bump [VNode<'bump>],
+    ) {
         if cfg!(debug_assertions) {
             let mut keys = fxhash::FxHashSet::default();
             let mut assert_unique_keys = |children: &'bump [VNode<'bump>]| {
@@ -751,7 +855,7 @@ impl<'bump> DiffMachine<'bump> {
         //
         // `shared_prefix_count` is the count of how many nodes at the start of
         // `new` and `old` share the same keys.
-        let (left_offset, right_offset) = match self.diff_keyed_ends(old, new) {
+        let (left_offset, right_offset) = match self.diff_keyed_ends(state, old, new) {
             Some(count) => count,
             None => return,
         };
@@ -761,7 +865,7 @@ impl<'bump> DiffMachine<'bump> {
         //     right_offset,
         // );
 
-        // log::debug!("stack before lo is {:#?}", self.stack.instructions);
+        // log::debug!("stack before lo is {:#?}", state.stack.instructions);
         // Ok, we now hopefully have a smaller range of children in the middle
         // within which to re-order nodes with the same keys, remove old nodes with
         // now-unused keys, and create new nodes with fresh keys.
@@ -775,14 +879,14 @@ impl<'bump> DiffMachine<'bump> {
         );
         if new_middle.is_empty() {
             // remove the old elements
-            self.remove_nodes(old_middle, true);
+            self.remove_nodes(state, old_middle, true);
         } else if old_middle.is_empty() {
             // there were no old elements, so just create the new elements
             // we need to find the right "foothold" though - we shouldn't use the "append" at all
             if left_offset == 0 {
                 // insert at the beginning of the old list
                 let foothold = &old[old.len() - right_offset];
-                self.stack.create_children(
+                state.stack.create_children(
                     new_middle,
                     MountType::InsertBefore {
                         other_node: foothold,
@@ -791,7 +895,7 @@ impl<'bump> DiffMachine<'bump> {
             } else if right_offset == 0 {
                 // insert at the end  the old list
                 let foothold = old.last().unwrap();
-                self.stack.create_children(
+                state.stack.create_children(
                     new_middle,
                     MountType::InsertAfter {
                         other_node: foothold,
@@ -800,7 +904,7 @@ impl<'bump> DiffMachine<'bump> {
             } else {
                 // inserting in the middle
                 let foothold = &old[left_offset - 1];
-                self.stack.create_children(
+                state.stack.create_children(
                     new_middle,
                     MountType::InsertAfter {
                         other_node: foothold,
@@ -808,10 +912,10 @@ impl<'bump> DiffMachine<'bump> {
                 );
             }
         } else {
-            self.diff_keyed_middle(old_middle, new_middle);
+            self.diff_keyed_middle(state, old_middle, new_middle);
         }
 
-        log::debug!("stack after km is {:#?}", self.stack.instructions);
+        log::debug!("stack after km is {:#?}", state.stack.instructions);
     }
 
     /// Diff both ends of the children that share keys.
@@ -820,7 +924,8 @@ impl<'bump> DiffMachine<'bump> {
     ///
     /// If there is no offset, then this function returns None and the diffing is complete.
     fn diff_keyed_ends(
-        &mut self,
+        &'bump self,
+        state: &mut DiffState<'bump>,
         old: &'bump [VNode<'bump>],
         new: &'bump [VNode<'bump>],
     ) -> Option<(usize, usize)> {
@@ -831,14 +936,14 @@ impl<'bump> DiffMachine<'bump> {
             if old.key() != new.key() {
                 break;
             }
-            self.stack.push(DiffInstruction::Diff { old, new });
+            state.stack.push(DiffInstruction::Diff { old, new });
             left_offset += 1;
         }
 
         // If that was all of the old children, then create and append the remaining
         // new children and we're finished.
         if left_offset == old.len() {
-            self.stack.create_children(
+            state.stack.create_children(
                 &new[left_offset..],
                 MountType::InsertAfter {
                     other_node: old.last().unwrap(),
@@ -850,7 +955,7 @@ impl<'bump> DiffMachine<'bump> {
         // And if that was all of the new children, then remove all of the remaining
         // old children and we're finished.
         if left_offset == new.len() {
-            self.remove_nodes(&old[left_offset..], true);
+            self.remove_nodes(state, &old[left_offset..], true);
             return None;
         }
 
@@ -861,7 +966,7 @@ impl<'bump> DiffMachine<'bump> {
             if old.key() != new.key() {
                 break;
             }
-            self.diff_node(old, new);
+            self.diff_node(state, old, new);
             right_offset += 1;
         }
 
@@ -881,7 +986,12 @@ impl<'bump> DiffMachine<'bump> {
     // This function will load the appropriate nodes onto the stack and do diffing in place.
     //
     // Upon exit from this function, it will be restored to that same state.
-    fn diff_keyed_middle(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) {
+    fn diff_keyed_middle(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        old: &'bump [VNode<'bump>],
+        new: &'bump [VNode<'bump>],
+    ) {
         /*
         1. Map the old keys into a numerical ordering based on indices.
         2. Create a map of old key to its index
@@ -945,7 +1055,7 @@ impl<'bump> DiffMachine<'bump> {
             log::debug!("old_key_to_old_index, {:#?}", old_key_to_old_index);
             log::debug!("new_index_to_old_index, {:#?}", new_index_to_old_index);
             log::debug!("shared_keys, {:#?}", shared_keys);
-            self.replace_and_create_many_with_many(old, new);
+            self.replace_and_create_many_with_many(state, old, new);
             return;
         }
 
@@ -989,15 +1099,15 @@ impl<'bump> DiffMachine<'bump> {
         // add mount instruction for the last items not covered by the lis
         let first_lis = *lis_sequence.first().unwrap();
         if first_lis > 0 {
-            self.stack.push_nodes_created(0);
-            self.stack.push(DiffInstruction::Mount {
+            state.stack.push_nodes_created(0);
+            state.stack.push(DiffInstruction::Mount {
                 and: MountType::InsertBefore {
                     other_node: &new[first_lis],
                 },
             });
 
             for (idx, new_node) in new[..first_lis].iter().enumerate().rev() {
-                apply(idx, new_node, &mut self.stack);
+                apply(idx, new_node, &mut state.stack);
             }
         }
 
@@ -1006,14 +1116,14 @@ impl<'bump> DiffMachine<'bump> {
         let mut last = *lis_iter.next().unwrap();
         for next in lis_iter {
             if last - next > 1 {
-                self.stack.push_nodes_created(0);
-                self.stack.push(DiffInstruction::Mount {
+                state.stack.push_nodes_created(0);
+                state.stack.push(DiffInstruction::Mount {
                     and: MountType::InsertBefore {
                         other_node: &new[last],
                     },
                 });
                 for (idx, new_node) in new[(next + 1)..last].iter().enumerate().rev() {
-                    apply(idx + next + 1, new_node, &mut self.stack);
+                    apply(idx + next + 1, new_node, &mut state.stack);
                 }
             }
             last = *next;
@@ -1022,19 +1132,19 @@ impl<'bump> DiffMachine<'bump> {
         // add mount instruction for the first items not covered by the lis
         let last = *lis_sequence.last().unwrap();
         if last < (new.len() - 1) {
-            self.stack.push_nodes_created(0);
-            self.stack.push(DiffInstruction::Mount {
+            state.stack.push_nodes_created(0);
+            state.stack.push(DiffInstruction::Mount {
                 and: MountType::InsertAfter {
                     other_node: &new[last],
                 },
             });
             for (idx, new_node) in new[(last + 1)..].iter().enumerate().rev() {
-                apply(idx + last + 1, new_node, &mut self.stack);
+                apply(idx + last + 1, new_node, &mut state.stack);
             }
         }
 
         for idx in lis_sequence.iter().rev() {
-            self.stack.push(DiffInstruction::Diff {
+            state.stack.push(DiffInstruction::Diff {
                 new: &new[*idx],
                 old: &old[new_index_to_old_index[*idx]],
             });
@@ -1045,7 +1155,11 @@ impl<'bump> DiffMachine<'bump> {
     //  Utilities
     // =====================
 
-    fn find_last_element(&mut self, vnode: &'bump VNode<'bump>) -> Option<ElementId> {
+    fn find_last_element(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        vnode: &'bump VNode<'bump>,
+    ) -> Option<ElementId> {
         let mut search_node = Some(vnode);
 
         loop {
@@ -1060,14 +1174,18 @@ impl<'bump> DiffMachine<'bump> {
                 }
                 VNode::Component(el) => {
                     let scope_id = el.associated_scope.get().unwrap();
-                    let scope = self.vdom.get_scope(&scope_id).unwrap();
+                    let scope = self.get_scope(&scope_id).unwrap();
                     search_node = Some(scope.root_node());
                 }
             }
         }
     }
 
-    fn find_first_element_id(&mut self, vnode: &'bump VNode<'bump>) -> Option<ElementId> {
+    fn find_first_element_id(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        vnode: &'bump VNode<'bump>,
+    ) -> Option<ElementId> {
         let mut search_node = Some(vnode);
 
         loop {
@@ -1078,7 +1196,7 @@ impl<'bump> DiffMachine<'bump> {
                 }
                 VNode::Component(el) => {
                     let scope_id = el.associated_scope.get().unwrap();
-                    let scope = self.vdom.get_scope(&scope_id).unwrap();
+                    let scope = self.get_scope(&scope_id).unwrap();
                     search_node = Some(scope.root_node());
                 }
                 VNode::Text(t) => break t.dom_id.get(),
@@ -1090,23 +1208,26 @@ impl<'bump> DiffMachine<'bump> {
     }
 
     fn replace_and_create_many_with_one(
-        &mut self,
+        &'bump self,
+        state: &mut DiffState<'bump>,
         old: &'bump [VNode<'bump>],
         new: &'bump VNode<'bump>,
     ) {
         if let Some(first_old) = old.get(0) {
-            self.remove_nodes(&old[1..], true);
-            self.stack
+            self.remove_nodes(state, &old[1..], true);
+            state
+                .stack
                 .create_node(new, MountType::Replace { old: first_old });
         } else {
-            self.stack.create_node(new, MountType::Append {});
+            state.stack.create_node(new, MountType::Append {});
         }
     }
 
     /// schedules nodes for garbage collection and pushes "remove" to the mutation stack
     /// remove can happen whenever
     fn remove_nodes(
-        &mut self,
+        &'bump self,
+        state: &mut DiffState<'bump>,
         nodes: impl IntoIterator<Item = &'bump VNode<'bump>>,
         gen_muts: bool,
     ) {
@@ -1115,50 +1236,50 @@ impl<'bump> DiffMachine<'bump> {
             match node {
                 VNode::Text(t) => {
                     let id = t.dom_id.get().unwrap();
-                    self.vdom.collect_garbage(id);
+                    self.collect_garbage(id);
 
                     if gen_muts {
-                        self.mutations.remove(id.as_u64());
+                        state.mutations.remove(id.as_u64());
                     }
                 }
                 VNode::Suspended(s) => {
                     let id = s.dom_id.get().unwrap();
-                    self.vdom.collect_garbage(id);
+                    self.collect_garbage(id);
 
                     if gen_muts {
-                        self.mutations.remove(id.as_u64());
+                        state.mutations.remove(id.as_u64());
                     }
                 }
                 VNode::Anchor(a) => {
                     let id = a.dom_id.get().unwrap();
-                    self.vdom.collect_garbage(id);
+                    self.collect_garbage(id);
 
                     if gen_muts {
-                        self.mutations.remove(id.as_u64());
+                        state.mutations.remove(id.as_u64());
                     }
                 }
                 VNode::Element(e) => {
                     let id = e.dom_id.get().unwrap();
 
                     if gen_muts {
-                        self.mutations.remove(id.as_u64());
+                        state.mutations.remove(id.as_u64());
                     }
 
-                    self.remove_nodes(e.children, false);
+                    self.remove_nodes(state, e.children, false);
                 }
 
                 VNode::Fragment(f) => {
-                    self.remove_nodes(f.children, gen_muts);
+                    self.remove_nodes(state, f.children, gen_muts);
                 }
 
                 VNode::Component(c) => {
                     let scope_id = c.associated_scope.get().unwrap();
-                    let scope = self.vdom.get_scope_mut(&scope_id).unwrap();
+                    let scope = self.get_scope_mut(&scope_id).unwrap();
                     let root = scope.root_node();
-                    self.remove_nodes(Some(root), gen_muts);
+                    self.remove_nodes(state, Some(root), gen_muts);
 
                     log::debug!("Destroying scope {:?}", scope_id);
-                    let mut s = self.vdom.try_remove(&scope_id).unwrap();
+                    let mut s = self.try_remove(&scope_id).unwrap();
                     s.hooks.clear_hooks();
                 }
             }
@@ -1169,40 +1290,51 @@ impl<'bump> DiffMachine<'bump> {
     ///
     /// The new nodes *will* be created - don't create them yourself!
     fn replace_and_create_many_with_many(
-        &mut self,
+        &'bump self,
+        state: &mut DiffState<'bump>,
         old: &'bump [VNode<'bump>],
         new: &'bump [VNode<'bump>],
     ) {
         if let Some(first_old) = old.get(0) {
-            self.remove_nodes(&old[1..], true);
-            self.stack
+            self.remove_nodes(state, &old[1..], true);
+            state
+                .stack
                 .create_children(new, MountType::Replace { old: first_old })
         } else {
-            self.stack.create_children(new, MountType::Append {});
+            state.stack.create_children(new, MountType::Append {});
         }
     }
 
     /// Adds a listener closure to a scope during diff.
-    fn attach_listener_to_scope<'a>(&mut self, listener: &'a Listener<'a>, scope: &mut ScopeInner) {
-        let long_listener: &'a Listener<'static> = unsafe { std::mem::transmute(listener) };
+    fn attach_listener_to_scope(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        listener: &'bump Listener<'bump>,
+        scope: &ScopeInner,
+    ) {
+        let long_listener: &'bump Listener<'static> = unsafe { std::mem::transmute(listener) };
         scope
             .items
-            .get_mut()
+            .borrow_mut()
             .listeners
             .push(long_listener as *const _)
     }
 
-    fn attach_suspended_node_to_scope(&mut self, suspended: &'bump VSuspended) {
-        if let Some(scope) = self
+    fn attach_suspended_node_to_scope(
+        &'bump self,
+        state: &mut DiffState<'bump>,
+        suspended: &'bump VSuspended,
+    ) {
+        if let Some(scope) = state
             .stack
             .current_scope()
-            .and_then(|id| self.vdom.get_scope_mut(&id))
+            .and_then(|id| self.get_scope_mut(&id))
         {
             // safety: this lifetime is managed by the logic on scope
             let extended: &VSuspended<'static> = unsafe { std::mem::transmute(suspended) };
             scope
                 .items
-                .get_mut()
+                .borrow_mut()
                 .suspended_nodes
                 .insert(suspended.task_id, extended as *const _);
         }

+ 1 - 1
packages/core/src/hooklist.rs

@@ -34,7 +34,7 @@ impl HookList {
     ///
     /// This should only be ran by Dioxus itself before "running scope".
     /// Dioxus knows how to descend through the tree to prevent mutable aliasing.
-    pub(crate) unsafe fn reset(&mut self) {
+    pub(crate) unsafe fn reset(&self) {
         self.idx.set(0);
     }
 

+ 2 - 1
packages/core/src/nodes.rs

@@ -319,7 +319,8 @@ pub struct Listener<'bump> {
 pub struct VComponent<'src> {
     pub key: Option<&'src str>,
 
-    pub associated_scope: Cell<Option<*mut ScopeInner>>,
+    pub associated_scope: Cell<Option<ScopeId>>,
+    // pub associated_scope: Cell<Option<*mut ScopeInner>>,
 
     // Function pointer to the FC that was used to generate this component
     pub user_fc: *const (),

+ 18 - 12
packages/core/src/scope.rs

@@ -43,14 +43,18 @@ pub type Context<'a> = &'a ScopeInner;
 /// use case they might have.
 pub struct ScopeInner {
     // Book-keeping about our spot in the arena
-    // yes, a raw pointer
-    // it's bump allocated so it's stable
-    // the safety of parent pointers is guaranteed by the logic in this crate
+
+    // safety:
+    //
+    // pointers to scopes are *always* valid since they are bump allocated and never freed until this scope is also freed
     pub(crate) parent_scope: Option<*mut ScopeInner>,
+
     pub(crate) our_arena_idx: ScopeId,
+
     pub(crate) height: u32,
 
     pub(crate) subtree: Cell<u32>,
+
     pub(crate) is_subtree_root: Cell<bool>,
 
     // Nodes
@@ -100,12 +104,12 @@ impl ScopeInner {
     ///
     /// This also makes sure that drop order is consistent and predictable. All resources that rely on being dropped will
     /// be dropped.
-    pub(crate) fn ensure_drop_safety(&mut self) {
+    pub(crate) fn ensure_drop_safety(&self) {
         // make sure we drop all borrowed props manually to guarantee that their drop implementation is called before we
         // run the hooks (which hold an &mut Reference)
         // right now, we don't drop
         self.items
-            .get_mut()
+            .borrow_mut()
             .borrowed_props
             .drain(..)
             .map(|li| unsafe { &*li })
@@ -116,9 +120,10 @@ impl ScopeInner {
                     .get()
                     .expect("VComponents should be associated with a valid Scope");
 
-                let scope = unsafe { &mut *scope_id };
+                todo!("move this onto virtualdom");
+                // let scope = unsafe { &mut *scope_id };
 
-                scope.ensure_drop_safety();
+                // scope.ensure_drop_safety();
 
                 todo!("drop the component's props");
                 // let mut drop_props = comp.drop_props.borrow_mut().take().unwrap();
@@ -127,7 +132,7 @@ impl ScopeInner {
 
         // Now that all the references are gone, we can safely drop our own references in our listeners.
         self.items
-            .get_mut()
+            .borrow_mut()
             .listeners
             .drain(..)
             .map(|li| unsafe { &*li })
@@ -135,8 +140,8 @@ impl ScopeInner {
     }
 
     /// A safe wrapper around calling listeners
-    pub(crate) fn call_listener(&mut self, event: UserEvent, element: ElementId) {
-        let listners = &mut self.items.get_mut().listeners;
+    pub(crate) fn call_listener(&self, event: UserEvent, element: ElementId) {
+        let listners = &mut self.items.borrow_mut().listeners;
 
         let raw_listener = listners.iter().find(|lis| {
             let search = unsafe { &***lis };
@@ -191,9 +196,10 @@ impl ScopeInner {
         // }
     }
 
-    pub(crate) fn update_vcomp(&mut self, vcomp: &VComponent) {
+    pub(crate) fn update_vcomp(&self, vcomp: &VComponent) {
         let f: *const _ = vcomp;
-        self.vcomp = unsafe { std::mem::transmute(f) };
+        todo!()
+        // self.vcomp = unsafe { std::mem::transmute(f) };
     }
 
     pub(crate) fn load_vcomp<'a>(&'a mut self) -> &'a VComponent<'a> {

+ 2 - 2
packages/core/src/scopearena.rs

@@ -32,8 +32,8 @@ impl ScopeArena {
         }
     }
 
-    pub fn get_mut(&mut self, id: &ScopeId) -> Option<&mut ScopeInner> {
-        unsafe { Some(&mut *self.scopes[id.0]) }
+    pub fn get_mut(&self, id: &ScopeId) -> Option<&ScopeInner> {
+        unsafe { Some(&*self.scopes[id.0]) }
     }
 
     pub fn new_with_key(

+ 22 - 12
packages/core/src/test_dom.rs

@@ -33,7 +33,9 @@ impl TestDom {
 
     pub fn diff<'a>(&'a self, old: &'a VNode<'a>, new: &'a VNode<'a>) -> Mutations<'a> {
         let mutations = Mutations::new();
-        let mut machine = DiffMachine::new(mutations);
+        let mut machine: DiffState = todo!();
+        // let mut machine = DiffState::new(mutations);
+        // let mut machine = DiffState::new(mutations);
         machine.stack.push(DiffInstruction::Diff { new, old });
         machine.mutations
     }
@@ -41,13 +43,17 @@ impl TestDom {
     pub fn create<'a>(&'a self, left: Option<LazyNodes<'a, '_>>) -> Mutations<'a> {
         let old = self.bump.alloc(self.render_direct(left));
 
-        let mut machine = DiffMachine::new(Mutations::new());
+        let mut machine: DiffState = todo!();
+        // let mut machine = DiffState::new(Mutations::new());
+        // let mut machine = DiffState::new(Mutations::new());
 
         machine.stack.create_node(old, MountType::Append);
 
-        machine.work(&mut || false);
+        todo!()
 
-        machine.mutations
+        // machine.work(&mut || false);
+
+        // machine.mutations
     }
 
     pub fn lazy_diff<'a>(
@@ -57,22 +63,26 @@ impl TestDom {
     ) -> (Mutations<'a>, Mutations<'a>) {
         let (old, new) = (self.render(left), self.render(right));
 
-        let mut machine = DiffMachine::new(Mutations::new());
+        let mut machine: DiffState = todo!();
+        // let mut machine = DiffState::new(Mutations::new());
 
         machine.stack.create_node(old, MountType::Append);
 
-        machine.work(|| false);
-        let create_edits = machine.mutations;
+        todo!()
+
+        // machine.work(|| false);
+        // let create_edits = machine.mutations;
 
-        let mut machine = DiffMachine::new(Mutations::new());
+        // let mut machine: DiffState = todo!();
+        // // let mut machine = DiffState::new(Mutations::new());
 
-        machine.stack.push(DiffInstruction::Diff { old, new });
+        // machine.stack.push(DiffInstruction::Diff { old, new });
 
-        machine.work(&mut || false);
+        // machine.work(&mut || false);
 
-        let edits = machine.mutations;
+        // let edits = machine.mutations;
 
-        (create_edits, edits)
+        // (create_edits, edits)
     }
 }
 

+ 57 - 33
packages/core/src/virtual_dom.rs

@@ -78,7 +78,7 @@ pub struct VirtualDom {
     // we need to keep the allocation around, but we don't necessarily use it
     _root_caller: Box<dyn Any>,
 
-    pub scopes: ScopeArena,
+    pub(crate) scopes: ScopeArena,
 
     pub receiver: UnboundedReceiver<SchedulerMsg>,
     pub sender: UnboundedSender<SchedulerMsg>,
@@ -92,7 +92,7 @@ pub struct VirtualDom {
 
     pub dirty_scopes: IndexSet<ScopeId>,
 
-    pub saved_state: Option<SavedDiffWork<'static>>,
+    pub(crate) saved_state: Option<SavedDiffWork<'static>>,
 
     pub in_progress: bool,
 }
@@ -250,7 +250,8 @@ impl VirtualDom {
     where
         P: 'static,
     {
-        let root_scope = self.pool.get_scope_mut(&self.base_scope).unwrap();
+        let base = self.base_scope;
+        let root_scope = self.get_scope_mut(&base).unwrap();
 
         // Pre-emptively drop any downstream references of the old props
         root_scope.ensure_drop_safety();
@@ -532,7 +533,7 @@ For the rest, we defer to the rIC period and work down each queue from high to l
 impl VirtualDom {
     // returns true if the event is discrete
     pub fn handle_ui_event(&mut self, event: UserEvent) -> bool {
-        let (discrete, priority) = event_meta(&event);
+        // let (discrete, priority) = event_meta(&event);
 
         if let Some(scope) = self.get_scope_mut(&event.scope) {
             if let Some(element) = event.mounted_dom_id {
@@ -555,7 +556,8 @@ impl VirtualDom {
         //     Low => todo!(),
         // }
 
-        discrete
+        todo!()
+        // discrete
     }
 
     fn prepare_work(&mut self) {
@@ -588,7 +590,7 @@ impl VirtualDom {
             SchedulerMsg::UiEvent(event) => {
                 //
 
-                let (discrete, priority) = event_meta(&event);
+                // let (discrete, priority) = event_meta(&event);
 
                 if let Some(scope) = self.get_scope_mut(&event.scope) {
                     if let Some(element) = event.mounted_dom_id {
@@ -602,7 +604,7 @@ impl VirtualDom {
                     }
                 }
 
-                discrete;
+                // discrete;
             }
         }
     }
@@ -625,12 +627,13 @@ impl VirtualDom {
         let mut ran_scopes = FxHashSet::default();
 
         if machine.stack.is_empty() {
-            self.dirty_scopes.retain(|id| self.get_scope(id).is_some());
-            self.dirty_scopes.sort_by(|a, b| {
-                let h1 = self.get_scope(a).unwrap().height;
-                let h2 = self.get_scope(b).unwrap().height;
-                h1.cmp(&h2).reverse()
-            });
+            todo!("order scopes");
+            // self.dirty_scopes.retain(|id| self.get_scope(id).is_some());
+            // self.dirty_scopes.sort_by(|a, b| {
+            //     let h1 = self.get_scope(a).unwrap().height;
+            //     let h2 = self.get_scope(b).unwrap().height;
+            //     h1.cmp(&h2).reverse()
+            // });
 
             if let Some(scopeid) = self.dirty_scopes.pop() {
                 log::info!("handling dirty scope {:?}", scopeid);
@@ -640,21 +643,23 @@ impl VirtualDom {
 
                     // if let Some(component) = self.get_scope_mut(&scopeid) {
                     if self.run_scope(&scopeid) {
-                        let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
+                        todo!("diff the scope")
                         // let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
-                        machine.stack.scope_stack.push(scopeid);
-                        machine.stack.push(DiffInstruction::Diff { new, old });
+                        // // let (old, new) = (component.frames.wip_head(), component.frames.fin_head());
+                        // machine.stack.scope_stack.push(scopeid);
+                        // machine.stack.push(DiffInstruction::Diff { new, old });
                     }
                     // }
                 }
             }
         }
 
-        let work_completed = machine.work(deadline_reached);
+        let work_completed: bool = todo!();
+        // let work_completed = machine.work(deadline_reached);
 
         // log::debug!("raw edits {:?}", machine.mutations.edits);
 
-        let mut machine: DiffMachine<'static> = unsafe { std::mem::transmute(machine) };
+        let mut machine: DiffState<'static> = unsafe { std::mem::transmute(machine) };
         // let mut saved = machine.save();
 
         if work_completed {
@@ -681,8 +686,9 @@ impl VirtualDom {
 
             // log::debug!("saved edits {:?}", mutations);
 
-            let mut saved = machine.save();
-            self.save_work(saved);
+            todo!();
+            // let mut saved = machine.save();
+            // self.save_work(saved);
             true
 
             // self.save_work(saved);
@@ -801,24 +807,26 @@ impl VirtualDom {
     ///
     /// Typically used to kickstart the VirtualDOM after initialization.
     pub fn rebuild_inner(&mut self, base_scope: ScopeId) -> Mutations {
-        let mut diff_machine = DiffMachine::new(Mutations::new());
-
         // TODO: drain any in-flight work
-        let cur_component = self
-            .get_scope_mut(&base_scope)
-            .expect("The base scope should never be moved");
-
-        log::debug!("rebuild {:?}", base_scope);
 
         // We run the component. If it succeeds, then we can diff it and add the changes to the dom.
         if self.run_scope(&base_scope) {
+            let cur_component = self
+                .get_scope_mut(&base_scope)
+                .expect("The base scope should never be moved");
+
+            log::debug!("rebuild {:?}", base_scope);
+
+            let mut diff_machine = DiffState::new(Mutations::new());
             diff_machine
                 .stack
                 .create_node(cur_component.frames.fin_head(), MountType::Append);
 
             diff_machine.stack.scope_stack.push(base_scope);
 
-            diff_machine.work(|| false);
+            todo!()
+            // self.work(&mut diff_machine, || false);
+            // diff_machine.work(|| false);
         } else {
             // todo: should this be a hard error?
             log::warn!(
@@ -827,7 +835,8 @@ impl VirtualDom {
             );
         }
 
-        unsafe { std::mem::transmute(diff_machine.mutations) }
+        todo!()
+        // unsafe { std::mem::transmute(diff_machine.mutations) }
     }
 
     pub fn hard_diff(&mut self, base_scope: ScopeId) -> Mutations {
@@ -838,16 +847,17 @@ impl VirtualDom {
         log::debug!("hard diff {:?}", base_scope);
 
         if self.run_scope(&base_scope) {
-            let mut diff_machine = DiffMachine::new(Mutations::new());
+            let mut diff_machine = DiffState::new(Mutations::new());
             diff_machine.cfg.force_diff = true;
-            diff_machine.diff_scope(base_scope);
+            self.diff_scope(&mut diff_machine, base_scope);
+            // diff_machine.diff_scope(base_scope);
             diff_machine.mutations
         } else {
             Mutations::new()
         }
     }
 
-    pub fn get_scope_mut(&mut self, id: &ScopeId) -> Option<&mut ScopeInner> {
+    pub fn get_scope_mut<'a>(&'a self, id: &ScopeId) -> Option<&'a ScopeInner> {
         self.scopes.get_mut(id)
     }
 
@@ -868,7 +878,8 @@ impl VirtualDom {
 
         // Safety:
         // - We've dropped all references to the wip bump frame
-        unsafe { scope.frames.reset_wip_frame() };
+        todo!("reset wip frame");
+        // unsafe { scope.frames.reset_wip_frame() };
 
         let items = scope.items.get_mut();
 
@@ -903,6 +914,19 @@ impl VirtualDom {
             false
         }
     }
+
+    pub fn reserve_node(&self, node: &VNode) -> ElementId {
+        todo!()
+        // self.node_reservations.insert(id);
+    }
+
+    pub fn collect_garbage(&self, id: ElementId) {
+        todo!()
+    }
+
+    pub fn try_remove(&self, id: &ScopeId) -> Option<ScopeInner> {
+        todo!()
+    }
 }
 
 // impl<'a> Future for PollAllTasks<'a> {