Kaynağa Gözat

WIP: still a bit stumped on DFS vs BFS

Jonathan Kelley 4 yıl önce
ebeveyn
işleme
3740f81383

+ 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));

+ 50 - 96
packages/core/src/scope.rs

@@ -12,11 +12,14 @@ use std::{
 };
 
 pub trait Properties: PartialEq {}
-impl Properties for () {}
+// 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>;
 }
@@ -46,6 +49,7 @@ pub struct Scope<P: Properties> {
 
     // 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>,
@@ -95,8 +99,51 @@ pub fn create_scoped<P: Properties + 'static>(
 }
 
 impl<P: Properties + 'static> Scoped for Scope<P> {
-    fn run(&mut self) {
-        self.run()
+    /// 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 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,
+        };
+
+        // 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);
+
+        /*
+        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
+        */
+
+        frame.head_node = node_slot
+            .deref()
+            .borrow_mut()
+            .take()
+            .expect("Viewing did not happen");
     }
 
     fn compare_props(&self, new: &Any) -> bool {
@@ -145,103 +192,10 @@ impl<P: Properties + 'static> Scoped for Scope<P> {
     }
 }
 
-impl<P: Properties> 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)
-    pub fn run<'bump>(&'bump mut self) {
-        // 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();
-        let caller = self.caller;
-        let props = &self.props;
-
-        // 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 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);
-        }
-    }
-}
-
 // ==========================
 // Active-frame related code
 // ==========================
 
-// impl<P: Properties> Scope<P> {
-//     /// 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
 // This root node has  "static" lifetime, but it's really not static.

+ 77 - 158
packages/core/src/virtual_dom.rs

@@ -1,7 +1,10 @@
 // use crate::{changelist::EditList, nodes::VNode};
 
-use crate::scope::{create_scoped, Scoped};
 use crate::{innerlude::*, scope::Properties};
+use crate::{
+    patch::Edit,
+    scope::{create_scoped, Scoped},
+};
 use bumpalo::Bump;
 use generational_arena::Arena;
 use std::{
@@ -25,19 +28,31 @@ pub struct VirtualDom {
     /// 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 {
@@ -57,51 +72,53 @@ impl VirtualDom {
     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| create_scoped(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,
-        }
+        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();
 
-        component.run();
+        let b = Bump::new();
 
-        diff_machine.diff_node(component.old_frame(), component.new_frame());
+        let mut diff_machine = DiffMachine::new(self, &b, self.base_scope);
+        // let mut diff_machine = DiffMachine::new(self, &self.diff_bump, self.base_scope);
 
-        Ok(diff_machine.consume())
+        todo!()
+        // let component = self.components.get(self.base_scope).unwrap();
+
+        // diff_machine.diff_node(component.old_frame(), component.new_frame());
+
+        // 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.
@@ -129,23 +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);
+        // 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();
-        diff_machine.diff_node(component.old_frame(), component.new_frame());
+        // component.run();
+        // diff_machine.diff_node(component.old_frame(), component.new_frame());
 
-        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();
@@ -159,115 +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.
-    /// todo
-    /// change this to accept a modification closure, so the user gets 0-cost access to the props item.
-    /// Good for cases where the props is changed remotely (or something similar) and building a whole new props item would
-    /// be wasteful
-    pub fn update_props<P: 'static>(
-        &mut self,
-        updater: impl FnOnce(&mut P),
-    ) -> Result<LifecycleEvent> {
-        todo!()
-        // // 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:
+// }