wip: more work on bumpframe

This commit is contained in:
Jonathan Kelley committed 2021-07-29 00:04:59 -04:00
1 parent 49856ccd68
commit 63a85e4865
4 files changed
+230 -253

No files matched your search

+7 -7
View File
@@ -15,7 +15,7 @@ pub struct BumpFrame {
pub(crate) head_node: VNode<'static>, pub(crate) head_node: VNode<'static>,
// used internally for debugging // used internally for debugging
name: &'static str, _name: &'static str,
} }
impl ActiveFrame { impl ActiveFrame {
@@ -23,12 +23,12 @@ impl ActiveFrame {
let frame_a = BumpFrame { let frame_a = BumpFrame {
bump: Bump::new(), bump: Bump::new(),
head_node: NodeFactory::unstable_place_holder(), head_node: NodeFactory::unstable_place_holder(),
name: "wip", _name: "wip",
}; };
let frame_b = BumpFrame { let frame_b = BumpFrame {
bump: Bump::new(), bump: Bump::new(),
head_node: NodeFactory::unstable_place_holder(), head_node: NodeFactory::unstable_place_holder(),
name: "fin", _name: "fin",
}; };
Self { Self {
generation: 0.into(), generation: 0.into(),
@@ -103,14 +103,14 @@ mod tests {
for _ in 0..5 { for _ in 0..5 {
let fin = frames.finished_frame(); let fin = frames.finished_frame();
let wip = frames.wip_frame(); let wip = frames.wip_frame();
assert_eq!(wip.name, "wip"); assert_eq!(wip._name, "wip");
assert_eq!(fin.name, "fin"); assert_eq!(fin._name, "fin");
frames.cycle_frame(); frames.cycle_frame();
let fin = frames.finished_frame(); let fin = frames.finished_frame();
let wip = frames.wip_frame(); let wip = frames.wip_frame();
assert_eq!(wip.name, "fin"); assert_eq!(wip._name, "fin");
assert_eq!(fin.name, "wip"); assert_eq!(fin._name, "wip");
frames.cycle_frame(); frames.cycle_frame();
} }
assert_eq!(frames.generation.get(), 10); assert_eq!(frames.generation.get(), 10);
+219 -106
View File
@@ -55,7 +55,8 @@ use crate::{arena::SharedResources, innerlude::*};
use fxhash::{FxHashMap, FxHashSet}; use fxhash::{FxHashMap, FxHashSet};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use std::{any::Any, cmp::Ordering, process::Child}; use std::{any::Any, cell::Cell, cmp::Ordering};
use DomEdit::*;
/// Instead of having handles directly over nodes, Dioxus uses simple u32 as node IDs. /// Instead of having handles directly over nodes, Dioxus uses simple u32 as node IDs.
/// The expectation is that the underlying renderer will mainain their Nodes in vec where the ids are the index. This allows /// The expectation is that the underlying renderer will mainain their Nodes in vec where the ids are the index. This allows
@@ -74,7 +75,7 @@ pub struct DiffMachine<'real, 'bump> {
pub vdom: &'bump SharedResources, pub vdom: &'bump SharedResources,
pub edits: DomEditor<'real, 'bump>, pub edits: &'real mut Vec<DomEdit<'bump>>,
pub scheduled_garbage: Vec<&'bump VNode<'bump>>, pub scheduled_garbage: Vec<&'bump VNode<'bump>>,
@@ -94,7 +95,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
) -> Self { ) -> Self {
Self { Self {
real_dom: dom, real_dom: dom,
edits: DomEditor::new(edits), edits,
cur_idxs: smallvec![cur_idx], cur_idxs: smallvec![cur_idx],
vdom: shared, vdom: shared,
scheduled_garbage: vec![], scheduled_garbage: vec![],
@@ -120,9 +121,9 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
let root = root.unwrap(); let root = root.unwrap();
if old.text != new.text { if old.text != new.text {
self.edits.push_root(root); self.push_root(root);
self.edits.set_text(new.text); self.set_text(new.text);
self.edits.pop(); self.pop();
} }
new_node.dom_id.set(Some(root)); new_node.dom_id.set(Some(root));
@@ -136,11 +137,11 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// //
// This case is rather rare (typically only in non-keyed lists) // This case is rather rare (typically only in non-keyed lists)
if new.tag_name != old.tag_name || new.namespace != old.namespace { if new.tag_name != old.tag_name || new.namespace != old.namespace {
self.edits.push_root(root); self.push_root(root);
let meta = self.create(new_node); let meta = self.create(new_node);
self.edits.replace_with(meta.added_to_stack); self.replace_with(meta.added_to_stack);
self.scheduled_garbage.push(old_node); self.scheduled_garbage.push(old_node);
self.edits.pop(); self.pop();
return; return;
} }
@@ -148,10 +149,10 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// Don't push the root if we don't have to // Don't push the root if we don't have to
let mut has_comitted = false; let mut has_comitted = false;
let mut please_commit = |edits: &mut DomEditor| { let mut please_commit = |edits: &mut Vec<DomEdit>| {
if !has_comitted { if !has_comitted {
has_comitted = true; has_comitted = true;
edits.push_root(root); edits.push(PushRoot { id: root.as_u64() });
} }
}; };
@@ -165,17 +166,17 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
for (old_attr, new_attr) in old.attributes.iter().zip(new.attributes.iter()) { for (old_attr, new_attr) in old.attributes.iter().zip(new.attributes.iter()) {
if old_attr.value != new_attr.value { if old_attr.value != new_attr.value {
please_commit(&mut self.edits); please_commit(&mut self.edits);
self.edits.set_attribute(new_attr); self.set_attribute(new_attr);
} }
} }
} else { } else {
// TODO: provide some sort of report on how "good" the diffing was // TODO: provide some sort of report on how "good" the diffing was
please_commit(&mut self.edits); please_commit(&mut self.edits);
for attribute in old.attributes { for attribute in old.attributes {
self.edits.remove_attribute(attribute); self.remove_attribute(attribute);
} }
for attribute in new.attributes { for attribute in new.attributes {
self.edits.set_attribute(attribute) self.set_attribute(attribute)
} }
} }
@@ -189,29 +190,29 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
for (old_l, new_l) in old.listeners.iter().zip(new.listeners.iter()) { for (old_l, new_l) in old.listeners.iter().zip(new.listeners.iter()) {
if old_l.event != new_l.event { if old_l.event != new_l.event {
please_commit(&mut self.edits); please_commit(&mut self.edits);
self.edits.remove_event_listener(old_l.event); self.remove_event_listener(old_l.event);
self.edits.new_event_listener(new_l); self.new_event_listener(new_l);
} }
new_l.mounted_node.set(old_l.mounted_node.get()); new_l.mounted_node.set(old_l.mounted_node.get());
} }
} else { } else {
please_commit(&mut self.edits); please_commit(&mut self.edits);
for listener in old.listeners { for listener in old.listeners {
self.edits.remove_event_listener(listener.event); self.remove_event_listener(listener.event);
} }
for listener in new.listeners { for listener in new.listeners {
listener.mounted_node.set(Some(root)); listener.mounted_node.set(Some(root));
self.edits.new_event_listener(listener); self.new_event_listener(listener);
} }
} }
if has_comitted { if has_comitted {
self.edits.pop(); self.pop();
} }
// Each child pushes its own root, so it doesn't need our current root // Each child pushes its own root, so it doesn't need our current root
todo!();
// self.diff_children(old.children, new.children); self.diff_children(old.children, new.children, None, &mut None);
} }
(VNodeKind::Component(old), VNodeKind::Component(new)) => { (VNodeKind::Component(old), VNodeKind::Component(new)) => {
@@ -249,7 +250,6 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
self.seen_nodes.insert(scope_addr); self.seen_nodes.insert(scope_addr);
} else { } else {
// this seems to be a fairy common code path that we could
let mut old_iter = RealChildIterator::new(old_node, &self.vdom); let mut old_iter = RealChildIterator::new(old_node, &self.vdom);
let first = old_iter let first = old_iter
.next() .next()
@@ -257,16 +257,16 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// remove any leftovers // remove any leftovers
for to_remove in old_iter { for to_remove in old_iter {
self.edits.push_root(to_remove.element_id().unwrap()); self.push_root(to_remove.element_id().unwrap());
self.edits.remove(); self.remove();
} }
// seems like we could combine this into a single instruction.... // seems like we could combine this into a single instruction....
self.edits.push_root(first.element_id().unwrap()); self.push_root(first.element_id().unwrap());
let meta = self.create(new_node); let meta = self.create(new_node);
self.edits.replace_with(meta.added_to_stack); self.replace_with(meta.added_to_stack);
self.scheduled_garbage.push(old_node); self.scheduled_garbage.push(old_node);
self.edits.pop(); self.pop();
// Wipe the old one and plant the new one // Wipe the old one and plant the new one
let old_scope = old.ass_scope.get().unwrap(); let old_scope = old.ass_scope.get().unwrap();
@@ -282,7 +282,16 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
return; return;
} }
self.diff_children(old, new, old, new_anchor) let mut new_anchor = None;
self.diff_children(
old.children,
new.children,
old_node.dom_id.get(),
&mut new_anchor,
);
if let Some(anchor) = new_anchor {
new_node.dom_id.set(Some(anchor));
}
} }
// The strategy here is to pick the first possible node from the previous set and use that as our replace with root // The strategy here is to pick the first possible node from the previous set and use that as our replace with root
@@ -326,8 +335,8 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// remove any leftovers // remove any leftovers
for to_remove in old_iter { for to_remove in old_iter {
self.edits.push_root(to_remove.element_id().unwrap()); self.push_root(to_remove.element_id().unwrap());
self.edits.remove(); self.remove();
} }
back_node.element_id().unwrap() back_node.element_id().unwrap()
@@ -335,9 +344,9 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
}; };
// replace the placeholder or first node with the nodes generated from the "new" // replace the placeholder or first node with the nodes generated from the "new"
self.edits.push_root(back_node_id); self.push_root(back_node_id);
let meta = self.create(new_node); let meta = self.create(new_node);
self.edits.replace_with(meta.added_to_stack); self.replace_with(meta.added_to_stack);
// todo use the is_static metadata to update this subtree // todo use the is_static metadata to update this subtree
} }
@@ -365,7 +374,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
match &node.kind { match &node.kind {
VNodeKind::Text(text) => { VNodeKind::Text(text) => {
let real_id = self.vdom.reserve_node(); let real_id = self.vdom.reserve_node();
self.edits.create_text_node(text.text, real_id); self.create_text_node(text.text, real_id);
node.dom_id.set(Some(real_id)); node.dom_id.set(Some(real_id));
CreateMeta::new(text.is_static, 1) CreateMeta::new(text.is_static, 1)
@@ -391,17 +400,16 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
let real_id = self.vdom.reserve_node(); let real_id = self.vdom.reserve_node();
if let Some(namespace) = namespace { if let Some(namespace) = namespace {
self.edits self.create_element(tag_name, Some(namespace), real_id)
.create_element(tag_name, Some(namespace), real_id)
} else { } else {
self.edits.create_element(tag_name, None, real_id) self.create_element(tag_name, None, real_id)
}; };
node.dom_id.set(Some(real_id)); node.dom_id.set(Some(real_id));
listeners.iter().for_each(|listener| { listeners.iter().for_each(|listener| {
log::info!("setting listener id to {:#?}", real_id); log::info!("setting listener id to {:#?}", real_id);
listener.mounted_node.set(Some(real_id)); listener.mounted_node.set(Some(real_id));
self.edits.new_event_listener(listener); self.new_event_listener(listener);
// if the node has an event listener, then it must be visited ? // if the node has an event listener, then it must be visited ?
is_static = false; is_static = false;
@@ -409,7 +417,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
for attr in *attributes { for attr in *attributes {
is_static = is_static && attr.is_static; is_static = is_static && attr.is_static;
self.edits.set_attribute(attr); self.set_attribute(attr);
} }
// Fast path: if there is a single text child, it is faster to // Fast path: if there is a single text child, it is faster to
@@ -424,7 +432,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// TODO move over // TODO move over
// if children.len() == 1 { // if children.len() == 1 {
// if let VNodeKind::Text(text) = &children[0].kind { // if let VNodeKind::Text(text) = &children[0].kind {
// self.edits.set_text(text.text); // self.set_text(text.text);
// return CreateMeta::new(is_static, 1); // return CreateMeta::new(is_static, 1);
// } // }
// } // }
@@ -434,7 +442,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
is_static = is_static && child_meta.is_static; is_static = is_static && child_meta.is_static;
// append whatever children were generated by this call // append whatever children were generated by this call
self.edits.append_children(child_meta.added_to_stack); self.append_children(child_meta.added_to_stack);
} }
// if is_static { // if is_static {
@@ -520,7 +528,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
VNodeKind::Suspended { node: real_node } => { VNodeKind::Suspended { node: real_node } => {
let id = self.vdom.reserve_node(); let id = self.vdom.reserve_node();
self.edits.create_placeholder(id); self.create_placeholder(id);
node.dom_id.set(Some(id)); node.dom_id.set(Some(id));
real_node.set(Some(id)); real_node.set(Some(id));
CreateMeta::new(false, 1) CreateMeta::new(false, 1)
@@ -594,7 +602,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
&mut self, &mut self,
old: &'bump [VNode<'bump>], old: &'bump [VNode<'bump>],
new: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>],
old_anchor: &mut Option<ElementId>, old_anchor: Option<ElementId>,
new_anchor: &mut Option<ElementId>, new_anchor: &mut Option<ElementId>,
) { ) {
const IS_EMPTY: bool = true; const IS_EMPTY: bool = true;
@@ -602,33 +610,36 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
match (old_anchor, new.is_empty()) { match (old_anchor, new.is_empty()) {
// Both are empty, dealing only with potential anchors // Both are empty, dealing only with potential anchors
(Some(_), IS_EMPTY) => { (Some(anchor), IS_EMPTY) => {
*new_anchor = *old_anchor; // new_anchor.set(Some(anchor));
if old.len() > 0 { if old.len() > 0 {
// clean up these virtual nodes (components, fragments, etc) // clean up these virtual nodes (components, fragments, etc)
} }
} }
// Completely adding new nodes, removing any placeholder if it exists // Completely adding new nodes, removing any placeholder if it exists
(Some(anchor), IS_NOT_EMPTY) => match old_anchor { (Some(anchor), IS_NOT_EMPTY) => {
//
// match old_anchor {
// If there's anchor to work from, then we replace it with the new children // If there's anchor to work from, then we replace it with the new children
Some(anchor) => { // Some(anchor) => {
self.edits.push_root(*anchor); self.push_root(anchor);
let meta = self.create_children(new); let meta = self.create_children(new);
if meta.added_to_stack > 0 { if meta.added_to_stack > 0 {
self.edits.replace_with(meta.added_to_stack) self.replace_with(meta.added_to_stack)
} else { } else {
// no items added to the stack... hmmmm.... // no items added to the stack... hmmmm....
*new_anchor = *old_anchor; *new_anchor = old_anchor;
}
} }
// }
// If there's no anchor to work with, we just straight up append them // If there's no anchor to work with, we just straight up append them
None => { // None => {
let meta = self.create_children(new); let meta = self.create_children(new);
self.edits.append_children(meta.added_to_stack); self.append_children(meta.added_to_stack);
} // }
}, // }
}
// Completely removing old nodes and putting an anchor in its place // Completely removing old nodes and putting an anchor in its place
// no anchor (old has nodes) and the new is empty // no anchor (old has nodes) and the new is empty
@@ -637,24 +648,24 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// load the first real // load the first real
if let Some(to_replace) = find_first_real_node(old, self.vdom) { if let Some(to_replace) = find_first_real_node(old, self.vdom) {
// //
self.edits.push_root(to_replace.dom_id.get().unwrap()); self.push_root(to_replace.dom_id.get().unwrap());
// Create the anchor // Create the anchor
let anchor_id = self.vdom.reserve_node(); let anchor_id = self.vdom.reserve_node();
self.edits.create_placeholder(anchor_id); self.create_placeholder(anchor_id);
*new_anchor = Some(anchor_id); // *new_anchor = Some(anchor_id);
// Replace that node // Replace that node
self.edits.replace_with(1); self.replace_with(1);
} else { } else {
// no real nodes - // no real nodes -
*new_anchor = *old_anchor; // new_anchor.set(old_anchor);
} }
// remove the rest // remove the rest
for child in &old[1..] { for child in &old[1..] {
self.edits.push_root(child.element_id().unwrap()); self.push_root(child.element_id().unwrap());
self.edits.remove(); self.remove();
} }
} }
@@ -784,7 +795,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
old: &'bump [VNode<'bump>], old: &'bump [VNode<'bump>],
new: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>],
) -> KeyedPrefixResult { ) -> KeyedPrefixResult {
// self.edits.go_down(); // self.go_down();
let mut shared_prefix_count = 0; let mut shared_prefix_count = 0;
@@ -794,7 +805,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
break; break;
} }
// self.edits.go_to_sibling(i); // self.go_to_sibling(i);
self.diff_node(old, new); self.diff_node(old, new);
@@ -804,8 +815,8 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// If that was all of the old children, then create and append the remaining // If that was all of the old children, then create and append the remaining
// new children and we're finished. // new children and we're finished.
if shared_prefix_count == old.len() { if shared_prefix_count == old.len() {
// self.edits.go_up(); // self.go_up();
// self.edits.commit_traversal(); // self.commit_traversal();
self.create_and_append_children(&new[shared_prefix_count..]); self.create_and_append_children(&new[shared_prefix_count..]);
return KeyedPrefixResult::Finished; return KeyedPrefixResult::Finished;
} }
@@ -813,13 +824,13 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// And if that was all of the new children, then remove all of the remaining // And if that was all of the new children, then remove all of the remaining
// old children and we're finished. // old children and we're finished.
if shared_prefix_count == new.len() { if shared_prefix_count == new.len() {
// self.edits.go_to_sibling(shared_prefix_count); // self.go_to_sibling(shared_prefix_count);
// self.edits.commit_traversal(); // self.commit_traversal();
self.remove_self_and_next_siblings(&old[shared_prefix_count..]); self.remove_self_and_next_siblings(&old[shared_prefix_count..]);
return KeyedPrefixResult::Finished; return KeyedPrefixResult::Finished;
} }
// //
// self.edits.go_up(); // self.go_up();
KeyedPrefixResult::MoreWorkToDo(shared_prefix_count) KeyedPrefixResult::MoreWorkToDo(shared_prefix_count)
} }
@@ -831,7 +842,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// //
// When this function returns, the change list stack is in the same state. // When this function returns, the change list stack is in the same state.
fn remove_all_children(&mut self, old: &'bump [VNode<'bump>]) { fn remove_all_children(&mut self, old: &'bump [VNode<'bump>]) {
// debug_assert!(self.edits.traversal_is_committed()); // debug_assert!(self.traversal_is_committed());
log::debug!("REMOVING CHILDREN"); log::debug!("REMOVING CHILDREN");
for _child in old { for _child in old {
// registry.remove_subtree(child); // registry.remove_subtree(child);
@@ -839,7 +850,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// Fast way to remove all children: set the node's textContent to an empty // Fast way to remove all children: set the node's textContent to an empty
// string. // string.
todo!() todo!()
// self.edits.set_inner_text(""); // self.set_inner_text("");
} }
// Create the given children and append them to the parent node. // Create the given children and append them to the parent node.
@@ -852,7 +863,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
pub fn create_and_append_children(&mut self, new: &'bump [VNode<'bump>]) { pub fn create_and_append_children(&mut self, new: &'bump [VNode<'bump>]) {
for child in new { for child in new {
let meta = self.create(child); let meta = self.create(child);
self.edits.append_children(meta.added_to_stack); self.append_children(meta.added_to_stack);
} }
} }
@@ -919,11 +930,11 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// // afresh. // // afresh.
// if shared_suffix_count == 0 && shared_keys.is_empty() { // if shared_suffix_count == 0 && shared_keys.is_empty() {
// if shared_prefix_count == 0 { // if shared_prefix_count == 0 {
// // self.edits.commit_traversal(); // // self.commit_traversal();
// self.remove_all_children(old); // self.remove_all_children(old);
// } else { // } else {
// // self.edits.go_down_to_child(shared_prefix_count); // // self.go_down_to_child(shared_prefix_count);
// // self.edits.commit_traversal(); // // self.commit_traversal();
// self.remove_self_and_next_siblings(&old[shared_prefix_count..]); // self.remove_self_and_next_siblings(&old[shared_prefix_count..]);
// } // }
@@ -945,8 +956,8 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// .unwrap_or(old.len()); // .unwrap_or(old.len());
// if end - start > 0 { // if end - start > 0 {
// // self.edits.commit_traversal(); // // self.commit_traversal();
// let mut t = self.edits.save_children_to_temporaries( // let mut t = self.save_children_to_temporaries(
// shared_prefix_count + start, // shared_prefix_count + start,
// shared_prefix_count + end, // shared_prefix_count + end,
// ); // );
@@ -971,9 +982,9 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// if !shared_keys.contains(&old_child.key()) { // if !shared_keys.contains(&old_child.key()) {
// // registry.remove_subtree(old_child); // // registry.remove_subtree(old_child);
// // todo // // todo
// // self.edits.commit_traversal(); // // self.commit_traversal();
// self.edits.remove(old_child.dom_id.get()); // self.remove(old_child.dom_id.get());
// self.edits.remove_child(i + shared_prefix_count); // self.remove_child(i + shared_prefix_count);
// removed_count += 1; // removed_count += 1;
// } // }
// } // }
@@ -1032,29 +1043,29 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// let old_index = new_index_to_old_index[last_index]; // let old_index = new_index_to_old_index[last_index];
// let temp = old_index_to_temp[old_index]; // let temp = old_index_to_temp[old_index];
// // [... parent] // // [... parent]
// self.edits.go_down_to_temp_child(temp); // self.go_down_to_temp_child(temp);
// // [... parent last] // // [... parent last]
// self.diff_node(&old[old_index], last); // self.diff_node(&old[old_index], last);
// if new_index_is_in_lis.contains(&last_index) { // if new_index_is_in_lis.contains(&last_index) {
// // Don't move it, since it is already where it needs to be. // // Don't move it, since it is already where it needs to be.
// } else { // } else {
// // self.edits.commit_traversal(); // // self.commit_traversal();
// // [... parent last] // // [... parent last]
// self.edits.append_child(); // self.append_child();
// // [... parent] // // [... parent]
// self.edits.go_down_to_temp_child(temp); // self.go_down_to_temp_child(temp);
// // [... parent last] // // [... parent last]
// } // }
// } else { // } else {
// // self.edits.commit_traversal(); // // self.commit_traversal();
// // [... parent] // // [... parent]
// self.create(last); // self.create(last);
// // [... parent last] // // [... parent last]
// self.edits.append_child(); // self.append_child();
// // [... parent] // // [... parent]
// self.edits.go_down_to_reverse_child(0); // self.go_down_to_reverse_child(0);
// // [... parent last] // // [... parent last]
// } // }
// } // }
@@ -1063,11 +1074,11 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// let old_index = new_index_to_old_index[new_index]; // let old_index = new_index_to_old_index[new_index];
// if old_index == u32::MAX as usize { // if old_index == u32::MAX as usize {
// debug_assert!(!shared_keys.contains(&new_child.key())); // debug_assert!(!shared_keys.contains(&new_child.key()));
// // self.edits.commit_traversal(); // // self.commit_traversal();
// // [... parent successor] // // [... parent successor]
// self.create(new_child); // self.create(new_child);
// // [... parent successor new_child] // // [... parent successor new_child]
// self.edits.insert_before(); // self.insert_before();
// // [... parent new_child] // // [... parent new_child]
// } else { // } else {
// debug_assert!(shared_keys.contains(&new_child.key())); // debug_assert!(shared_keys.contains(&new_child.key()));
@@ -1076,14 +1087,14 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// if new_index_is_in_lis.contains(&new_index) { // if new_index_is_in_lis.contains(&new_index) {
// // [... parent successor] // // [... parent successor]
// self.edits.go_to_temp_sibling(temp); // self.go_to_temp_sibling(temp);
// // [... parent new_child] // // [... parent new_child]
// } else { // } else {
// // self.edits.commit_traversal(); // // self.commit_traversal();
// // [... parent successor] // // [... parent successor]
// self.edits.push_temporary(temp); // self.push_temporary(temp);
// // [... parent successor new_child] // // [... parent successor new_child]
// self.edits.insert_before(); // self.insert_before();
// // [... parent new_child] // // [... parent new_child]
// } // }
@@ -1136,17 +1147,17 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
Ordering::Greater => { Ordering::Greater => {
for item in &old[new.len()..] { for item in &old[new.len()..] {
for i in RealChildIterator::new(item, self.vdom) { for i in RealChildIterator::new(item, self.vdom) {
self.edits.push_root(i.element_id().unwrap()); self.push_root(i.element_id().unwrap());
self.edits.remove(); self.remove();
} }
} }
} }
// old.len < new.len -> adding some nodes // old.len < new.len -> adding some nodes
Ordering::Less => { Ordering::Less => {
// [... parent last_child] // [... parent last_child]
// self.edits.go_up(); // self.go_up();
// [... parent] // [... parent]
// self.edits.commit_traversal(); // self.commit_traversal();
self.create_and_append_children(&new[old.len()..]); self.create_and_append_children(&new[old.len()..]);
} }
// old.len == new.len -> no nodes added/removed, but πerhaps changed // old.len == new.len -> no nodes added/removed, but πerhaps changed
@@ -1168,7 +1179,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// //
// [... parent] // [... parent]
fn remove_self_and_next_siblings(&self, old: &[VNode<'bump>]) { fn remove_self_and_next_siblings(&self, old: &[VNode<'bump>]) {
// debug_assert!(self.edits.traversal_is_committed()); // debug_assert!(self.traversal_is_committed());
for child in old { for child in old {
if let VNodeKind::Component(_vcomp) = child.kind { if let VNodeKind::Component(_vcomp) = child.kind {
// dom // dom
@@ -1182,7 +1193,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// }) // })
// let id = get_id(); // let id = get_id();
// *component.stable_addr.as_ref().borrow_mut() = Some(id); // *component.stable_addr.as_ref().borrow_mut() = Some(id);
// self.edits.save_known_root(id); // self.save_known_root(id);
// let scope = Rc::downgrade(&component.ass_scope); // let scope = Rc::downgrade(&component.ass_scope);
// self.lifecycle_events.push_back(LifeCycleEvent::Mount { // self.lifecycle_events.push_back(LifeCycleEvent::Mount {
// caller: Rc::downgrade(&component.caller), // caller: Rc::downgrade(&component.caller),
@@ -1194,7 +1205,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// registry.remove_subtree(child); // registry.remove_subtree(child);
} }
todo!() todo!()
// self.edits.remove_self_and_next_siblings(); // self.remove_self_and_next_siblings();
} }
pub fn get_scope_mut(&mut self, id: &ScopeId) -> Option<&'bump mut Scope> { pub fn get_scope_mut(&mut self, id: &ScopeId) -> Option<&'bump mut Scope> {
@@ -1209,6 +1220,108 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
// if we have, then we're trying to alias it, which is not allowed // if we have, then we're trying to alias it, which is not allowed
unsafe { self.vdom.get_scope(*id) } unsafe { self.vdom.get_scope(*id) }
} }
// Navigation
pub(crate) fn push_root(&mut self, root: ElementId) {
let id = root.as_u64();
self.edits.push(PushRoot { id });
}
pub(crate) fn pop(&mut self) {
self.edits.push(PopRoot {});
}
// Add Nodes to the dom
// add m nodes from the stack
pub(crate) fn append_children(&mut self, many: u32) {
self.edits.push(AppendChildren { many });
}
// replace the n-m node on the stack with the m nodes
// ends with the last element of the chain on the top of the stack
pub(crate) fn replace_with(&mut self, many: u32) {
self.edits.push(ReplaceWith { many });
}
// Remove Nodesfrom the dom
pub(crate) fn remove(&mut self) {
self.edits.push(Remove);
}
// Create
pub(crate) fn create_text_node(&mut self, text: &'bump str, id: ElementId) {
let id = id.as_u64();
self.edits.push(CreateTextNode { text, id });
}
pub(crate) fn create_element(
&mut self,
tag: &'static str,
ns: Option<&'static str>,
id: ElementId,
) {
let id = id.as_u64();
match ns {
Some(ns) => self.edits.push(CreateElementNs { id, ns, tag }),
None => self.edits.push(CreateElement { id, tag }),
}
}
// placeholders are nodes that don't get rendered but still exist as an "anchor" in the real dom
pub(crate) fn create_placeholder(&mut self, id: ElementId) {
let id = id.as_u64();
self.edits.push(CreatePlaceholder { id });
}
// events
pub(crate) fn new_event_listener(&mut self, listener: &Listener) {
let Listener {
event,
scope,
mounted_node,
..
} = listener;
let element_id = mounted_node.get().unwrap().as_u64();
self.edits.push(NewEventListener {
scope: scope.clone(),
event_name: event,
mounted_node_id: element_id,
});
}
pub(crate) fn remove_event_listener(&mut self, event: &'static str) {
self.edits.push(RemoveEventListener { event });
}
// modify
pub(crate) fn set_text(&mut self, text: &'bump str) {
self.edits.push(SetText { text });
}
pub(crate) fn set_attribute(&mut self, attribute: &'bump Attribute) {
let Attribute {
name,
value,
is_static,
is_volatile,
namespace,
} = attribute;
// field: &'static str,
// value: &'bump str,
// ns: Option<&'static str>,
self.edits.push(SetAttribute {
field: name,
value,
ns: *namespace,
});
}
pub(crate) fn remove_attribute(&mut self, attribute: &Attribute) {
let name = attribute.name;
self.edits.push(RemoveAttribute { name });
}
} }
// When we create new nodes, we need to propagate some information back up the call chain. // When we create new nodes, we need to propagate some information back up the call chain.
@@ -1237,11 +1350,11 @@ enum KeyedPrefixResult {
} }
fn find_first_real_node<'a>( fn find_first_real_node<'a>(
nodes: &'a [VNode<'a>], nodes: impl IntoIterator<Item = &'a VNode<'a>>,
scopes: &'a SharedResources, scopes: &'a SharedResources,
) -> Option<&'a VNode<'a>> { ) -> Option<&'a VNode<'a>> {
for node in nodes { for node in nodes {
let iter = RealChildIterator::new(node, scopes); let mut iter = RealChildIterator::new(node, scopes);
if let Some(node) = iter.next() { if let Some(node) = iter.next() {
return Some(node); return Some(node);
} }
+1 -137
View File
@@ -5,143 +5,7 @@
//! //!
//! //!
use crate::{ use crate::innerlude::ScopeId;
innerlude::{Attribute, Listener, ScopeId},
ElementId,
};
/// The `DomEditor` provides an imperative interface for the Diffing algorithm to plan out its changes.
///
/// However, the DomEditor only builds a change list - it does not apply them. In contrast with the "RealDom", the DomEditor
/// is cancellable and flushable. At any moment in time, Dioxus may choose to completely clear the edit list and start over.
///
/// This behavior is used in the cooperative scheduling algorithm.
pub struct DomEditor<'real, 'bump> {
pub edits: &'real mut Vec<DomEdit<'bump>>,
}
use DomEdit::*;
impl<'real, 'bump> DomEditor<'real, 'bump> {
pub fn new(edits: &'real mut Vec<DomEdit<'bump>>) -> Self {
Self { edits }
}
// Navigation
pub(crate) fn push_root(&mut self, root: ElementId) {
let id = root.as_u64();
self.edits.push(PushRoot { id });
}
#[inline]
pub(crate) fn pop(&mut self) {
self.edits.push(PopRoot {});
}
// Add Nodes to the dom
// add m nodes from the stack
#[inline]
pub(crate) fn append_children(&mut self, many: u32) {
self.edits.push(AppendChildren { many });
}
// replace the n-m node on the stack with the m nodes
// ends with the last element of the chain on the top of the stack
#[inline]
pub(crate) fn replace_with(&mut self, many: u32) {
self.edits.push(ReplaceWith { many });
}
// Remove Nodesfrom the dom
#[inline]
pub(crate) fn remove(&mut self) {
self.edits.push(Remove);
}
#[inline]
pub(crate) fn remove_all_children(&mut self) {
self.edits.push(RemoveAllChildren);
}
// Create
#[inline]
pub(crate) fn create_text_node(&mut self, text: &'bump str, id: ElementId) {
let id = id.as_u64();
self.edits.push(CreateTextNode { text, id });
}
pub(crate) fn create_element(
&mut self,
tag: &'static str,
ns: Option<&'static str>,
id: ElementId,
) {
let id = id.as_u64();
match ns {
Some(ns) => self.edits.push(CreateElementNs { id, ns, tag }),
None => self.edits.push(CreateElement { id, tag }),
}
}
// placeholders are nodes that don't get rendered but still exist as an "anchor" in the real dom
pub(crate) fn create_placeholder(&mut self, id: ElementId) {
let id = id.as_u64();
self.edits.push(CreatePlaceholder { id });
}
// events
pub(crate) fn new_event_listener(&mut self, listener: &Listener) {
let Listener {
event,
scope,
mounted_node,
..
} = listener;
let element_id = mounted_node.get().unwrap().as_u64();
self.edits.push(NewEventListener {
scope: scope.clone(),
event_name: event,
mounted_node_id: element_id,
});
}
#[inline]
pub(crate) fn remove_event_listener(&mut self, event: &'static str) {
self.edits.push(RemoveEventListener { event });
}
// modify
#[inline]
pub(crate) fn set_text(&mut self, text: &'bump str) {
self.edits.push(SetText { text });
}
#[inline]
pub(crate) fn set_attribute(&mut self, attribute: &'bump Attribute) {
let Attribute {
name,
value,
is_static,
is_volatile,
namespace,
} = attribute;
// field: &'static str,
// value: &'bump str,
// ns: Option<&'static str>,
self.edits.push(SetAttribute {
field: name,
value,
ns: *namespace,
});
}
#[inline]
pub(crate) fn remove_attribute(&mut self, attribute: &Attribute) {
let name = attribute.name;
self.edits.push(RemoveAttribute { name });
}
}
/// A `DomEdit` represents a serialzied form of the VirtualDom's trait-based API. This allows streaming edits across the /// A `DomEdit` represents a serialzied form of the VirtualDom's trait-based API. This allows streaming edits across the
/// network or through FFI boundaries. /// network or through FFI boundaries.
+3 -3
View File
@@ -194,7 +194,7 @@ impl VirtualDom {
// We run the component. If it succeeds, then we can diff it and add the changes to the dom. // 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() { if cur_component.run_scope().is_ok() {
let meta = diff_machine.create(cur_component.frames.fin_head()); let meta = diff_machine.create(cur_component.frames.fin_head());
diff_machine.edits.append_children(meta.added_to_stack); diff_machine.append_children(meta.added_to_stack);
} else { } else {
// todo: should this be a hard error? // todo: should this be a hard error?
log::warn!( log::warn!(
@@ -295,13 +295,13 @@ impl VirtualDom {
// push the old node's root onto the stack // push the old node's root onto the stack
let real_id = domnode.get().ok_or(Error::NotMounted)?; let real_id = domnode.get().ok_or(Error::NotMounted)?;
diff_machine.edits.push_root(real_id); diff_machine.push_root(real_id);
// push these new nodes onto the diff machines stack // push these new nodes onto the diff machines stack
let meta = diff_machine.create(&*nodes); let meta = diff_machine.create(&*nodes);
// replace the placeholder with the new nodes we just pushed on the stack // replace the placeholder with the new nodes we just pushed on the stack
diff_machine.edits.replace_with(meta.added_to_stack); diff_machine.replace_with(meta.added_to_stack);
} }
} }
} }