feat: a new vnode type for anchors
This commit is contained in:
1 parent
63a85e4865
commit
d618092e9d
15 files changed
+715
-441
No files matched your search
@@ -5,7 +5,9 @@ use std::{cell::UnsafeCell, rc::Rc};
|
||||
use crate::heuristics::*;
|
||||
use crate::innerlude::*;
|
||||
use futures_util::stream::FuturesUnordered;
|
||||
use fxhash::{FxHashMap, FxHashSet};
|
||||
use slab::Slab;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
// slotmap::new_key_type! {
|
||||
// // A dedicated key type for the all the scopes
|
||||
@@ -47,7 +49,7 @@ pub struct SharedResources {
|
||||
|
||||
/// We use a SlotSet to keep track of the keys that are currently being used.
|
||||
/// However, we don't store any specific data since the "mirror"
|
||||
pub raw_elements: Shared<Slab<()>>,
|
||||
pub raw_elements: Rc<RefCell<Slab<()>>>,
|
||||
|
||||
pub task_setter: Rc<dyn Fn(ScopeId)>,
|
||||
}
|
||||
@@ -133,7 +135,10 @@ impl SharedResources {
|
||||
}
|
||||
|
||||
/// return the id, freeing the space of the original node
|
||||
pub fn collect_garbage(&self, id: ElementId) {}
|
||||
pub fn collect_garbage(&self, id: ElementId) {
|
||||
let mut r: RefMut<Slab<()>> = self.raw_elements.borrow_mut();
|
||||
r.remove(id.0);
|
||||
}
|
||||
|
||||
pub fn borrow_queue(&self) -> RefMut<Vec<HeightMarker>> {
|
||||
self.event_queue.borrow_mut()
|
||||
|
||||
@@ -138,8 +138,8 @@ impl<'src, P> Context<'src, P> {
|
||||
self,
|
||||
lazy_nodes: LazyNodes<'src, F>,
|
||||
) -> DomTree<'src> {
|
||||
let scope_ref = self.scope;
|
||||
Some(lazy_nodes.into_vnode(NodeFactory { scope: scope_ref }))
|
||||
let bump = &self.scope.frames.wip_frame().bump;
|
||||
Some(lazy_nodes.into_vnode(NodeFactory { bump }))
|
||||
}
|
||||
|
||||
/// `submit_task` will submit the future to be polled.
|
||||
@@ -178,7 +178,7 @@ impl<'src, P> Context<'src, P> {
|
||||
///
|
||||
pub fn consume_shared_state<T: 'static>(self) -> Option<Rc<T>> {
|
||||
let mut scope = Some(self.scope);
|
||||
let mut par = None;
|
||||
let mut parent = None;
|
||||
|
||||
let ty = TypeId::of::<T>();
|
||||
while let Some(inner) = scope {
|
||||
@@ -202,7 +202,7 @@ impl<'src, P> Context<'src, P> {
|
||||
.clone()
|
||||
.downcast::<T>()
|
||||
.expect("Should not fail, already validated the type from the hashmap");
|
||||
par = Some(rc);
|
||||
parent = Some(rc);
|
||||
break;
|
||||
} else {
|
||||
match inner.parent_idx {
|
||||
@@ -213,7 +213,7 @@ impl<'src, P> Context<'src, P> {
|
||||
}
|
||||
}
|
||||
}
|
||||
par
|
||||
parent
|
||||
}
|
||||
|
||||
/// Store a value between renders
|
||||
|
||||
+408
-356
File diff suppressed because it is too large.
Load diff
@@ -64,3 +64,24 @@ pub enum DomEdit<'bump> {
|
||||
name: &'static str,
|
||||
},
|
||||
}
|
||||
impl DomEdit<'_> {
|
||||
pub fn is(&self, id: &'static str) -> bool {
|
||||
match self {
|
||||
DomEdit::PushRoot { .. } => id == "PushRoot",
|
||||
DomEdit::PopRoot => id == "PopRoot",
|
||||
DomEdit::AppendChildren { .. } => id == "AppendChildren",
|
||||
DomEdit::ReplaceWith { .. } => id == "ReplaceWith",
|
||||
DomEdit::Remove => id == "Remove",
|
||||
DomEdit::RemoveAllChildren => id == "RemoveAllChildren",
|
||||
DomEdit::CreateTextNode { .. } => id == "CreateTextNode",
|
||||
DomEdit::CreateElement { .. } => id == "CreateElement",
|
||||
DomEdit::CreateElementNs { .. } => id == "CreateElementNs",
|
||||
DomEdit::CreatePlaceholder { .. } => id == "CreatePlaceholder",
|
||||
DomEdit::NewEventListener { .. } => id == "NewEventListener",
|
||||
DomEdit::RemoveEventListener { .. } => id == "RemoveEventListener",
|
||||
DomEdit::SetText { .. } => id == "SetText",
|
||||
DomEdit::SetAttribute { .. } => id == "SetAttribute",
|
||||
DomEdit::RemoveAttribute { .. } => id == "RemoveAttribute",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,10 @@ use std::{
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use crate::innerlude::{ElementId, HeightMarker, ScopeId};
|
||||
use crate::{
|
||||
innerlude::{ElementId, HeightMarker, ScopeId},
|
||||
VNode,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EventTrigger {
|
||||
@@ -46,15 +49,16 @@ impl EventTrigger {
|
||||
/// The ultimate goal of the scheduler is to manage latency of changes, prioritizing "flashier" changes over "subtler" changes.
|
||||
#[derive(Debug)]
|
||||
pub enum EventPriority {
|
||||
/// "Immediate" work will interrupt whatever work is currently being done and force its way through. This type of work
|
||||
/// is typically reserved for small changes to single elements.
|
||||
/// Garbage collection is a type of work than can be scheduled around other work, but must be completed in a specific
|
||||
/// order. The GC must be run for a component before any other future work for that component is run. Otherwise,
|
||||
/// we will leak slots in our slab.
|
||||
///
|
||||
/// The primary user of the "Immediate" priority is the `Signal` API which performs surgical mutations to the DOM.
|
||||
Immediate,
|
||||
/// Garbage collection mixes with the safety aspects of the virtualdom so it's very important to get it done before
|
||||
/// other work.
|
||||
GarbageCollection,
|
||||
|
||||
/// "High Priority" work will not interrupt other high priority work, but will interrupt long medium and low priority work.
|
||||
///
|
||||
///
|
||||
/// This is typically reserved for things like user interaction.
|
||||
High,
|
||||
|
||||
@@ -106,6 +110,8 @@ pub enum VirtualEvent {
|
||||
MouseEvent(on::MouseEvent),
|
||||
PointerEvent(on::PointerEvent),
|
||||
|
||||
GarbageCollection,
|
||||
|
||||
// image event has conflicting method types
|
||||
// ImageEvent(event_data::ImageEvent),
|
||||
SetStateEvent {
|
||||
@@ -198,7 +204,6 @@ pub mod on {
|
||||
Listener {
|
||||
event: shortname,
|
||||
mounted_node: Cell::new(None),
|
||||
scope: c.scope.our_arena_idx,
|
||||
callback: RefCell::new(Some(callback)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,11 +190,10 @@ where
|
||||
None => {
|
||||
//
|
||||
Some(VNode {
|
||||
dom_id: empty_cell(),
|
||||
key: None,
|
||||
kind: VNodeKind::Suspended {
|
||||
kind: VNodeKind::Suspended(VSuspended {
|
||||
node: domnode.clone(),
|
||||
},
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -250,7 +249,8 @@ impl<'src> SuspendedContext<'src> {
|
||||
lazy_nodes: LazyNodes<'src, F>,
|
||||
) -> DomTree<'src> {
|
||||
let scope_ref = self.inner.scope;
|
||||
let bump = &self.inner.scope.frames.wip_frame().bump;
|
||||
|
||||
Some(lazy_nodes.into_vnode(NodeFactory { scope: scope_ref }))
|
||||
Some(lazy_nodes.into_vnode(NodeFactory { bump }))
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#![allow(non_snake_case)]
|
||||
#![doc = include_str!("../README.md")]
|
||||
//! Dioxus Core
|
||||
//! ----------
|
||||
//!
|
||||
|
||||
+65
-36
@@ -7,7 +7,7 @@ use crate::{
|
||||
events::VirtualEvent,
|
||||
innerlude::{empty_cell, Context, DomTree, ElementId, Properties, Scope, ScopeId, FC},
|
||||
};
|
||||
use bumpalo::boxed::Box as BumpBox;
|
||||
use bumpalo::{boxed::Box as BumpBox, Bump};
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
fmt::{Arguments, Debug, Formatter},
|
||||
@@ -20,16 +20,24 @@ pub struct VNode<'src> {
|
||||
pub kind: VNodeKind<'src>,
|
||||
|
||||
pub(crate) key: Option<&'src str>,
|
||||
|
||||
/// ElementId supports NonZero32 and Cell is zero cost, so the size of this field is unaffected
|
||||
pub(crate) dom_id: Cell<Option<ElementId>>,
|
||||
}
|
||||
impl VNode<'_> {
|
||||
pub fn key(&self) -> Option<&str> {
|
||||
|
||||
impl<'src> VNode<'src> {
|
||||
pub fn key(&self) -> Option<&'src str> {
|
||||
self.key
|
||||
}
|
||||
pub fn element_id(&self) -> Option<ElementId> {
|
||||
self.dom_id.get()
|
||||
pub fn direct_id(&self) -> ElementId {
|
||||
self.try_direct_id().unwrap()
|
||||
}
|
||||
pub fn try_direct_id(&self) -> Option<ElementId> {
|
||||
match &self.kind {
|
||||
VNodeKind::Text(el) => el.dom_id.get(),
|
||||
VNodeKind::Element(el) => el.dom_id.get(),
|
||||
VNodeKind::Anchor(el) => el.dom_id.get(),
|
||||
VNodeKind::Fragment(_) => None,
|
||||
VNodeKind::Component(_) => None,
|
||||
VNodeKind::Suspended(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,11 +55,18 @@ pub enum VNodeKind<'src> {
|
||||
|
||||
Component(&'src VComponent<'src>),
|
||||
|
||||
Suspended { node: Rc<Cell<Option<ElementId>>> },
|
||||
Suspended(VSuspended),
|
||||
|
||||
Anchor(VAnchor),
|
||||
}
|
||||
|
||||
pub struct VAnchor {
|
||||
pub dom_id: Cell<Option<ElementId>>,
|
||||
}
|
||||
|
||||
pub struct VText<'src> {
|
||||
pub text: &'src str,
|
||||
pub dom_id: Cell<Option<ElementId>>,
|
||||
pub is_static: bool,
|
||||
}
|
||||
|
||||
@@ -77,6 +92,7 @@ pub struct VElement<'a> {
|
||||
// tag is always static
|
||||
pub tag_name: &'static str,
|
||||
pub namespace: Option<&'static str>,
|
||||
pub dom_id: Cell<Option<ElementId>>,
|
||||
|
||||
pub static_listeners: bool,
|
||||
pub listeners: &'a [Listener<'a>],
|
||||
@@ -110,8 +126,6 @@ pub struct Listener<'bump> {
|
||||
/// The type of event to listen for.
|
||||
pub(crate) event: &'static str,
|
||||
|
||||
pub scope: ScopeId,
|
||||
|
||||
pub mounted_node: Cell<Option<ElementId>>,
|
||||
|
||||
pub(crate) callback: RefCell<Option<BumpBox<'bump, dyn FnMut(VirtualEvent) + 'bump>>>,
|
||||
@@ -150,27 +164,42 @@ pub struct VComponent<'src> {
|
||||
pub(crate) user_fc: *const (),
|
||||
}
|
||||
|
||||
pub struct VSuspended {
|
||||
pub node: Rc<Cell<Option<ElementId>>>,
|
||||
}
|
||||
|
||||
/// This struct provides an ergonomic API to quickly build VNodes.
|
||||
///
|
||||
/// NodeFactory is used to build VNodes in the component's memory space.
|
||||
/// This struct adds metadata to the final VNode about listeners, attributes, and children
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct NodeFactory<'a> {
|
||||
pub scope: &'a Scope,
|
||||
pub(crate) bump: &'a Bump,
|
||||
}
|
||||
|
||||
impl<'a> NodeFactory<'a> {
|
||||
pub fn new(bump: &'a Bump) -> NodeFactory<'a> {
|
||||
NodeFactory { bump }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bump(&self) -> &'a bumpalo::Bump {
|
||||
&self.scope.frames.wip_frame().bump
|
||||
&self.bump
|
||||
}
|
||||
|
||||
pub fn render_directly<F>(&self, lazy_nodes: LazyNodes<'a, F>) -> DomTree<'a>
|
||||
where
|
||||
F: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
Some(lazy_nodes.into_vnode(NodeFactory { bump: self.bump }))
|
||||
}
|
||||
|
||||
pub fn unstable_place_holder() -> VNode<'static> {
|
||||
VNode {
|
||||
dom_id: empty_cell(),
|
||||
key: None,
|
||||
kind: VNodeKind::Text(VText {
|
||||
text: "",
|
||||
dom_id: empty_cell(),
|
||||
is_static: true,
|
||||
}),
|
||||
}
|
||||
@@ -179,9 +208,9 @@ impl<'a> NodeFactory<'a> {
|
||||
/// Used in a place or two to make it easier to build vnodes from dummy text
|
||||
pub fn static_text(&self, text: &'static str) -> VNode<'a> {
|
||||
VNode {
|
||||
dom_id: empty_cell(),
|
||||
key: None,
|
||||
kind: VNodeKind::Text(VText {
|
||||
dom_id: empty_cell(),
|
||||
text,
|
||||
is_static: true,
|
||||
}),
|
||||
@@ -208,9 +237,12 @@ impl<'a> NodeFactory<'a> {
|
||||
pub fn text(&self, args: Arguments) -> VNode<'a> {
|
||||
let (text, is_static) = self.raw_text(args);
|
||||
VNode {
|
||||
dom_id: empty_cell(),
|
||||
key: None,
|
||||
kind: VNodeKind::Text(VText { text, is_static }),
|
||||
kind: VNodeKind::Text(VText {
|
||||
text,
|
||||
is_static,
|
||||
dom_id: empty_cell(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,19 +292,7 @@ impl<'a> NodeFactory<'a> {
|
||||
let children: &'a V = self.bump().alloc(children);
|
||||
let children = children.as_ref();
|
||||
|
||||
// We take the references directly from the bump arena
|
||||
//
|
||||
// TODO: this code shouldn't necessarily be here of all places
|
||||
// It would make more sense to do this in diffing
|
||||
|
||||
let mut queue = self.scope.listeners.borrow_mut();
|
||||
for listener in listeners.iter() {
|
||||
let long_listener: &'a Listener<'static> = unsafe { std::mem::transmute(listener) };
|
||||
queue.push(long_listener as *const _)
|
||||
}
|
||||
|
||||
VNode {
|
||||
dom_id: empty_cell(),
|
||||
key,
|
||||
kind: VNodeKind::Element(self.bump().alloc(VElement {
|
||||
tag_name: tag,
|
||||
@@ -280,6 +300,7 @@ impl<'a> NodeFactory<'a> {
|
||||
listeners,
|
||||
attributes,
|
||||
children,
|
||||
dom_id: empty_cell(),
|
||||
|
||||
// todo: wire up more constization
|
||||
static_listeners: false,
|
||||
@@ -291,11 +312,10 @@ impl<'a> NodeFactory<'a> {
|
||||
|
||||
pub fn suspended() -> VNode<'static> {
|
||||
VNode {
|
||||
dom_id: empty_cell(),
|
||||
key: None,
|
||||
kind: VNodeKind::Suspended {
|
||||
kind: VNodeKind::Suspended(VSuspended {
|
||||
node: Rc::new(empty_cell()),
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,7 +410,6 @@ impl<'a> NodeFactory<'a> {
|
||||
|
||||
VNode {
|
||||
key,
|
||||
dom_id: empty_cell(),
|
||||
kind: VNodeKind::Component(self.bump().alloc_with(|| VComponent {
|
||||
user_fc,
|
||||
comparator,
|
||||
@@ -430,7 +449,6 @@ impl<'a> NodeFactory<'a> {
|
||||
let children = node_iter.into_vnode_list(self);
|
||||
|
||||
VNode {
|
||||
dom_id: empty_cell(),
|
||||
key: None,
|
||||
kind: VNodeKind::Fragment(VFragment {
|
||||
children,
|
||||
@@ -491,6 +509,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if nodes.len() == 0 {
|
||||
nodes.push(VNode {
|
||||
kind: VNodeKind::Anchor(VAnchor {
|
||||
dom_id: empty_cell(),
|
||||
}),
|
||||
key: None,
|
||||
});
|
||||
}
|
||||
|
||||
nodes.into_bump_slice()
|
||||
}
|
||||
}
|
||||
@@ -625,8 +652,10 @@ impl Debug for NodeFactory<'_> {
|
||||
impl Debug for VNode<'_> {
|
||||
fn fmt(&self, s: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
|
||||
match &self.kind {
|
||||
VNodeKind::Element(el) => write!(s, "element, {}", el.tag_name),
|
||||
VNodeKind::Text(t) => write!(s, "text, {}", t.text),
|
||||
VNodeKind::Element(el) => write!(s, "VElement {{ name: {} }}", el.tag_name),
|
||||
VNodeKind::Text(t) => write!(s, "VText {{ text: {} }}", t.text),
|
||||
VNodeKind::Anchor(a) => write!(s, "VAnchor"),
|
||||
|
||||
VNodeKind::Fragment(_) => write!(s, "fragment"),
|
||||
VNodeKind::Suspended { .. } => write!(s, "suspended"),
|
||||
VNodeKind::Component(_) => write!(s, "component"),
|
||||
|
||||
+35
-10
@@ -1,5 +1,6 @@
|
||||
use crate::innerlude::*;
|
||||
use bumpalo::boxed::Box as BumpBox;
|
||||
use fxhash::FxHashSet;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
borrow::BorrowMut,
|
||||
@@ -24,13 +25,15 @@ pub struct Scope {
|
||||
pub(crate) parent_idx: Option<ScopeId>,
|
||||
pub(crate) our_arena_idx: ScopeId,
|
||||
pub(crate) height: u32,
|
||||
pub(crate) descendents: RefCell<HashSet<ScopeId>>,
|
||||
pub(crate) descendents: RefCell<FxHashSet<ScopeId>>,
|
||||
|
||||
// Nodes
|
||||
// an internal, highly efficient storage of vnodes
|
||||
// lots of safety condsiderations
|
||||
pub(crate) frames: ActiveFrame,
|
||||
pub(crate) caller: Rc<WrappedCaller>,
|
||||
pub(crate) child_nodes: ScopeChildren<'static>,
|
||||
pub(crate) pending_garbage: RefCell<Vec<*const VNode<'static>>>,
|
||||
|
||||
// Listeners
|
||||
pub(crate) listeners: RefCell<Vec<*const Listener<'static>>>,
|
||||
@@ -67,11 +70,18 @@ impl Scope {
|
||||
height: u32,
|
||||
|
||||
child_nodes: ScopeChildren,
|
||||
// child_nodes: &'creator_node [VNode<'creator_node>],
|
||||
|
||||
vdom: SharedResources,
|
||||
) -> Self {
|
||||
let child_nodes = unsafe { child_nodes.extend_lifetime() };
|
||||
|
||||
// insert ourself as a descendent of the parent
|
||||
// when the parent is removed, this map will be traversed, and we will also be cleaned up.
|
||||
if let Some(parent) = &parent {
|
||||
let parent = unsafe { vdom.get_scope(*parent) }.unwrap();
|
||||
parent.descendents.borrow_mut().insert(arena_idx);
|
||||
}
|
||||
|
||||
Self {
|
||||
child_nodes,
|
||||
caller,
|
||||
@@ -80,10 +90,12 @@ impl Scope {
|
||||
height,
|
||||
vdom,
|
||||
frames: ActiveFrame::new(),
|
||||
|
||||
hooks: Default::default(),
|
||||
shared_contexts: Default::default(),
|
||||
listeners: Default::default(),
|
||||
descendents: Default::default(),
|
||||
pending_garbage: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +114,9 @@ impl Scope {
|
||||
// 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
|
||||
if !self.pending_garbage.borrow().is_empty() {
|
||||
panic!("cannot run scope while garbage is pending! Please clean up your mess first");
|
||||
}
|
||||
|
||||
log::debug!("reset okay");
|
||||
|
||||
@@ -189,11 +204,11 @@ impl Scope {
|
||||
if let Some(raw_listener) = raw_listener {
|
||||
let listener = unsafe { &**raw_listener };
|
||||
|
||||
log::info!(
|
||||
"calling listener {:?}, {:?}",
|
||||
listener.event,
|
||||
listener.scope
|
||||
);
|
||||
// log::info!(
|
||||
// "calling listener {:?}, {:?}",
|
||||
// listener.event,
|
||||
// // listener.scope
|
||||
// );
|
||||
let mut cb = listener.callback.borrow_mut();
|
||||
if let Some(cb) = cb.as_mut() {
|
||||
(cb)(event);
|
||||
@@ -209,10 +224,20 @@ impl Scope {
|
||||
self.frames.fin_head()
|
||||
}
|
||||
|
||||
// #[inline]
|
||||
pub fn child_nodes<'a>(&'a self) -> ScopeChildren {
|
||||
// self.child_nodes
|
||||
unsafe { self.child_nodes.unextend_lfetime() }
|
||||
// unsafe { std::mem::transmute(self.child_nodes) }
|
||||
}
|
||||
|
||||
pub fn consume_garbage(&self) -> Vec<&VNode> {
|
||||
let mut garbage = self.pending_garbage.borrow_mut();
|
||||
garbage
|
||||
.drain(..)
|
||||
.map(|node| {
|
||||
// safety: scopes cannot cycle without their garbage being collected. these nodes are safe
|
||||
let node: &VNode<'static> = unsafe { &*node };
|
||||
let node: &VNode = unsafe { std::mem::transmute(node) };
|
||||
node
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ use crate::innerlude::*;
|
||||
// create a cell with a "none" value
|
||||
#[inline]
|
||||
pub fn empty_cell() -> Cell<Option<ElementId>> {
|
||||
Cell::new(None as Option<ElementId>)
|
||||
Cell::new(None)
|
||||
}
|
||||
|
||||
/// A helper type that lets scopes be ordered by their height
|
||||
|
||||
@@ -25,7 +25,7 @@ use crate::{arena::SharedResources, innerlude::*};
|
||||
use std::any::Any;
|
||||
|
||||
use std::any::TypeId;
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{Ref, RefCell, RefMut};
|
||||
use std::pin::Pin;
|
||||
|
||||
/// An integrated virtual node system that progresses events and diffs UI trees.
|
||||
@@ -193,8 +193,8 @@ impl VirtualDom {
|
||||
|
||||
// We run the component. If it succeeds, then we can diff it and add the changes to the dom.
|
||||
if cur_component.run_scope().is_ok() {
|
||||
let meta = diff_machine.create(cur_component.frames.fin_head());
|
||||
diff_machine.append_children(meta.added_to_stack);
|
||||
let meta = diff_machine.create_vnode(cur_component.frames.fin_head());
|
||||
diff_machine.edit_append_children(meta.added_to_stack);
|
||||
} else {
|
||||
// todo: should this be a hard error?
|
||||
log::warn!(
|
||||
@@ -269,6 +269,47 @@ impl VirtualDom {
|
||||
let mut diff_machine = DiffMachine::new(edits, realdom, trigger.originator, &self.shared);
|
||||
|
||||
match &trigger.event {
|
||||
// When a scope gets destroyed during a diff, it gets its own garbage collection event
|
||||
// However, an old scope might be attached
|
||||
VirtualEvent::GarbageCollection => {
|
||||
let scope = diff_machine.get_scope_mut(&trigger.originator).unwrap();
|
||||
|
||||
let mut garbage_list = scope.consume_garbage();
|
||||
|
||||
while let Some(node) = garbage_list.pop() {
|
||||
match &node.kind {
|
||||
VNodeKind::Text(_) => {
|
||||
//
|
||||
self.shared.collect_garbage(node.direct_id())
|
||||
}
|
||||
VNodeKind::Anchor(anchor) => {
|
||||
//
|
||||
}
|
||||
|
||||
VNodeKind::Element(el) => {
|
||||
self.shared.collect_garbage(node.direct_id());
|
||||
for child in el.children {
|
||||
garbage_list.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
VNodeKind::Fragment(frag) => {
|
||||
for child in frag.children {
|
||||
garbage_list.push(child);
|
||||
}
|
||||
}
|
||||
VNodeKind::Component(comp) => {
|
||||
// run the destructors
|
||||
todo!();
|
||||
}
|
||||
VNodeKind::Suspended(node) => {
|
||||
// make sure the task goes away
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing yet
|
||||
VirtualEvent::AsyncEvent { .. } => {}
|
||||
|
||||
@@ -295,13 +336,13 @@ impl VirtualDom {
|
||||
|
||||
// push the old node's root onto the stack
|
||||
let real_id = domnode.get().ok_or(Error::NotMounted)?;
|
||||
diff_machine.push_root(real_id);
|
||||
diff_machine.edit_push_root(real_id);
|
||||
|
||||
// push these new nodes onto the diff machines stack
|
||||
let meta = diff_machine.create(&*nodes);
|
||||
let meta = diff_machine.create_vnode(&*nodes);
|
||||
|
||||
// replace the placeholder with the new nodes we just pushed on the stack
|
||||
diff_machine.replace_with(meta.added_to_stack);
|
||||
diff_machine.edit_replace_with(meta.added_to_stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -330,7 +371,7 @@ impl VirtualDom {
|
||||
|
||||
// Make sure this isn't a node we've already seen, we don't want to double-render anything
|
||||
// If we double-renderer something, this would cause memory safety issues
|
||||
if diff_machine.seen_nodes.contains(&update.idx) {
|
||||
if diff_machine.seen_scopes.contains(&update.idx) {
|
||||
log::debug!("Skipping update for: {:#?}", update);
|
||||
continue;
|
||||
}
|
||||
@@ -342,7 +383,7 @@ impl VirtualDom {
|
||||
.expect("Failed to find scope or borrow would be aliasing");
|
||||
|
||||
// Now, all the "seen nodes" are nodes that got notified by running this listener
|
||||
diff_machine.seen_nodes.insert(update.idx.clone());
|
||||
diff_machine.seen_scopes.insert(update.idx.clone());
|
||||
|
||||
if cur_component.run_scope().is_ok() {
|
||||
let (old, new) = (
|
||||
|
||||
Reference in new issue
Block a user