Pārlūkot izejas kodu

Merge pull request #1 from jkelleyrtp/jk/dyn_scope

Feat: move to dyn Scope for arena
Jonathan Kelley 4 gadi atpakaļ
vecāks
revīzija
e44639954e

+ 3 - 18
packages/core/examples/step.rs

@@ -1,34 +1,19 @@
-//! An example that shows how to:
-//!     create a scope,
-//!     render a component,
-//!     change some data
-//!     render it again
-//!     consume the diffs and write that to a renderer
-
 use dioxus_core::prelude::*;
 
 fn main() -> Result<(), ()> {
     let p1 = Props { name: "bob".into() };
 
-    let _vdom = VirtualDom::new_with_props(Example, p1);
-    // vdom.progress()?;
+    let mut vdom = VirtualDom::new_with_props(Example, p1);
+    vdom.update_props(|p: &mut Props| {});
 
     Ok(())
 }
 
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
 struct Props {
     name: String,
 }
 
-// impl Properties for Props {
-//     fn call(&self, ptr: *const ()) {}
-
-//     // fn new() -> Self {
-//     //     todo!()
-//     // }
-// }
-
 static Example: FC<Props> = |ctx, _props| {
     ctx.render(html! {
         <div>

+ 58 - 11
packages/core/src/diff.rs

@@ -32,10 +32,14 @@
 //!
 //! More info on how to improve this diffing algorithm:
 //!  - https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/
-use crate::innerlude::*;
+use crate::{
+    innerlude::*,
+    scope::{create_scoped, Scoped},
+};
 use bumpalo::Bump;
 use fxhash::{FxHashMap, FxHashSet};
-use std::cmp::Ordering;
+use generational_arena::Arena;
+use std::{cell::RefCell, cmp::Ordering, collections::VecDeque, rc::Rc};
 
 /// 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.
@@ -49,20 +53,23 @@ use std::cmp::Ordering;
 /// 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 wereboth updated via
 /// subscriptions and props changes.
-pub struct DiffMachine<'a> {
+pub struct DiffMachine<'a, 'b> {
     pub change_list: EditMachine<'a>,
-    immediate_queue: Vec<ScopeIdx>,
-    diffed: FxHashSet<ScopeIdx>,
-    need_to_diff: FxHashSet<ScopeIdx>,
+
+    pub vdom: &'b VirtualDom,
+    pub cur_idx: ScopeIdx,
+    pub diffed: FxHashSet<ScopeIdx>,
+    pub need_to_diff: FxHashSet<ScopeIdx>,
 }
 
-impl<'a> DiffMachine<'a> {
-    pub fn new(bump: &'a Bump) -> Self {
+impl<'a, 'b> DiffMachine<'a, 'b> {
+    pub fn new(vdom: &'b VirtualDom, bump: &'a Bump, idx: ScopeIdx) -> Self {
         Self {
+            cur_idx: idx,
             change_list: EditMachine::new(bump),
-            immediate_queue: Vec::new(),
             diffed: FxHashSet::default(),
             need_to_diff: FxHashSet::default(),
+            vdom,
         }
     }
 
@@ -71,6 +78,7 @@ impl<'a> DiffMachine<'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.
         Then, we diff and queue an edit event (via chagelist). s single trees - when components show up, we save that traversal and then re-enter later.
@@ -120,7 +128,45 @@ impl<'a> DiffMachine<'a> {
                 todo!("Usage of component VNode not currently supported");
             }
 
-            (_, VNode::Component(_)) | (VNode::Component(_), _) => {
+            (_, VNode::Component(new)) => {
+                // let VComponent {
+                //     props,
+                //     props_type,
+                //     comp,
+                //     caller,
+                //     assigned_scope,
+                //     ..
+                // } = *new;
+
+                // make the component
+                // let idx = unsafe {
+                //     // let vdom = &mut *self.vdom;
+                //     vdom.insert_with(|f| {
+                //         todo!()
+                //         //
+                //         // create_scoped(caller, props, myidx, parent)
+                //     })
+                // };
+
+                // we have no stable reference to work from
+                // push the lifecycle event onto the queue
+                // self.lifecycle_events
+                //     .borrow_mut()
+                //     .push_back(LifecycleEvent {
+                //         event_type: LifecycleType::Mount {
+                //             props: new.props,
+                //             to: self.cur_idx,
+                //         },
+                //     });
+                // we need to associaote this new component with a scope...
+
+                // self.change_list.save_known_root(id)
+                self.change_list.commit_traversal();
+
+                // push the current
+            }
+
+            (VNode::Component(old), _) => {
                 todo!("Usage of component VNode not currently supported");
             }
 
@@ -137,7 +183,8 @@ impl<'a> DiffMachine<'a> {
     //     [... node]
     //
     // The change list stack is left unchanged.
-    fn diff_listeners(&mut self, old: &[Listener<'a>], new: &[Listener<'a>]) {
+    fn diff_listeners(&mut self, old: &[Listener<'_>], new: &[Listener<'_>]) {
+        // fn diff_listeners(&mut self, old: &[Listener<'a>], new: &[Listener<'a>]) {
         if !old.is_empty() || !new.is_empty() {
             self.change_list.commit_traversal();
         }

+ 13 - 6
packages/core/src/nodes.rs

@@ -296,11 +296,13 @@ mod vtext {
 /// Virtual Components for custom user-defined components
 /// Only supports the functional syntax
 mod vcomponent {
-    use crate::innerlude::{Context, FC};
-    use std::{any::TypeId, marker::PhantomData};
+    use crate::innerlude::{Context, ScopeIdx, FC};
+    use std::{any::TypeId, cell::RefCell, marker::PhantomData, rc::Rc};
 
     use super::DomTree;
 
+    pub type StableScopeAddres = Rc<RefCell<Option<ScopeIdx>>>;
+
     #[derive(Debug)]
     pub struct VComponent<'src> {
         _p: PhantomData<&'src ()>,
@@ -308,6 +310,11 @@ mod vcomponent {
         pub(crate) props_type: TypeId,
         pub(crate) comp: *const (),
         pub(crate) caller: Caller,
+
+        // once a component gets mounted, its parent gets a stable address.
+        // this way we can carry the scope index from between renders
+        // genius, really!
+        pub assigned_scope: StableScopeAddres,
     }
 
     pub struct Caller(Box<dyn Fn(Context) -> DomTree>);
@@ -323,10 +330,10 @@ mod vcomponent {
         // - perform comparisons when diffing (memoization)
         // -
         pub fn new<P>(comp: FC<P>, props: P) -> Self {
-            let caller = move |ctx: Context| {
-                let t = comp(ctx, &props);
-                t
-            };
+            // let caller = move |ctx: Context| {
+            //     let t = comp(ctx, &props);
+            //     t
+            // };
             // let _caller = comp as *const ();
             // let _props = Box::new(props);
 

+ 6 - 4
packages/core/src/patch.rs

@@ -126,6 +126,7 @@ pub struct EditMachine<'src> {
     pub traversal: Traversal,
     next_temporary: u32,
     forcing_new_listeners: bool,
+
     pub emitter: EditList<'src>,
 }
 
@@ -214,10 +215,6 @@ impl<'a> EditMachine<'a> {
         debug_assert!(self.traversal_is_committed());
         debug_assert!(start < end);
         let temp_base = self.next_temporary;
-        // debug!(
-        //     "emit: save_children_to_temporaries({}, {}, {})",
-        //     temp_base, start, end
-        // );
         self.next_temporary = temp_base + (end - start) as u32;
         self.emitter.push(Edit::SaveChildrenToTemporaries {
             temp: temp_base,
@@ -367,6 +364,11 @@ impl<'a> EditMachine<'a> {
         // debug!("emit: remove_event_listener({:?})", event);
     }
 
+    pub fn save_known_root(&mut self, id: ScopeIdx) {
+        log::debug!("emit: save_known_root({:?})", id);
+        self.emitter.push(Edit::MakeKnown { node: id })
+    }
+
     // pub fn save_template(&mut self, id: CacheId) {
     //     debug_assert!(self.traversal_is_committed());
     //     debug_assert!(!self.has_template(id));

+ 139 - 144
packages/core/src/scope.rs

@@ -11,22 +11,36 @@ use std::{
     ops::Deref,
 };
 
+pub trait Properties: PartialEq {}
+// just for now
+impl<T: PartialEq> Properties for T {}
+
+pub trait Scoped {
+    fn run(&mut self);
+    fn compare_props(&self, new: &dyn std::any::Any) -> bool;
+    fn call_listener(&mut self, trigger: EventTrigger);
+
+    fn new_frame<'bump>(&'bump self) -> &'bump VNode<'bump>;
+    fn old_frame<'bump>(&'bump self) -> &'bump VNode<'bump>;
+}
+
 /// Every component in Dioxus is represented by a `Scope`.
 ///
 /// Scopes contain the state for hooks, the component's props, and other lifecycle information.
 ///
 /// Scopes are allocated in a generational arena. As components are mounted/unmounted, they will replace slots of dead components.
 /// The actual contents of the hooks, though, will be allocated with the standard allocator. These should not allocate as frequently.
-pub struct Scope {
+pub struct Scope<P: Properties> {
     // Map to the parent
     pub parent: Option<ScopeIdx>,
 
-    // lying, cheating reference >:(
-    pub props: Box<dyn std::any::Any>,
-
     // our own index
     pub myidx: ScopeIdx,
 
+    pub caller: FC<P>,
+
+    pub props: P,
+
     // ==========================
     // slightly unsafe stuff
     // ==========================
@@ -35,71 +49,113 @@ pub struct Scope {
 
     // These hooks are actually references into the hook arena
     // These two could be combined with "OwningRef" to remove unsafe usage
+    // or we could dedicate a tiny bump arena just for them
     // could also use ourborous
     pub hooks: RefCell<Vec<*mut Hook>>,
     pub hook_arena: typed_arena::Arena<Hook>,
 
     // Unsafety:
     // - is self-refenrential and therefore needs to point into the bump
-    //
     // Stores references into the listeners attached to the vnodes
     // NEEDS TO BE PRIVATE
     listeners: RefCell<Vec<*const dyn Fn(crate::events::VirtualEvent)>>,
+}
+
+// instead of having it as a trait method, we use a single function
+// todo: do the unsafety magic stuff to erase the type of p
+pub fn create_scoped<P: Properties + 'static>(
+    caller: FC<P>,
+    props: P,
+    myidx: ScopeIdx,
+    parent: Option<ScopeIdx>,
+) -> Box<dyn Scoped> {
+    let hook_arena = typed_arena::Arena::new();
+    let hooks = RefCell::new(Vec::new());
+
+    let listeners = Default::default();
+
+    let old_frame = BumpFrame {
+        bump: Bump::new(),
+        head_node: VNode::text(""),
+    };
+
+    let new_frame = BumpFrame {
+        bump: Bump::new(),
+        head_node: VNode::text(""),
+    };
 
-    // Unsafety
-    // - is a raw ptr because we need to compare
-    pub caller: *const (),
+    let frames = ActiveFrame::from_frames(old_frame, new_frame);
+
+    Box::new(Scope {
+        myidx,
+        hook_arena,
+        hooks,
+        caller,
+        frames,
+        listeners,
+        parent,
+        props,
+    })
 }
 
-impl Scope {
-    // create a new scope from a function
-    pub fn new<'a, P1, P2: 'static>(
-        f: FC<P1>,
-        props: P1,
-        myidx: ScopeIdx,
-        parent: Option<ScopeIdx>,
-    ) -> Self {
-        let hook_arena = typed_arena::Arena::new();
-        let hooks = RefCell::new(Vec::new());
-
-        // Capture the caller
-        let caller = f as *const ();
-
-        let listeners = Default::default();
-
-        let old_frame = BumpFrame {
-            bump: Bump::new(),
-            head_node: VNode::text(""),
+impl<P: Properties + 'static> Scoped for Scope<P> {
+    /// Create a new context and run the component with references from the Virtual Dom
+    /// This function downcasts the function pointer based on the stored props_type
+    ///
+    /// Props is ?Sized because we borrow the props and don't need to know the size. P (sized) is used as a marker (unsized)
+    fn run<'bump>(&'bump mut self) {
+        let frame = {
+            let frame = self.frames.next();
+            frame.bump.reset();
+            frame
         };
 
-        let new_frame = BumpFrame {
-            bump: Bump::new(),
-            head_node: VNode::text(""),
+        let node_slot = std::rc::Rc::new(RefCell::new(None));
+
+        let ctx: Context<'bump> = Context {
+            arena: &self.hook_arena,
+            hooks: &self.hooks,
+            bump: &frame.bump,
+            idx: 0.into(),
+            _p: PhantomData {},
+            final_nodes: node_slot.clone(),
+            scope: self.myidx,
+            listeners: &self.listeners,
         };
 
-        let frames = ActiveFrame::from_frames(old_frame, new_frame);
+        // Note that the actual modification of the vnode head element occurs during this call
+        // let _: DomTree = caller(ctx, props);
+        let _: DomTree = (self.caller)(ctx, &self.props);
 
-        // box the props
-        let props = Box::new(props);
+        /*
+        SAFETY ALERT
 
-        let props = unsafe { std::mem::transmute::<_, Box<P2>>(props) };
+        DO NOT USE THIS VNODE WITHOUT THE APPOPRIATE ACCESSORS.
+        KEEPING THIS STATIC REFERENCE CAN LEAD TO UB.
 
-        Self {
-            myidx,
-            hook_arena,
-            hooks,
-            caller,
-            frames,
-            listeners,
-            parent,
-            props,
-        }
+        Some things to note:
+        - The VNode itself is bound to the lifetime, but it itself is owned by scope.
+        - The VNode has a private API and can only be used from accessors.
+        - Public API cannot drop or destructure VNode
+        */
+
+        frame.head_node = node_slot
+            .deref()
+            .borrow_mut()
+            .take()
+            .expect("Viewing did not happen");
+    }
+
+    fn compare_props(&self, new: &Any) -> bool {
+        new.downcast_ref::<P>()
+            .map(|f| &self.props == f)
+            .expect("Props should not be of a different type")
     }
 
     // A safe wrapper around calling listeners
     // calling listeners will invalidate the list of listeners
     // The listener list will be completely drained because the next frame will write over previous listeners
-    pub fn call_listener(&mut self, trigger: EventTrigger) {
+    fn call_listener(&mut self, trigger: EventTrigger) {
         let EventTrigger {
             listener_id,
             event: source,
@@ -126,112 +182,19 @@ impl Scope {
             self.listeners.borrow_mut().drain(..);
         }
     }
-}
 
-pub struct RawComponent {
-    // used as a memoization strategy
-    comparator: *const Box<dyn Fn(&Box<dyn Any>) -> bool>,
-
-    // used to actually run the component
-    // encapsulates props
-    runner: *const Box<dyn Fn(Context) -> DomTree>,
-
-    // the actual FC<T>
-    raw: *const (),
-}
-
-impl Scope {
-    /// Create a new context and run the component with references from the Virtual Dom
-    /// This function downcasts the function pointer based on the stored props_type
-    ///
-    /// Props is ?Sized because we borrow the props and don't need to know the size. P (sized) is used as a marker (unsized)
-    pub fn run<'bump, PLocked: Sized + 'static>(&'bump mut self) {
-        let frame = {
-            let frame = self.frames.next();
-            frame.bump.reset();
-            frame
-        };
-
-        let node_slot = std::rc::Rc::new(RefCell::new(None));
-
-        let ctx: Context<'bump> = Context {
-            arena: &self.hook_arena,
-            hooks: &self.hooks,
-            bump: &frame.bump,
-            idx: 0.into(),
-            _p: PhantomData {},
-            final_nodes: node_slot.clone(),
-            scope: self.myidx,
-            listeners: &self.listeners,
-        };
-
-        unsafe {
-            /*
-            SAFETY ALERT
-
-            This particular usage of transmute is outlined in its docs https://doc.rust-lang.org/std/mem/fn.transmute.html
-            We hide the generic bound on the function item by casting it to raw pointer. When the function is actually called,
-            we transmute the function back using the props as reference.
-
-            we could do a better check to make sure that the TypeID is correct before casting
-            --
-            This is safe because we check that the generic type matches before casting.
-            */
-            // we use plocked to be able to remove the borrowed lifetime
-            // these lifetimes could be very broken, so we need to dynamically manage them
-            let caller = std::mem::transmute::<*const (), FC<PLocked>>(self.caller);
-            let props = self.props.downcast_ref::<PLocked>().unwrap();
-
-            // Note that the actual modification of the vnode head element occurs during this call
-            let _: DomTree = caller(ctx, props);
-
-            /*
-            SAFETY ALERT
-
-            DO NOT USE THIS VNODE WITHOUT THE APPOPRIATE ACCESSORS.
-            KEEPING THIS STATIC REFERENCE CAN LEAD TO UB.
-
-            Some things to note:
-            - The VNode itself is bound to the lifetime, but it itself is owned by scope.
-            - The VNode has a private API and can only be used from accessors.
-            - Public API cannot drop or destructure VNode
-            */
-            // the nodes we care about have been unsafely extended to a static lifetime in context
-            frame.head_node = node_slot
-                .deref()
-                .borrow_mut()
-                .take()
-                .expect("Viewing did not happen");
-        }
+    fn new_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
+        self.frames.current_head_node()
     }
-}
 
-fn retrieve_listeners(node: &VNode<'static>, listeners: &mut Vec<&Listener>) {
-    if let VNode::Element(el) = *node {
-        for listener in el.listeners {
-            // let g = listener as *const Listener;
-            listeners.push(listener);
-        }
-        for child in el.children {
-            retrieve_listeners(child, listeners);
-        }
+    fn old_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
+        self.frames.prev_head_node()
     }
 }
 
 // ==========================
 // Active-frame related code
 // ==========================
-impl Scope {
-    /// Accessor to get the root node and its children (safely)\
-    /// Scope is self-referntial, so we are forced to use the 'static lifetime to cheat
-    pub fn new_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
-        self.frames.current_head_node()
-    }
-
-    pub fn old_frame<'bump>(&'bump self) -> &'bump VNode<'bump> {
-        self.frames.prev_head_node()
-    }
-}
 
 // todo, do better with the active frame stuff
 // somehow build this vnode with a lifetime tied to self
@@ -323,8 +286,8 @@ mod tests {
         let props = ();
         let parent = None;
         let mut nodes = generational_arena::Arena::new();
-        nodes.insert_with(|f| {
-            let scope = Scope::new::<(), ()>(example, props, f, parent);
+        nodes.insert_with(|myidx| {
+            let scope = create_scoped(example, props, myidx, parent);
         });
     }
 
@@ -390,3 +353,35 @@ mod tests {
         let props = ExampleProps { name: &source_text };
     }
 }
+
+#[cfg(asd)]
+mod old {
+
+    /// The ComponentCaller struct is an opaque object that encapsultes the memoization and running functionality for FC
+    ///
+    /// It's opaque because during the diffing mechanism, the type of props is sealed away in a closure. This makes it so
+    /// scope doesn't need to be generic
+    pub struct ComponentCaller {
+        // used as a memoization strategy
+        comparator: Box<dyn Fn(&Box<dyn Any>) -> bool>,
+
+        // used to actually run the component
+        // encapsulates props
+        runner: Box<dyn Fn(Context) -> DomTree>,
+
+        props_type: TypeId,
+
+        // the actual FC<T>
+        raw: *const (),
+    }
+
+    impl ComponentCaller {
+        fn new<P>(props: P) -> Self {
+            let comparator = Box::new(|f| false);
+            todo!();
+            // Self { comparator }
+        }
+
+        fn update_props<P>(props: P) {}
+    }
+}

+ 87 - 169
packages/core/src/virtual_dom.rs

@@ -1,6 +1,10 @@
 // use crate::{changelist::EditList, nodes::VNode};
 
-use crate::innerlude::*;
+use crate::{innerlude::*, scope::Properties};
+use crate::{
+    patch::Edit,
+    scope::{create_scoped, Scoped},
+};
 use bumpalo::Bump;
 use generational_arena::Arena;
 use std::{
@@ -18,21 +22,37 @@ use std::{
 /// Differences are converted into patches which a renderer can use to draw the UI.
 pub struct VirtualDom {
     /// All mounted components are arena allocated to make additions, removals, and references easy to work with
-    /// A generational arean is used to re-use slots of deleted scopes without having to resize the underlying arena.
-    pub(crate) components: Arena<Scope>,
-
+    /// A generational arena is used to re-use slots of deleted scopes without having to resize the underlying arena.
+    ///
+    /// eventually, come up with a better datastructure that reuses boxes for known P types
+    /// like a generational typemap bump arena
+    /// -> IE a cache line for each P type with soem heuristics on optimizing layout
+    pub(crate) components: Arena<Box<dyn Scoped>>,
+    // pub(crate) components: Rc<RefCell<Arena<Box<dyn Scoped>>>>,
     /// The index of the root component.
     /// Will not be ready if the dom is fresh
-    base_scope: ScopeIdx,
-
-    event_queue: RefCell<VecDeque<LifecycleEvent>>,
-
-    // todo: encapsulate more state into this so we can better reuse it
-    diff_bump: Bump,
+    pub(crate) base_scope: ScopeIdx,
 
     // Type of the original props. This is done so VirtualDom does not need to be generic.
     #[doc(hidden)]
     _root_prop_type: std::any::TypeId,
+    // ======================
+    //  DIFF RELATED ITEMs
+    // ======================
+    // // todo: encapsulate more state into this so we can better reuse it
+    pub(crate) diff_bump: Bump,
+    // // be very very very very very careful
+    // pub change_list: EditMachine<'static>,
+
+    // // vdom: &'a VirtualDom,
+    // vdom: *mut Arena<Box<dyn Scoped>>,
+
+    // // vdom: Rc<RefCell<Arena<Box<dyn Scoped>>>>,
+    // pub cur_idx: ScopeIdx,
+
+    // // todo
+    // // do an indexmap sorted by height
+    // dirty_nodes: fxhash::FxHashSet<ScopeIdx>,
 }
 
 impl VirtualDom {
@@ -49,55 +69,56 @@ impl VirtualDom {
     ///
     /// This is useful when a component tree can be driven by external state (IE SSR) but it would be too expensive
     /// to toss out the entire tree.
-    pub fn new_with_props<P: 'static>(root: FC<P>, root_props: P) -> Self {
+    pub fn new_with_props<P: Properties + 'static>(root: FC<P>, root_props: P) -> Self {
         let mut components = Arena::new();
 
-        let event_queue = RefCell::new(VecDeque::new());
-
         // Create a reference to the component in the arena
         // Note: we are essentially running the "Mount" lifecycle event manually while the vdom doesnt yet exist
         // This puts the dom in a usable state on creation, rather than being potentially invalid
-        let base_scope =
-            components.insert_with(|id| Scope::new::<_, P>(root, root_props, id, None));
-
-        // evaluate the component, pushing any updates its generates into the lifecycle queue
-        // todo!
-
-        let _root_prop_type = TypeId::of::<P>();
-        let diff_bump = Bump::new();
-
-        Self {
-            components,
-            base_scope,
-            event_queue,
-            diff_bump,
-            _root_prop_type,
-        }
+        let base_scope = components.insert_with(|id| create_scoped(root, root_props, id, None));
+
+        todo!()
+        // Self {
+        //     // components: RefCell::new(components),
+        //     components: components,
+        //     // components: Rc::new(RefCell::new(components)),
+        //     base_scope,
+        //     // event_queue: RefCell::new(VecDeque::new()),
+        //     diff_bump: Bump::new(),
+        //     _root_prop_type: TypeId::of::<P>(),
+        // }
     }
 
     /// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom.
-    ///
-    ///
-    pub fn rebuild(&mut self) -> Result<EditList<'_>> {
+
+    // pub fn rebuild<'s>(&'s mut self) -> Result<> {
+    // pub fn rebuild<'s>(&'s mut self) -> Result<std::cell::Ref<'_, Arena<Box<dyn Scoped>>>> {
+    pub fn rebuild<'s>(&'s mut self) -> Result<EditList<'s>> {
         // Reset and then build a new diff machine
         // The previous edit list cannot be around while &mut is held
         // Make sure variance doesnt break this
         self.diff_bump.reset();
-        let mut diff_machine = DiffMachine::new(&self.diff_bump);
 
-        // this is still a WIP
-        // we'll need to re-fecth all the scopes that were changed and build the diff machine
-        // fetch the component again
-        let component = self
-            .components
+        self.components
             .get_mut(self.base_scope)
-            .expect("Root should always exist");
+            .expect("Root should always exist")
+            .run();
+
+        let b = Bump::new();
+
+        let mut diff_machine = DiffMachine::new(self, &b, self.base_scope);
+        // let mut diff_machine = DiffMachine::new(self, &self.diff_bump, self.base_scope);
 
-        component.run::<()>();
+        todo!()
+        // let component = self.components.get(self.base_scope).unwrap();
 
-        diff_machine.diff_node(component.old_frame(), component.new_frame());
+        // diff_machine.diff_node(component.old_frame(), component.new_frame());
 
-        Ok(diff_machine.consume())
+        // let edits = diff_machine.consume();
+
+        // self.diff_bump = b;
+
+        // Ok(edits)
     }
 
     /// This method is the most sophisticated way of updating the virtual dom after an external event has been triggered.
@@ -125,37 +146,32 @@ impl VirtualDom {
     ///
     /// ```
     pub fn progress_with_event(&mut self, event: EventTrigger) -> Result<EditList<'_>> {
-        let component = self
-            .components
-            .get_mut(event.component_id)
-            .expect("Component should exist if an event was triggered");
-
-        component.call_listener(event);
-
+        // self.components
+        //     .borrow_mut()
+        //     .get_mut(event.component_id)
+        //     .map(|f| {
+        //         f.call_listener(event);
+        //         f
+        //     })
+        //     .map(|f| f.run())
+        //     .expect("Borrowing should not fail");
+
+        // component.call_listener(event);
+
+        // .expect("Component should exist if an event was triggered");
         // Reset and then build a new diff machine
         // The previous edit list cannot be around while &mut is held
         // Make sure variance doesnt break this
-        self.diff_bump.reset();
-        let mut diff_machine = DiffMachine::new(&self.diff_bump);
-
-        // this is still a WIP
-        // we'll need to re-fecth all the scopes that were changed and build the diff machine
-        // fetch the component again
-        // let component = self
-        //     .components
-        //     .get_mut(self.base_scope)
-        //     .expect("Root should always exist");
+        // self.diff_bump.reset();
+        // let mut diff_machine = DiffMachine::new(&mut self, event.component_id);
+        // let mut diff_machine =
+        //     DiffMachine::new(&self.diff_bump, &mut self.components, event.component_id);
 
-        component.run::<()>();
+        // component.run();
+        // diff_machine.diff_node(component.old_frame(), component.new_frame());
 
-        diff_machine.diff_node(component.old_frame(), component.new_frame());
-        // diff_machine.diff_node(
-        //     component.old_frame(),
-        //     component.new_frame(),
-        //     Some(self.base_scope),
-        // );
-
-        Ok(diff_machine.consume())
+        todo!()
+        // Ok(diff_machine.consume())
         // Err(crate::error::Error::NoEvent)
         // Mark dirty components. Descend from the highest node until all dirty nodes are updated.
         // let mut affected_components = Vec::new();
@@ -169,106 +185,8 @@ impl VirtualDom {
 
         // todo!()
     }
-
-    /// Using mutable access to the Virtual Dom, progress a given lifecycle event
-    fn process_lifecycle(&mut self, LifecycleEvent { event_type }: LifecycleEvent) -> Result<()> {
-        match event_type {
-            // Component needs to be mounted to the virtual dom
-            LifecycleType::Mount {
-                to: _,
-                under: _,
-                props: _,
-            } => {}
-
-            // The parent for this component generated new props and the component needs update
-            LifecycleType::PropsChanged {
-                props: _,
-                component: _,
-            } => {}
-
-            // Component was messaged via the internal subscription service
-            LifecycleType::Callback { component: _ } => {}
-        }
-
-        Ok(())
-    }
-
-    /// Pop the top event of the internal lifecycle event queu
-    pub fn pop_event(&self) -> Option<LifecycleEvent> {
-        self.event_queue.borrow_mut().pop_front()
-    }
-
-    /// With access to the virtual dom, schedule an update to the Root component's props.
-    /// This generates the appropriate Lifecycle even. It's up to the renderer to actually feed this lifecycle event
-    /// back into the event system to get an edit list.
-    pub fn update_props<P: 'static>(&mut self, new_props: P) -> Result<LifecycleEvent> {
-        // Ensure the props match
-        if TypeId::of::<P>() != self._root_prop_type {
-            return Err(Error::WrongProps);
-        }
-
-        Ok(LifecycleEvent {
-            event_type: LifecycleType::PropsChanged {
-                props: Box::new(new_props),
-                component: self.base_scope,
-            },
-        })
-    }
-}
-
-pub struct LifecycleEvent {
-    pub event_type: LifecycleType,
 }
 
-pub enum LifecycleType {
-    // Component needs to be mounted, but its scope doesn't exist yet
-    Mount {
-        to: ScopeIdx,
-        under: usize,
-        props: Box<dyn std::any::Any>,
-    },
-
-    // Parent was evalauted causing new props to generate
-    PropsChanged {
-        props: Box<dyn std::any::Any>,
-        component: ScopeIdx,
-    },
-
-    // Hook for the subscription API
-    Callback {
-        component: ScopeIdx,
-    },
-}
-
-impl LifecycleEvent {
-    fn index(&self) -> Option<ScopeIdx> {
-        match &self.event_type {
-            LifecycleType::Mount {
-                to: _,
-                under: _,
-                props: _,
-            } => None,
-
-            LifecycleType::PropsChanged { component, .. }
-            | LifecycleType::Callback { component } => Some(component.clone()),
-        }
-    }
-}
-
-mod tests {
-    use super::*;
-
-    #[test]
-    fn start_dom() {
-        let mut dom = VirtualDom::new(|ctx, props| {
-            todo!()
-            // ctx.render(|ctx| {
-            //     use crate::builder::*;
-            //     let bump = ctx.bump();
-            //     div(bump).child(text("hello,    world")).finish()
-            // })
-        });
-        let edits = dom.rebuild().unwrap();
-        println!("{:#?}", edits);
-    }
-}
+// struct LockedEdits<'src> {
+//     edits:
+// }