mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-23 20:53:06 +00:00
wip: more work on bumpframe
This commit is contained in:
parent
49856ccd68
commit
63a85e4865
4 changed files with 230 additions and 253 deletions
|
@ -15,7 +15,7 @@ pub struct BumpFrame {
|
|||
pub(crate) head_node: VNode<'static>,
|
||||
|
||||
// used internally for debugging
|
||||
name: &'static str,
|
||||
_name: &'static str,
|
||||
}
|
||||
|
||||
impl ActiveFrame {
|
||||
|
@ -23,12 +23,12 @@ impl ActiveFrame {
|
|||
let frame_a = BumpFrame {
|
||||
bump: Bump::new(),
|
||||
head_node: NodeFactory::unstable_place_holder(),
|
||||
name: "wip",
|
||||
_name: "wip",
|
||||
};
|
||||
let frame_b = BumpFrame {
|
||||
bump: Bump::new(),
|
||||
head_node: NodeFactory::unstable_place_holder(),
|
||||
name: "fin",
|
||||
_name: "fin",
|
||||
};
|
||||
Self {
|
||||
generation: 0.into(),
|
||||
|
@ -103,14 +103,14 @@ mod tests {
|
|||
for _ in 0..5 {
|
||||
let fin = frames.finished_frame();
|
||||
let wip = frames.wip_frame();
|
||||
assert_eq!(wip.name, "wip");
|
||||
assert_eq!(fin.name, "fin");
|
||||
assert_eq!(wip._name, "wip");
|
||||
assert_eq!(fin._name, "fin");
|
||||
frames.cycle_frame();
|
||||
|
||||
let fin = frames.finished_frame();
|
||||
let wip = frames.wip_frame();
|
||||
assert_eq!(wip.name, "fin");
|
||||
assert_eq!(fin.name, "wip");
|
||||
assert_eq!(wip._name, "fin");
|
||||
assert_eq!(fin._name, "wip");
|
||||
frames.cycle_frame();
|
||||
}
|
||||
assert_eq!(frames.generation.get(), 10);
|
||||
|
|
|
@ -55,7 +55,8 @@ use crate::{arena::SharedResources, innerlude::*};
|
|||
use fxhash::{FxHashMap, FxHashSet};
|
||||
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.
|
||||
/// 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 edits: DomEditor<'real, 'bump>,
|
||||
pub edits: &'real mut Vec<DomEdit<'bump>>,
|
||||
|
||||
pub scheduled_garbage: Vec<&'bump VNode<'bump>>,
|
||||
|
||||
|
@ -94,7 +95,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
) -> Self {
|
||||
Self {
|
||||
real_dom: dom,
|
||||
edits: DomEditor::new(edits),
|
||||
edits,
|
||||
cur_idxs: smallvec![cur_idx],
|
||||
vdom: shared,
|
||||
scheduled_garbage: vec![],
|
||||
|
@ -120,9 +121,9 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
let root = root.unwrap();
|
||||
|
||||
if old.text != new.text {
|
||||
self.edits.push_root(root);
|
||||
self.edits.set_text(new.text);
|
||||
self.edits.pop();
|
||||
self.push_root(root);
|
||||
self.set_text(new.text);
|
||||
self.pop();
|
||||
}
|
||||
|
||||
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)
|
||||
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);
|
||||
self.edits.replace_with(meta.added_to_stack);
|
||||
self.replace_with(meta.added_to_stack);
|
||||
self.scheduled_garbage.push(old_node);
|
||||
self.edits.pop();
|
||||
self.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -148,10 +149,10 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
|
||||
// Don't push the root if we don't have to
|
||||
let mut has_comitted = false;
|
||||
let mut please_commit = |edits: &mut DomEditor| {
|
||||
let mut please_commit = |edits: &mut Vec<DomEdit>| {
|
||||
if !has_comitted {
|
||||
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()) {
|
||||
if old_attr.value != new_attr.value {
|
||||
please_commit(&mut self.edits);
|
||||
self.edits.set_attribute(new_attr);
|
||||
self.set_attribute(new_attr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: provide some sort of report on how "good" the diffing was
|
||||
please_commit(&mut self.edits);
|
||||
for attribute in old.attributes {
|
||||
self.edits.remove_attribute(attribute);
|
||||
self.remove_attribute(attribute);
|
||||
}
|
||||
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()) {
|
||||
if old_l.event != new_l.event {
|
||||
please_commit(&mut self.edits);
|
||||
self.edits.remove_event_listener(old_l.event);
|
||||
self.edits.new_event_listener(new_l);
|
||||
self.remove_event_listener(old_l.event);
|
||||
self.new_event_listener(new_l);
|
||||
}
|
||||
new_l.mounted_node.set(old_l.mounted_node.get());
|
||||
}
|
||||
} else {
|
||||
please_commit(&mut self.edits);
|
||||
for listener in old.listeners {
|
||||
self.edits.remove_event_listener(listener.event);
|
||||
self.remove_event_listener(listener.event);
|
||||
}
|
||||
for listener in new.listeners {
|
||||
listener.mounted_node.set(Some(root));
|
||||
self.edits.new_event_listener(listener);
|
||||
self.new_event_listener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
if has_comitted {
|
||||
self.edits.pop();
|
||||
self.pop();
|
||||
}
|
||||
|
||||
// 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)) => {
|
||||
|
@ -249,7 +250,6 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
|
||||
self.seen_nodes.insert(scope_addr);
|
||||
} else {
|
||||
// this seems to be a fairy common code path that we could
|
||||
let mut old_iter = RealChildIterator::new(old_node, &self.vdom);
|
||||
let first = old_iter
|
||||
.next()
|
||||
|
@ -257,16 +257,16 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
|
||||
// remove any leftovers
|
||||
for to_remove in old_iter {
|
||||
self.edits.push_root(to_remove.element_id().unwrap());
|
||||
self.edits.remove();
|
||||
self.push_root(to_remove.element_id().unwrap());
|
||||
self.remove();
|
||||
}
|
||||
|
||||
// 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);
|
||||
self.edits.replace_with(meta.added_to_stack);
|
||||
self.replace_with(meta.added_to_stack);
|
||||
self.scheduled_garbage.push(old_node);
|
||||
self.edits.pop();
|
||||
self.pop();
|
||||
|
||||
// Wipe the old one and plant the new one
|
||||
let old_scope = old.ass_scope.get().unwrap();
|
||||
|
@ -282,7 +282,16 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
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
|
||||
|
@ -326,8 +335,8 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
|
||||
// remove any leftovers
|
||||
for to_remove in old_iter {
|
||||
self.edits.push_root(to_remove.element_id().unwrap());
|
||||
self.edits.remove();
|
||||
self.push_root(to_remove.element_id().unwrap());
|
||||
self.remove();
|
||||
}
|
||||
|
||||
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"
|
||||
self.edits.push_root(back_node_id);
|
||||
self.push_root(back_node_id);
|
||||
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
|
||||
}
|
||||
|
@ -365,7 +374,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
match &node.kind {
|
||||
VNodeKind::Text(text) => {
|
||||
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));
|
||||
|
||||
CreateMeta::new(text.is_static, 1)
|
||||
|
@ -391,17 +400,16 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
|
||||
let real_id = self.vdom.reserve_node();
|
||||
if let Some(namespace) = namespace {
|
||||
self.edits
|
||||
.create_element(tag_name, Some(namespace), real_id)
|
||||
self.create_element(tag_name, Some(namespace), real_id)
|
||||
} 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));
|
||||
|
||||
listeners.iter().for_each(|listener| {
|
||||
log::info!("setting listener id to {:#?}", 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 ?
|
||||
is_static = false;
|
||||
|
@ -409,7 +417,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
|
||||
for attr in *attributes {
|
||||
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
|
||||
|
@ -424,7 +432,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
// TODO move over
|
||||
// if children.len() == 1 {
|
||||
// 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);
|
||||
// }
|
||||
// }
|
||||
|
@ -434,7 +442,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
is_static = is_static && child_meta.is_static;
|
||||
|
||||
// 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 {
|
||||
|
@ -520,7 +528,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
|
||||
VNodeKind::Suspended { node: real_node } => {
|
||||
let id = self.vdom.reserve_node();
|
||||
self.edits.create_placeholder(id);
|
||||
self.create_placeholder(id);
|
||||
node.dom_id.set(Some(id));
|
||||
real_node.set(Some(id));
|
||||
CreateMeta::new(false, 1)
|
||||
|
@ -594,7 +602,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
&mut self,
|
||||
old: &'bump [VNode<'bump>],
|
||||
new: &'bump [VNode<'bump>],
|
||||
old_anchor: &mut Option<ElementId>,
|
||||
old_anchor: Option<ElementId>,
|
||||
new_anchor: &mut Option<ElementId>,
|
||||
) {
|
||||
const IS_EMPTY: bool = true;
|
||||
|
@ -602,33 +610,36 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
|
||||
match (old_anchor, new.is_empty()) {
|
||||
// Both are empty, dealing only with potential anchors
|
||||
(Some(_), IS_EMPTY) => {
|
||||
*new_anchor = *old_anchor;
|
||||
(Some(anchor), IS_EMPTY) => {
|
||||
// new_anchor.set(Some(anchor));
|
||||
if old.len() > 0 {
|
||||
// clean up these virtual nodes (components, fragments, etc)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
Some(anchor) => {
|
||||
self.edits.push_root(*anchor);
|
||||
// Some(anchor) => {
|
||||
self.push_root(anchor);
|
||||
let meta = self.create_children(new);
|
||||
if meta.added_to_stack > 0 {
|
||||
self.edits.replace_with(meta.added_to_stack)
|
||||
self.replace_with(meta.added_to_stack)
|
||||
} else {
|
||||
// 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
|
||||
None => {
|
||||
// None => {
|
||||
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
|
||||
// no anchor (old has nodes) and the new is empty
|
||||
|
@ -637,24 +648,24 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
// load the first real
|
||||
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
|
||||
let anchor_id = self.vdom.reserve_node();
|
||||
self.edits.create_placeholder(anchor_id);
|
||||
*new_anchor = Some(anchor_id);
|
||||
self.create_placeholder(anchor_id);
|
||||
// *new_anchor = Some(anchor_id);
|
||||
|
||||
// Replace that node
|
||||
self.edits.replace_with(1);
|
||||
self.replace_with(1);
|
||||
} else {
|
||||
// no real nodes -
|
||||
*new_anchor = *old_anchor;
|
||||
// new_anchor.set(old_anchor);
|
||||
}
|
||||
|
||||
// remove the rest
|
||||
for child in &old[1..] {
|
||||
self.edits.push_root(child.element_id().unwrap());
|
||||
self.edits.remove();
|
||||
self.push_root(child.element_id().unwrap());
|
||||
self.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -784,7 +795,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
old: &'bump [VNode<'bump>],
|
||||
new: &'bump [VNode<'bump>],
|
||||
) -> KeyedPrefixResult {
|
||||
// self.edits.go_down();
|
||||
// self.go_down();
|
||||
|
||||
let mut shared_prefix_count = 0;
|
||||
|
||||
|
@ -794,7 +805,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
break;
|
||||
}
|
||||
|
||||
// self.edits.go_to_sibling(i);
|
||||
// self.go_to_sibling(i);
|
||||
|
||||
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
|
||||
// new children and we're finished.
|
||||
if shared_prefix_count == old.len() {
|
||||
// self.edits.go_up();
|
||||
// self.edits.commit_traversal();
|
||||
// self.go_up();
|
||||
// self.commit_traversal();
|
||||
self.create_and_append_children(&new[shared_prefix_count..]);
|
||||
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
|
||||
// old children and we're finished.
|
||||
if shared_prefix_count == new.len() {
|
||||
// self.edits.go_to_sibling(shared_prefix_count);
|
||||
// self.edits.commit_traversal();
|
||||
// self.go_to_sibling(shared_prefix_count);
|
||||
// self.commit_traversal();
|
||||
self.remove_self_and_next_siblings(&old[shared_prefix_count..]);
|
||||
return KeyedPrefixResult::Finished;
|
||||
}
|
||||
//
|
||||
// self.edits.go_up();
|
||||
// self.go_up();
|
||||
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.
|
||||
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");
|
||||
for _child in old {
|
||||
// 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
|
||||
// string.
|
||||
todo!()
|
||||
// self.edits.set_inner_text("");
|
||||
// self.set_inner_text("");
|
||||
}
|
||||
|
||||
// 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>]) {
|
||||
for child in new {
|
||||
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.
|
||||
// if shared_suffix_count == 0 && shared_keys.is_empty() {
|
||||
// if shared_prefix_count == 0 {
|
||||
// // self.edits.commit_traversal();
|
||||
// // self.commit_traversal();
|
||||
// self.remove_all_children(old);
|
||||
// } else {
|
||||
// // self.edits.go_down_to_child(shared_prefix_count);
|
||||
// // self.edits.commit_traversal();
|
||||
// // self.go_down_to_child(shared_prefix_count);
|
||||
// // self.commit_traversal();
|
||||
// self.remove_self_and_next_siblings(&old[shared_prefix_count..]);
|
||||
// }
|
||||
|
||||
|
@ -945,8 +956,8 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
// .unwrap_or(old.len());
|
||||
|
||||
// if end - start > 0 {
|
||||
// // self.edits.commit_traversal();
|
||||
// let mut t = self.edits.save_children_to_temporaries(
|
||||
// // self.commit_traversal();
|
||||
// let mut t = self.save_children_to_temporaries(
|
||||
// shared_prefix_count + start,
|
||||
// shared_prefix_count + end,
|
||||
// );
|
||||
|
@ -971,9 +982,9 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
// if !shared_keys.contains(&old_child.key()) {
|
||||
// // registry.remove_subtree(old_child);
|
||||
// // todo
|
||||
// // self.edits.commit_traversal();
|
||||
// self.edits.remove(old_child.dom_id.get());
|
||||
// self.edits.remove_child(i + shared_prefix_count);
|
||||
// // self.commit_traversal();
|
||||
// self.remove(old_child.dom_id.get());
|
||||
// self.remove_child(i + shared_prefix_count);
|
||||
// removed_count += 1;
|
||||
// }
|
||||
// }
|
||||
|
@ -1032,29 +1043,29 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
// let old_index = new_index_to_old_index[last_index];
|
||||
// let temp = old_index_to_temp[old_index];
|
||||
// // [... parent]
|
||||
// self.edits.go_down_to_temp_child(temp);
|
||||
// self.go_down_to_temp_child(temp);
|
||||
// // [... parent last]
|
||||
// self.diff_node(&old[old_index], last);
|
||||
|
||||
// if new_index_is_in_lis.contains(&last_index) {
|
||||
// // Don't move it, since it is already where it needs to be.
|
||||
// } else {
|
||||
// // self.edits.commit_traversal();
|
||||
// // self.commit_traversal();
|
||||
// // [... parent last]
|
||||
// self.edits.append_child();
|
||||
// self.append_child();
|
||||
// // [... parent]
|
||||
// self.edits.go_down_to_temp_child(temp);
|
||||
// self.go_down_to_temp_child(temp);
|
||||
// // [... parent last]
|
||||
// }
|
||||
// } else {
|
||||
// // self.edits.commit_traversal();
|
||||
// // self.commit_traversal();
|
||||
// // [... parent]
|
||||
// self.create(last);
|
||||
|
||||
// // [... parent last]
|
||||
// self.edits.append_child();
|
||||
// self.append_child();
|
||||
// // [... parent]
|
||||
// self.edits.go_down_to_reverse_child(0);
|
||||
// self.go_down_to_reverse_child(0);
|
||||
// // [... parent last]
|
||||
// }
|
||||
// }
|
||||
|
@ -1063,11 +1074,11 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
// let old_index = new_index_to_old_index[new_index];
|
||||
// if old_index == u32::MAX as usize {
|
||||
// debug_assert!(!shared_keys.contains(&new_child.key()));
|
||||
// // self.edits.commit_traversal();
|
||||
// // self.commit_traversal();
|
||||
// // [... parent successor]
|
||||
// self.create(new_child);
|
||||
// // [... parent successor new_child]
|
||||
// self.edits.insert_before();
|
||||
// self.insert_before();
|
||||
// // [... parent new_child]
|
||||
// } else {
|
||||
// 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) {
|
||||
// // [... parent successor]
|
||||
// self.edits.go_to_temp_sibling(temp);
|
||||
// self.go_to_temp_sibling(temp);
|
||||
// // [... parent new_child]
|
||||
// } else {
|
||||
// // self.edits.commit_traversal();
|
||||
// // self.commit_traversal();
|
||||
// // [... parent successor]
|
||||
// self.edits.push_temporary(temp);
|
||||
// self.push_temporary(temp);
|
||||
// // [... parent successor new_child]
|
||||
// self.edits.insert_before();
|
||||
// self.insert_before();
|
||||
// // [... parent new_child]
|
||||
// }
|
||||
|
||||
|
@ -1136,17 +1147,17 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
Ordering::Greater => {
|
||||
for item in &old[new.len()..] {
|
||||
for i in RealChildIterator::new(item, self.vdom) {
|
||||
self.edits.push_root(i.element_id().unwrap());
|
||||
self.edits.remove();
|
||||
self.push_root(i.element_id().unwrap());
|
||||
self.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
// old.len < new.len -> adding some nodes
|
||||
Ordering::Less => {
|
||||
// [... parent last_child]
|
||||
// self.edits.go_up();
|
||||
// self.go_up();
|
||||
// [... parent]
|
||||
// self.edits.commit_traversal();
|
||||
// self.commit_traversal();
|
||||
self.create_and_append_children(&new[old.len()..]);
|
||||
}
|
||||
// old.len == new.len -> no nodes added/removed, but πerhaps changed
|
||||
|
@ -1168,7 +1179,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
//
|
||||
// [... parent]
|
||||
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 {
|
||||
if let VNodeKind::Component(_vcomp) = child.kind {
|
||||
// dom
|
||||
|
@ -1182,7 +1193,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
// })
|
||||
// let id = get_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);
|
||||
// self.lifecycle_events.push_back(LifeCycleEvent::Mount {
|
||||
// caller: Rc::downgrade(&component.caller),
|
||||
|
@ -1194,7 +1205,7 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
// registry.remove_subtree(child);
|
||||
}
|
||||
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> {
|
||||
|
@ -1209,6 +1220,108 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> {
|
|||
// if we have, then we're trying to alias it, which is not allowed
|
||||
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.
|
||||
|
@ -1237,11 +1350,11 @@ enum KeyedPrefixResult {
|
|||
}
|
||||
|
||||
fn find_first_real_node<'a>(
|
||||
nodes: &'a [VNode<'a>],
|
||||
nodes: impl IntoIterator<Item = &'a VNode<'a>>,
|
||||
scopes: &'a SharedResources,
|
||||
) -> Option<&'a VNode<'a>> {
|
||||
for node in nodes {
|
||||
let iter = RealChildIterator::new(node, scopes);
|
||||
let mut iter = RealChildIterator::new(node, scopes);
|
||||
if let Some(node) = iter.next() {
|
||||
return Some(node);
|
||||
}
|
||||
|
|
|
@ -5,143 +5,7 @@
|
|||
//!
|
||||
//!
|
||||
|
||||
use crate::{
|
||||
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 });
|
||||
}
|
||||
}
|
||||
use crate::innerlude::ScopeId;
|
||||
|
||||
/// A `DomEdit` represents a serialzied form of the VirtualDom's trait-based API. This allows streaming edits across the
|
||||
/// network or through FFI boundaries.
|
||||
|
|
|
@ -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.
|
||||
if cur_component.run_scope().is_ok() {
|
||||
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 {
|
||||
// todo: should this be a hard error?
|
||||
log::warn!(
|
||||
|
@ -295,13 +295,13 @@ impl VirtualDom {
|
|||
|
||||
// push the old node's root onto the stack
|
||||
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
|
||||
let meta = diff_machine.create(&*nodes);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue