From e4cda7c2cbba536b045fa7bed1263b78ed33c096 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sun, 7 Nov 2021 01:01:22 -0500 Subject: [PATCH] wip: remove bumpframe --- packages/core/src/diff.rs | 18 +- packages/core/src/lib.rs | 2 - packages/core/src/nodes.rs | 10 +- packages/core/src/{ => old}/bumpframe.rs | 72 +++--- packages/core/src/scope.rs | 274 +++++++++++------------ packages/core/src/scopearena.rs | 59 ++++- packages/core/src/virtual_dom.rs | 32 +-- 7 files changed, 236 insertions(+), 231 deletions(-) rename packages/core/src/{ => old}/bumpframe.rs (56%) diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 46e278ca7..7322cc96b 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -125,7 +125,7 @@ impl<'bump> DiffState<'bump> { impl<'bump> ScopeArena { pub fn diff_scope(&'bump self, state: &mut DiffState<'bump>, id: &ScopeId) { if let Some(component) = self.get_scope(&id) { - let (old, new) = (component.frames.wip_head(), component.frames.fin_head()); + let (old, new) = (component.wip_head(), component.fin_head()); state.stack.push(DiffInstruction::Diff { new, old }); self.work(state, || false); } @@ -392,9 +392,7 @@ impl<'bump> ScopeArena { if !vcomponent.can_memoize { let cur_scope = self.get_scope(&parent_idx).unwrap(); - let extended = vcomponent as *const VComponent; - let extended: *const VComponent<'static> = unsafe { std::mem::transmute(extended) }; - + let extended = unsafe { std::mem::transmute(vcomponent) }; cur_scope.items.get_mut().borrowed_props.push(extended); } @@ -1296,12 +1294,8 @@ impl<'bump> ScopeArena { listener: &'bump Listener<'bump>, scope: &ScopeState, ) { - let long_listener: &'bump Listener<'static> = unsafe { std::mem::transmute(listener) }; - scope - .items - .borrow_mut() - .listeners - .push(long_listener as *const _) + let long_listener = unsafe { std::mem::transmute(listener) }; + scope.items.borrow_mut().listeners.push(long_listener) } fn attach_suspended_node_to_scope( @@ -1315,12 +1309,12 @@ impl<'bump> ScopeArena { .and_then(|id| self.get_scope(&id)) { // safety: this lifetime is managed by the logic on scope - let extended: &VSuspended<'static> = unsafe { std::mem::transmute(suspended) }; + let extended = unsafe { std::mem::transmute(suspended) }; scope .items .borrow_mut() .suspended_nodes - .insert(suspended.task_id, extended as *const _); + .insert(suspended.task_id, extended); } } } diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 68bce35af..4c528e87f 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -12,7 +12,6 @@ Navigating this crate: Some utilities */ -pub(crate) mod bumpframe; pub(crate) mod component; pub(crate) mod diff; pub(crate) mod diff_stack; @@ -31,7 +30,6 @@ pub(crate) mod virtual_dom; pub mod debug_dom; pub(crate) mod innerlude { - pub(crate) use crate::bumpframe::*; pub use crate::component::*; pub(crate) use crate::diff::*; pub use crate::diff_stack::*; diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index 96e041436..a75813819 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -21,9 +21,8 @@ use std::{ /// It is used during the diffing/rendering process as a runtime key into an existing set of nodes. The "render" key /// is essentially a unique key to guarantee safe usage of the Node. pub struct NodeLink { - frame_id: u32, - gen_id: u32, - scope_id: ScopeId, + pub(crate) gen_id: u32, + pub(crate) scope_id: ScopeId, } /// A composable "VirtualNode" to declare a User Interface in the Dioxus VirtualDOM. @@ -197,7 +196,6 @@ impl<'src> VNode<'src> { key: f.key, }), VNode::Linked(c) => VNode::Linked(NodeLink { - frame_id: c.frame_id, gen_id: c.gen_id, scope_id: c.scope_id, }), @@ -222,8 +220,8 @@ impl Debug for VNode<'_> { VNode::Component(comp) => write!(s, "VComponent {{ fc: {:?}}}", comp.user_fc), VNode::Linked(c) => write!( s, - "VCached {{ frame_id: {}, gen_id: {}, scope_id: {:?} }}", - c.frame_id, c.gen_id, c.scope_id + "VCached {{ gen_id: {}, scope_id: {:?} }}", + c.gen_id, c.scope_id ), } } diff --git a/packages/core/src/bumpframe.rs b/packages/core/src/old/bumpframe.rs similarity index 56% rename from packages/core/src/bumpframe.rs rename to packages/core/src/old/bumpframe.rs index b4facf39f..1c1994e8d 100644 --- a/packages/core/src/bumpframe.rs +++ b/packages/core/src/old/bumpframe.rs @@ -3,67 +3,51 @@ use bumpalo::Bump; use std::cell::Cell; pub(crate) struct ActiveFrame { - // We use a "generation" for users of contents in the bump frames to ensure their data isn't broken - pub generation: Cell, + pub cur_generation: Cell, // The double-buffering situation that we will use pub frames: [BumpFrame; 2], } -pub(crate) struct BumpFrame { - pub bump: Bump, - pub(crate) head_node: VNode<'static>, - - #[cfg(test)] - // used internally for debugging - _name: &'static str, -} - impl ActiveFrame { pub fn new() -> Self { let b1 = Bump::new(); let b2 = Bump::new(); let frame_a = BumpFrame { - head_node: VNode::Fragment(VFragment { - key: None, - children: &[], - }), bump: b1, - - #[cfg(test)] - _name: "wip", + generation: 0.into(), }; let frame_b = BumpFrame { - head_node: VNode::Fragment(VFragment { - key: None, - children: &[], - }), bump: b2, - - #[cfg(test)] - _name: "fin", - }; - Self { generation: 0.into(), + }; + + Self { frames: [frame_a, frame_b], + cur_generation: 0.into(), } } - pub unsafe fn reset_wip_frame(&mut self) { - self.wip_frame_mut().bump.reset() + pub unsafe fn reset_wip_frame(&self) { + // todo: unsafecell or something + let bump = self.wip_frame() as *const _ as *mut BumpFrame; + let g = &mut *bump; + g.bump.reset(); + + // self.wip_frame_mut().bump.reset() } /// The "work in progress frame" represents the frame that is currently being worked on. pub fn wip_frame(&self) -> &BumpFrame { - match self.generation.get() & 1 == 0 { + match self.cur_generation.get() & 1 == 0 { true => &self.frames[0], false => &self.frames[1], } } pub fn wip_frame_mut(&mut self) -> &mut BumpFrame { - match self.generation.get() & 1 == 0 { + match self.cur_generation.get() & 1 == 0 { true => &mut self.frames[0], false => &mut self.frames[1], } @@ -71,26 +55,26 @@ impl ActiveFrame { /// The finished frame represents the frame that has been "finished" and cannot be modified again pub fn finished_frame(&self) -> &BumpFrame { - match self.generation.get() & 1 == 1 { + match self.cur_generation.get() & 1 == 1 { true => &self.frames[0], false => &self.frames[1], } } - /// Give out our self-referential item with our own borrowed lifetime - pub fn fin_head<'b>(&'b self) -> &'b VNode<'b> { - let cur_head = &self.finished_frame().head_node; - unsafe { std::mem::transmute::<&VNode<'static>, &VNode<'b>>(cur_head) } - } + // /// Give out our self-referential item with our own borrowed lifetime + // pub fn fin_head<'b>(&'b self) -> &'b VNode<'b> { + // let cur_head = &self.finished_frame().head_node; + // unsafe { std::mem::transmute::<&VNode<'static>, &VNode<'b>>(cur_head) } + // } - /// Give out our self-referential item with our own borrowed lifetime - pub fn wip_head<'b>(&'b self) -> &'b VNode<'b> { - let cur_head = &self.wip_frame().head_node; - unsafe { std::mem::transmute::<&VNode<'static>, &VNode<'b>>(cur_head) } - } + // /// Give out our self-referential item with our own borrowed lifetime + // pub fn wip_head<'b>(&'b self) -> &'b VNode<'b> { + // let cur_head = &self.wip_frame().head_node; + // unsafe { std::mem::transmute::<&VNode<'static>, &VNode<'b>>(cur_head) } + // } pub fn cycle_frame(&mut self) { - self.generation.set(self.generation.get() + 1); + self.cur_generation.set(self.cur_generation.get() + 1); } } @@ -117,6 +101,6 @@ mod tests { assert_eq!(fin._name, "wip"); frames.cycle_frame(); } - assert_eq!(frames.generation.get(), 10); + assert_eq!(frames.cur_generation.get(), 10); } } diff --git a/packages/core/src/scope.rs b/packages/core/src/scope.rs index c4ef331f2..fd46f7476 100644 --- a/packages/core/src/scope.rs +++ b/packages/core/src/scope.rs @@ -47,6 +47,8 @@ pub struct ScopeState { // safety: // // pointers to scopes are *always* valid since they are bump allocated and never freed until this scope is also freed + // this is just a bit of a hack to not need an Rc to the ScopeArena. + // todo: replace this will ScopeId and provide a connection to scope arena directly pub(crate) parent_scope: Option<*mut ScopeState>, pub(crate) our_arena_idx: ScopeId, @@ -57,11 +59,14 @@ pub struct ScopeState { pub(crate) is_subtree_root: Cell, - // Nodes - pub(crate) frames: ActiveFrame, + // The double-buffering situation that we will use + pub(crate) frames: [Bump; 2], pub(crate) vcomp: *const VComponent<'static>, + pub(crate) old_root: RefCell>, + pub(crate) new_root: RefCell>, + /* we care about: - listeners (and how to call them when an event is triggered) @@ -81,136 +86,20 @@ pub struct ScopeState { pub struct SelfReferentialItems<'a> { // nodes stored by "cx.render" - pub(crate) cached_nodes: Vec>, + pub(crate) cached_nodes_old: Vec>, + pub(crate) cached_nodes_new: Vec>, - pub(crate) generation: u32, + pub(crate) generation: Cell, - pub(crate) listeners: Vec<*const Listener<'a>>, - pub(crate) borrowed_props: Vec<*const VComponent<'a>>, - pub(crate) suspended_nodes: FxHashMap>, + pub(crate) listeners: Vec<&'a Listener<'a>>, + pub(crate) borrowed_props: Vec<&'a VComponent<'a>>, + pub(crate) suspended_nodes: FxHashMap>, pub(crate) tasks: Vec>>, pub(crate) pending_effects: Vec>, } -pub struct ScopeVcomp { - // important things -} - +// Public methods exposed to libraries and components impl ScopeState { - /// This method cleans up any references to data held within our hook list. This prevents mutable aliasing from - /// causing UB in our tree. - /// - /// This works by cleaning up our references from the bottom of the tree to the top. The directed graph of components - /// essentially forms a dependency tree that we can traverse from the bottom to the top. As we traverse, we remove - /// any possible references to the data in the hook list. - /// - /// References to hook data can only be stored in listeners and component props. During diffing, we make sure to log - /// all listeners and borrowed props so we can clear them here. - /// - /// 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(&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 - .borrow_mut() - .borrowed_props - .drain(..) - .map(|li| unsafe { &*li }) - .for_each(|comp| { - // First drop the component's undropped references - let scope_id = comp - .associated_scope - .get() - .expect("VComponents should be associated with a valid Scope"); - - todo!("move this onto virtualdom"); - // let scope = unsafe { &mut *scope_id }; - - // scope.ensure_drop_safety(); - - todo!("drop the component's props"); - // let mut drop_props = comp.drop_props.borrow_mut().take().unwrap(); - // drop_props(); - }); - - // Now that all the references are gone, we can safely drop our own references in our listeners. - self.items - .borrow_mut() - .listeners - .drain(..) - .map(|li| unsafe { &*li }) - .for_each(|listener| drop(listener.callback.borrow_mut().take())); - } - - /// A safe wrapper around calling 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 }; - if search.event == event.name { - let search_id = search.mounted_node.get(); - search_id.map(|f| f == element).unwrap_or(false) - } else { - false - } - }); - - if let Some(raw_listener) = raw_listener { - let listener = unsafe { &**raw_listener }; - let mut cb = listener.callback.borrow_mut(); - if let Some(cb) = cb.as_mut() { - (cb)(event.event); - } - } else { - log::warn!("An event was triggered but there was no listener to handle it"); - } - } - - // General strategy here is to load up the appropriate suspended task and then run it. - // Suspended nodes cannot be called repeatedly. - pub(crate) fn call_suspended_node<'a>(&'a mut self, task_id: u64) { - let mut nodes = &mut self.items.get_mut().suspended_nodes; - - if let Some(suspended) = nodes.remove(&task_id) { - let sus: &'a VSuspended<'static> = unsafe { &*suspended }; - let sus: &'a VSuspended<'a> = unsafe { std::mem::transmute(sus) }; - let mut boxed = sus.callback.borrow_mut().take().unwrap(); - let new_node: Element = boxed(); - } - } - - // run the list of effects - pub(crate) fn run_effects(&mut self) { - // pub(crate) fn run_effects(&mut self, pool: &ResourcePool) { - for mut effect in self.items.get_mut().pending_effects.drain(..) { - effect(); - } - } - - pub(crate) fn new_subtree(&self) -> Option { - todo!() - // if self.is_subtree_root.get() { - // None - // } else { - // let cur = self.shared.cur_subtree.get(); - // self.shared.cur_subtree.set(cur + 1); - // Some(cur) - // } - } - - pub(crate) fn update_vcomp(&self, vcomp: &VComponent) { - let f: *const _ = vcomp; - todo!() - // self.vcomp = unsafe { std::mem::transmute(f) }; - } - - pub(crate) fn load_vcomp<'a>(&'a mut self) -> &'a VComponent<'a> { - unsafe { std::mem::transmute(&*self.vcomp) } - } - /// Get the root VNode for this Scope. /// /// This VNode is the "entrypoint" VNode. If the component renders multiple nodes, then this VNode will be a fragment. @@ -227,7 +116,7 @@ impl ScopeState { /// } /// ``` pub fn root_node(&self) -> &VNode { - self.frames.fin_head() + self.fin_head() } /// Get the subtree ID that this scope belongs to. @@ -316,7 +205,7 @@ impl ScopeState { let chan = self.sender.clone(); let id = self.scope_id(); Rc::new(move || { - chan.unbounded_send(SchedulerMsg::Immediate(id)); + let _ = chan.unbounded_send(SchedulerMsg::Immediate(id)); }) } @@ -328,7 +217,7 @@ impl ScopeState { pub fn schedule_update_any(&self) -> Rc { let chan = self.sender.clone(); Rc::new(move |id| { - chan.unbounded_send(SchedulerMsg::Immediate(id)); + let _ = chan.unbounded_send(SchedulerMsg::Immediate(id)); }) } @@ -343,17 +232,14 @@ impl ScopeState { /// /// `ScopeId` is not unique for the lifetime of the VirtualDom - a ScopeId will be reused if a component is unmounted. pub fn needs_update_any(&self, id: ScopeId) { - self.sender - .unbounded_send(SchedulerMsg::Immediate(id)) - .unwrap(); + let _ = self.sender.unbounded_send(SchedulerMsg::Immediate(id)); } /// Get the [`ScopeId`] of a mounted component. /// /// `ScopeId` is not unique for the lifetime of the VirtualDom - a ScopeId will be reused if a component is unmounted. pub fn bump(&self) -> &Bump { - let bump = &self.frames.wip_frame().bump; - bump + &self.wip_frame() } /// Take a lazy VNode structure and actually build it with the context of the VDom's efficient VNode allocator. @@ -363,20 +249,28 @@ impl ScopeState { /// ## Example /// /// ```ignore - /// fn Component(cx: Context<()>) -> VNode { + /// fn Component(cx: Scope, props: &Props) -> Element { /// // Lazy assemble the VNode tree - /// let lazy_tree = html! {
"Hello World"
}; + /// let lazy_nodes = rsx!("hello world"); /// /// // Actually build the tree and allocate it /// cx.render(lazy_tree) /// } ///``` pub fn render<'src>(&'src self, lazy_nodes: Option>) -> Option { - todo!() - // ) -> Option> { - // let bump = &self.frames.wip_frame().bump; - // let factory = NodeFactory { bump }; - // lazy_nodes.map(|f| f.call(factory)) + let bump = &self.wip_frame(); + let factory = NodeFactory { bump }; + let node = lazy_nodes.map(|f| f.call(factory))?; + + self.items + .borrow_mut() + .cached_nodes_old + .push(unsafe { std::mem::transmute(node) }); + + Some(NodeLink { + gen_id: self.items.borrow().generation.get(), + scope_id: self.our_arena_idx, + }) } /// Push an effect to be ran after the component has been successfully mounted to the dom @@ -544,3 +438,103 @@ Consult the `rules of hooks` to understand how to use hooks properly. You likely used the hook in a conditional. Hooks rely on consistent ordering between renders. Functions prefixed with "use" should never be called conditionally. "###; + +// Important internal methods +impl ScopeState { + /// Give out our self-referential item with our own borrowed lifetime + pub(crate) fn fin_head<'b>(&'b self) -> &'b VNode<'b> { + todo!() + // let cur_head = &self.finished_frame().head_node; + // unsafe { std::mem::transmute::<&VNode<'static>, &VNode<'b>>(cur_head) } + } + + /// Give out our self-referential item with our own borrowed lifetime + pub(crate) fn wip_head<'b>(&'b self) -> &'b VNode<'b> { + todo!() + // let cur_head = &self.wip_frame().head_node; + // unsafe { std::mem::transmute::<&VNode<'static>, &VNode<'b>>(cur_head) } + } + + /// The "work in progress frame" represents the frame that is currently being worked on. + pub(crate) fn wip_frame(&self) -> &Bump { + todo!() + // match self.cur_generation.get() & 1 == 0 { + // true => &self.frames[0], + // false => &self.frames[1], + // } + } + + pub unsafe fn reset_wip_frame(&self) { + // todo: unsafecell or something + let bump = self.wip_frame() as *const _ as *mut Bump; + let g = &mut *bump; + g.reset(); + + // self.wip_frame_mut().bump.reset() + } + + /// A safe wrapper around calling listeners + pub(crate) fn call_listener(&self, event: UserEvent, element: ElementId) { + let listners = &mut self.items.borrow_mut().listeners; + + let listener = listners.iter().find(|lis| { + let search = lis; + if search.event == event.name { + let search_id = search.mounted_node.get(); + search_id.map(|f| f == element).unwrap_or(false) + } else { + false + } + }); + + if let Some(listener) = listener { + let mut cb = listener.callback.borrow_mut(); + if let Some(cb) = cb.as_mut() { + (cb)(event.event); + } + } else { + log::warn!("An event was triggered but there was no listener to handle it"); + } + } + + // General strategy here is to load up the appropriate suspended task and then run it. + // Suspended nodes cannot be called repeatedly. + pub(crate) fn call_suspended_node<'a>(&'a mut self, task_id: u64) { + let mut nodes = &mut self.items.get_mut().suspended_nodes; + + if let Some(suspended) = nodes.remove(&task_id) { + let sus: &'a VSuspended<'static> = unsafe { &*suspended }; + let sus: &'a VSuspended<'a> = unsafe { std::mem::transmute(sus) }; + let mut boxed = sus.callback.borrow_mut().take().unwrap(); + let new_node: Element = boxed(); + } + } + + // run the list of effects + pub(crate) fn run_effects(&mut self) { + for mut effect in self.items.get_mut().pending_effects.drain(..) { + effect(); + } + } + + pub(crate) fn new_subtree(&self) -> Option { + todo!() + // if self.is_subtree_root.get() { + // None + // } else { + // let cur = self.shared.cur_subtree.get(); + // self.shared.cur_subtree.set(cur + 1); + // Some(cur) + // } + } + + pub(crate) fn update_vcomp(&self, vcomp: &VComponent) { + let f: *const _ = vcomp; + todo!() + // self.vcomp = unsafe { std::mem::transmute(f) }; + } + + pub(crate) fn load_vcomp<'a>(&'a mut self) -> &'a VComponent<'a> { + unsafe { std::mem::transmute(&*self.vcomp) } + } +} diff --git a/packages/core/src/scopearena.rs b/packages/core/src/scopearena.rs index 5a7011f3c..f419e410a 100644 --- a/packages/core/src/scopearena.rs +++ b/packages/core/src/scopearena.rs @@ -65,7 +65,7 @@ impl ScopeArena { height, subtree: Cell::new(subtree), is_subtree_root: Cell::new(false), - frames: ActiveFrame::new(), + frames: [Bump::default(), Bump::default()], vcomp, hooks: Default::default(), @@ -77,9 +77,12 @@ impl ScopeArena { suspended_nodes: Default::default(), tasks: Default::default(), pending_effects: Default::default(), - cached_nodes: Default::default(), + cached_nodes_old: Default::default(), generation: Default::default(), + cached_nodes_new: todo!(), }), + old_root: todo!(), + new_root: todo!(), }; let stable = self.bump.alloc(new_scope); @@ -101,5 +104,55 @@ impl ScopeArena { todo!() } - // scopes never get dropepd + // These methods would normally exist on `scope` but they need access to *all* of the scopes + + /// This method cleans up any references to data held within our hook list. This prevents mutable aliasing from + /// causing UB in our tree. + /// + /// This works by cleaning up our references from the bottom of the tree to the top. The directed graph of components + /// essentially forms a dependency tree that we can traverse from the bottom to the top. As we traverse, we remove + /// any possible references to the data in the hook list. + /// + /// References to hook data can only be stored in listeners and component props. During diffing, we make sure to log + /// all listeners and borrowed props so we can clear them here. + /// + /// 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(&self, scope_id: &ScopeId) { + let scope = self.get_scope(scope_id).unwrap(); + + // 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 + scope + .items + .borrow_mut() + .borrowed_props + .drain(..) + .for_each(|comp| { + // First drop the component's undropped references + let scope_id = comp + .associated_scope + .get() + .expect("VComponents should be associated with a valid Scope"); + + todo!("move this onto virtualdom"); + // let scope = unsafe { &mut *scope_id }; + + // scope.ensure_drop_safety(); + + todo!("drop the component's props"); + // let mut drop_props = comp.drop_props.borrow_mut().take().unwrap(); + // drop_props(); + }); + + // Now that all the references are gone, we can safely drop our own references in our listeners. + scope + .items + .borrow_mut() + .listeners + .drain(..) + .map(|li| unsafe { &*li }) + .for_each(|listener| drop(listener.callback.borrow_mut().take())); + } } diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index f25922d7b..034a29a62 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -36,8 +36,6 @@ use std::{ rc::Rc, }; -use crate::innerlude::*; - /// An integrated virtual node system that progresses events and diffs UI trees. /// /// Differences are converted into patches which a renderer can use to draw the UI. @@ -423,7 +421,7 @@ impl VirtualDom { if self.run_scope(&scopeid) { let scope = self.scopes.get_scope(&scopeid).unwrap(); - let (old, new) = (scope.frames.wip_head(), scope.frames.fin_head()); + let (old, new) = (scope.wip_head(), scope.fin_head()); diff_state.stack.scope_stack.push(scopeid); diff_state.stack.push(DiffInstruction::Diff { new, old }); } @@ -543,7 +541,7 @@ impl VirtualDom { // Cycle to the next frame and then reset it // This breaks any latent references, invalidating every pointer referencing into it. // Remove all the outdated listeners - scope.ensure_drop_safety(); + self.scopes.ensure_drop_safety(id); // Safety: // - We dropped the listeners, so no more &mut T can be used while these are held @@ -551,11 +549,10 @@ impl VirtualDom { unsafe { scope.hooks.reset() }; // Safety: - // - We've dropped all references to the wip bump frame - todo!("reset wip frame"); - // unsafe { scope.frames.reset_wip_frame() }; + // - We've dropped all references to the wip bump frame with "ensure_drop_safety" + unsafe { scope.reset_wip_frame() }; - let items = scope.items.get_mut(); + let mut items = scope.items.borrow_mut(); // just forget about our suspended nodes while we're at it items.suspended_nodes.clear(); @@ -568,12 +565,12 @@ impl VirtualDom { log::debug!("Borrowed stuff is successfully cleared"); // temporarily cast the vcomponent to the right lifetime - let vcomp = scope.load_vcomp(); + // let vcomp = scope.load_vcomp(); let render: &dyn Fn(&ScopeState) -> Element = todo!(); // Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders. - if let Some(builder) = render(scope) { + if let Some(key) = render(scope) { todo!("attach the niode"); // let new_head = builder.into_vnode(NodeFactory { // bump: &scope.frames.wip_frame().bump, @@ -589,19 +586,6 @@ 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 { - todo!() - } } pub enum SchedulerMsg { @@ -627,7 +611,7 @@ pub struct UserEvent { /// The name that the renderer will use to mount the listener. pub name: &'static str, - /// The type of event + /// Event Data pub event: Box, }