From bcde6601cb406e761cc24fe30d2d8de84053fcef Mon Sep 17 00:00:00 2001 From: Martin Molzer Date: Thu, 6 Jan 2022 00:49:50 +0100 Subject: [PATCH] work on naming: ancestor -> bundle --- packages/yew/src/dom_bundle/attributes.rs | 12 +++--- packages/yew/src/dom_bundle/bcomp.rs | 14 +++---- packages/yew/src/dom_bundle/blist.rs | 16 +++---- packages/yew/src/dom_bundle/bnode.rs | 31 +++++++------- packages/yew/src/dom_bundle/bportal.rs | 51 +++++++++++++---------- packages/yew/src/dom_bundle/bsuspense.rs | 24 +++++------ packages/yew/src/dom_bundle/btag.rs | 8 ++-- packages/yew/src/dom_bundle/btext.rs | 10 ++--- packages/yew/src/tests/layout_tests.rs | 26 +++++------- packages/yew/src/virtual_dom/vnode.rs | 14 +++---- packages/yew/src/virtual_dom/vportal.rs | 12 +++--- 11 files changed, 111 insertions(+), 107 deletions(-) diff --git a/packages/yew/src/dom_bundle/attributes.rs b/packages/yew/src/dom_bundle/attributes.rs index 912329eace5..8a60aad9f49 100644 --- a/packages/yew/src/dom_bundle/attributes.rs +++ b/packages/yew/src/dom_bundle/attributes.rs @@ -47,8 +47,8 @@ impl Apply for Value { self } - fn apply_diff(self, el: &Self::Element, ancestor: &mut Self) { - match (&self.0, &ancestor.0) { + fn apply_diff(self, el: &Self::Element, bundle: &mut Self) { + match (&self.0, &bundle.0) { (Some(new), Some(_)) => { // Refresh value from the DOM. It might have changed. if new.as_ref() != el.value() { @@ -96,8 +96,8 @@ pub(crate) trait Apply { /// Apply contained values to [Element] with no ancestor fn apply(self, el: &Self::Element) -> Self::Bundle; - /// Apply diff between [self] and `ancestor` to [Element]. - fn apply_diff(self, el: &Self::Element, ancestor: &mut Self::Bundle); + /// Apply diff between [self] and `bundle` to [Element]. + fn apply_diff(self, el: &Self::Element, bundle: &mut Self::Bundle); } /// Fields specific to @@ -159,12 +159,12 @@ impl Apply for InputFields { self } - fn apply_diff(self, el: &Self::Element, ancestor: &mut Self) { + fn apply_diff(self, el: &Self::Element, bundle: &mut Self) { // IMPORTANT! This parameter has to be set every time // to prevent strange behaviour in the browser when the DOM changes el.set_checked(self.checked); - self.value.apply_diff(el, &mut ancestor.value); + self.value.apply_diff(el, &mut bundle.value); } } diff --git a/packages/yew/src/dom_bundle/bcomp.rs b/packages/yew/src/dom_bundle/bcomp.rs index dcceb83406a..8542194d0b9 100644 --- a/packages/yew/src/dom_bundle/bcomp.rs +++ b/packages/yew/src/dom_bundle/bcomp.rs @@ -160,10 +160,10 @@ impl Reconcilable for VComp { parent_scope: &AnyScope, parent: &Element, next_sibling: NodeRef, - ancestor: &mut BNode, + bundle: &mut BNode, ) -> NodeRef { - let bcomp = match ancestor { - // If the ancestor is the same type, reuse it and update its properties + let bcomp = match bundle { + // If the existing bundle is the same type, reuse it and update its properties BNode::BComp(ref mut bcomp) if self.type_id == bcomp.type_id && self.key == bcomp.key => { @@ -171,7 +171,7 @@ impl Reconcilable for VComp { } _ => { let (node_ref, self_) = self.attach(parent_scope, parent, next_sibling); - ancestor.replace(parent, self_.into()); + bundle.replace(parent, self_.into()); return node_ref; } }; @@ -239,8 +239,8 @@ mod tests { let parent_scope: AnyScope = AnyScope::test(); let parent_element = document.create_element("div").unwrap(); - let ancestor = html! { }; - let (_, mut comp) = ancestor.attach(&parent_scope, &parent_element, NodeRef::default()); + let comp = html! { }; + let (_, mut bundle) = comp.attach(&parent_scope, &parent_element, NodeRef::default()); for _ in 0..10000 { let node = html! { }; @@ -248,7 +248,7 @@ mod tests { &parent_scope, &parent_element, NodeRef::default(), - &mut comp, + &mut bundle, ); } } diff --git a/packages/yew/src/dom_bundle/blist.rs b/packages/yew/src/dom_bundle/blist.rs index 25e3039cc11..19c65d82e9d 100644 --- a/packages/yew/src/dom_bundle/blist.rs +++ b/packages/yew/src/dom_bundle/blist.rs @@ -53,16 +53,16 @@ impl<'s> ElementWriter<'s> { ) } - fn patch(self, node: VNode, ancestor: &mut BNode) -> Self { - test_log!("patching: {:?} -> {:?}", ancestor, node); + fn patch(self, node: VNode, bundle: &mut BNode) -> Self { + test_log!("patching: {:?} -> {:?}", bundle, node); test_log!( " parent={:?}, next_sibling={:?}", self.parent.outer_html(), self.next_sibling ); // Advance the next sibling reference (from right to left) - ancestor.shift(self.parent, self.next_sibling.clone()); - let next = node.reconcile(self.parent_scope, self.parent, self.next_sibling, ancestor); + bundle.shift(self.parent, self.next_sibling.clone()); + let next = node.reconcile(self.parent_scope, self.parent, self.next_sibling, bundle); test_log!(" next_position: {:?}", next); Self { next_sibling: next, @@ -306,7 +306,7 @@ impl Reconcilable for VList { parent_scope: &AnyScope, parent: &Element, next_sibling: NodeRef, - ancestor: &mut BNode, + bundle: &mut BNode, ) -> NodeRef { // Here, we will try to diff the previous list elements with the new // ones we want to insert. For that, we will use two lists: @@ -314,7 +314,7 @@ impl Reconcilable for VList { // - rights: previously rendered elements. // // The left items are known since we want to insert them - // (self.children). For the right ones, we will look at the ancestor, + // (self.children). For the right ones, we will look at the bundle, // i.e. the current DOM list element that we want to replace with self. if self.children.is_empty() { @@ -325,7 +325,9 @@ impl Reconcilable for VList { } let lefts = self.children; - let blist = ancestor.make_list(); + // 'Forcefully' create a pretend the existing node is a list. Creates a + // singleton list if it isn't already. + let blist = bundle.make_list(); let rights = &mut blist.rev_children; test_log!("lefts: {:?}", lefts); test_log!("rights: {:?}", rights); diff --git a/packages/yew/src/dom_bundle/bnode.rs b/packages/yew/src/dom_bundle/bnode.rs index 04c41a155a9..903079fa6e5 100644 --- a/packages/yew/src/dom_bundle/bnode.rs +++ b/packages/yew/src/dom_bundle/bnode.rs @@ -133,29 +133,30 @@ impl Reconcilable for VNode { parent_scope: &AnyScope, parent: &Element, next_sibling: NodeRef, - ancestor: &mut BNode, + bundle: &mut BNode, ) -> NodeRef { match self { - VNode::VTag(vtag) => vtag.reconcile(parent_scope, parent, next_sibling, ancestor), - VNode::VText(vtext) => vtext.reconcile(parent_scope, parent, next_sibling, ancestor), - VNode::VComp(vcomp) => vcomp.reconcile(parent_scope, parent, next_sibling, ancestor), - VNode::VList(vlist) => vlist.reconcile(parent_scope, parent, next_sibling, ancestor), + VNode::VTag(vtag) => vtag.reconcile(parent_scope, parent, next_sibling, bundle), + VNode::VText(vtext) => vtext.reconcile(parent_scope, parent, next_sibling, bundle), + VNode::VComp(vcomp) => vcomp.reconcile(parent_scope, parent, next_sibling, bundle), + VNode::VList(vlist) => vlist.reconcile(parent_scope, parent, next_sibling, bundle), VNode::VRef(node) => { - if let BNode::BRef(ref n) = ancestor { - if &node == n { - return NodeRef::new(node); + let _existing = match bundle { + BNode::BRef(ref n) if &node == n => n, + _ => { + let (node_ref, self_) = + VNode::VRef(node).attach(parent_scope, parent, next_sibling); + bundle.replace(parent, self_); + return node_ref; } - } - let (node_ref, self_) = - VNode::VRef(node).attach(parent_scope, parent, next_sibling); - ancestor.replace(parent, self_); - node_ref + }; + NodeRef::new(node) } VNode::VPortal(vportal) => { - vportal.reconcile(parent_scope, parent, next_sibling, ancestor) + vportal.reconcile(parent_scope, parent, next_sibling, bundle) } VNode::VSuspense(vsuspsense) => { - vsuspsense.reconcile(parent_scope, parent, next_sibling, ancestor) + vsuspsense.reconcile(parent_scope, parent, next_sibling, bundle) } } } diff --git a/packages/yew/src/dom_bundle/bportal.rs b/packages/yew/src/dom_bundle/bportal.rs index 4356fe39787..0217cbebe69 100644 --- a/packages/yew/src/dom_bundle/bportal.rs +++ b/packages/yew/src/dom_bundle/bportal.rs @@ -6,7 +6,6 @@ use crate::dom_bundle::{DomBundle, Reconcilable}; use crate::html::{AnyScope, NodeRef}; use crate::virtual_dom::Key; use crate::virtual_dom::VPortal; -use std::borrow::BorrowMut; use web_sys::Element; /// The bundle implementation to [VPortal]. @@ -15,7 +14,7 @@ pub struct BPortal { /// The element under which the content is inserted. host: Element, /// The next sibling after the inserted content - next_sibling: NodeRef, + inner_sibling: NodeRef, /// The inserted node node: Box, } @@ -41,18 +40,18 @@ impl Reconcilable for VPortal { _parent: &Element, host_next_sibling: NodeRef, ) -> (NodeRef, Self::Bundle) { - let VPortal { + let Self { host, - next_sibling, + inner_sibling, node, } = self; - let (_, inner) = node.attach(parent_scope, &host, next_sibling.clone()); + let (_, inner) = node.attach(parent_scope, &host, inner_sibling.clone()); ( host_next_sibling, BPortal { host, node: Box::new(inner), - next_sibling, + inner_sibling, }, ) } @@ -62,25 +61,33 @@ impl Reconcilable for VPortal { parent_scope: &AnyScope, parent: &Element, next_sibling: NodeRef, - ancestor: &mut BNode, + bundle: &mut BNode, ) -> NodeRef { - if let BNode::BPortal(portal) = ancestor { - let old_host = std::mem::replace(&mut portal.host, self.host); - let old_sibling = std::mem::replace(&mut portal.next_sibling, self.next_sibling); - let node = &mut portal.node; - if old_host != portal.host || old_sibling != portal.next_sibling { - // Remount the inner node somewhere else instead of diffing - // Move the node, but keep the state - node.shift(&portal.host, portal.next_sibling.clone()); + let portal = match bundle { + BNode::BPortal(portal) => portal, + _ => { + let (self_ref, self_) = self.attach(parent_scope, parent, next_sibling); + bundle.replace(parent, self_.into()); + return self_ref; } - let inner_ancestor = node.borrow_mut(); - self.node - .reconcile(parent_scope, parent, next_sibling.clone(), inner_ancestor); - return next_sibling; - } + }; + let Self { + host, + inner_sibling, + node, + } = self; + + let old_host = std::mem::replace(&mut portal.host, host); + let old_inner_sibling = std::mem::replace(&mut portal.inner_sibling, inner_sibling); - let (_, self_) = self.attach(parent_scope, parent, next_sibling.clone()); - ancestor.replace(parent, self_.into()); + if old_host != portal.host || old_inner_sibling != portal.inner_sibling { + // Remount the inner node somewhere else instead of diffing + // Move the node, but keep the state + portal + .node + .shift(&portal.host, portal.inner_sibling.clone()); + } + node.reconcile(parent_scope, parent, next_sibling.clone(), &mut portal.node); next_sibling } } diff --git a/packages/yew/src/dom_bundle/bsuspense.rs b/packages/yew/src/dom_bundle/bsuspense.rs index f0120100e68..0430d2f9735 100644 --- a/packages/yew/src/dom_bundle/bsuspense.rs +++ b/packages/yew/src/dom_bundle/bsuspense.rs @@ -90,9 +90,9 @@ impl Reconcilable for VSuspense { parent_scope: &AnyScope, parent: &Element, next_sibling: NodeRef, - ancestor: &mut BNode, + bundle: &mut BNode, ) -> NodeRef { - let suspense = match ancestor { + let suspense = match bundle { // We only preserve the child state if they are the same suspense. BNode::BSuspense(m) if m.key == self.key && self.detached_parent == m.detached_parent => @@ -101,41 +101,41 @@ impl Reconcilable for VSuspense { } _ => { let (self_ref, self_) = self.attach(parent_scope, parent, next_sibling); - ancestor.replace(parent, self_.into()); + bundle.replace(parent, self_.into()); return self_ref; } }; - let children_ancestor = &mut suspense.children; + let children_bundle = &mut suspense.children; // no need to update key & detached_parent // When it's suspended, we render children into an element that is detached from the dom // tree while rendering fallback UI into the original place where children resides in. match (self.suspended, &mut suspense.fallback) { - (true, Some(fallback_ancestor)) => { + (true, Some(fallback_bundle)) => { self.children.reconcile( parent_scope, &self.detached_parent, NodeRef::default(), - children_ancestor, + children_bundle, ); self.fallback - .reconcile(parent_scope, parent, next_sibling, fallback_ancestor) + .reconcile(parent_scope, parent, next_sibling, fallback_bundle) } (false, None) => { self.children - .reconcile(parent_scope, parent, next_sibling, children_ancestor) + .reconcile(parent_scope, parent, next_sibling, children_bundle) } (true, None) => { - children_ancestor.shift(&self.detached_parent, NodeRef::default()); + children_bundle.shift(&self.detached_parent, NodeRef::default()); self.children.reconcile( parent_scope, &self.detached_parent, NodeRef::default(), - children_ancestor, + children_bundle, ); // first render of fallback let (fallback_ref, fallback) = @@ -147,9 +147,9 @@ impl Reconcilable for VSuspense { (false, Some(_)) => { suspense.fallback.take().unwrap().detach(parent); - children_ancestor.shift(parent, next_sibling.clone()); + children_bundle.shift(parent, next_sibling.clone()); self.children - .reconcile(parent_scope, parent, next_sibling, children_ancestor) + .reconcile(parent_scope, parent, next_sibling, children_bundle) } } } diff --git a/packages/yew/src/dom_bundle/btag.rs b/packages/yew/src/dom_bundle/btag.rs index 8ea31f5983e..30d88c1edb7 100644 --- a/packages/yew/src/dom_bundle/btag.rs +++ b/packages/yew/src/dom_bundle/btag.rs @@ -136,12 +136,12 @@ impl Reconcilable for VTag { parent_scope: &AnyScope, parent: &Element, next_sibling: NodeRef, - node_bundle: &mut BNode, + bundle: &mut BNode, ) -> NodeRef { // This kind of branching patching routine reduces branch predictor misses and the need to // unpack the enums (including `Option`s) all the time, resulting in a more streamlined // patching flow - let is_matching_tag = match node_bundle { + let is_matching_tag = match bundle { BNode::BTag(ex) if self.key == ex.key => match (&self.inner, &ex.inner) { (VTagInner::Input(_), BTagInner::Input(_)) => true, (VTagInner::Textarea { .. }, BTagInner::Textarea { .. }) => true, @@ -155,7 +155,7 @@ impl Reconcilable for VTag { // If the ancestor is a tag of the same type, don't recreate, keep the // old tag and update its attributes and children. let tag = if is_matching_tag { - match node_bundle { + match bundle { BNode::BTag(a) => { // Preserve the reference that already exists a.deref_mut() @@ -164,7 +164,7 @@ impl Reconcilable for VTag { } } else { let (self_ref, self_) = self.attach(parent_scope, parent, next_sibling); - node_bundle.replace(parent, self_.into()); + bundle.replace(parent, self_.into()); return self_ref; }; diff --git a/packages/yew/src/dom_bundle/btext.rs b/packages/yew/src/dom_bundle/btext.rs index ceba5225f7d..40004c681c2 100644 --- a/packages/yew/src/dom_bundle/btext.rs +++ b/packages/yew/src/dom_bundle/btext.rs @@ -55,14 +55,14 @@ impl Reconcilable for VText { parent_scope: &AnyScope, parent: &Element, next_sibling: NodeRef, - ancestor: &mut BNode, + bundle: &mut BNode, ) -> NodeRef { - let btext = match ancestor { + let btext = match bundle { BNode::BText(btext) => btext, _ => { - let (node_ref, self_) = self.attach(parent_scope, parent, next_sibling); - ancestor.replace(parent, self_.into()); - return node_ref; + let (self_ref, self_) = self.attach(parent_scope, parent, next_sibling); + bundle.replace(parent, self_.into()); + return self_ref; } }; let Self { text } = self; diff --git a/packages/yew/src/tests/layout_tests.rs b/packages/yew/src/tests/layout_tests.rs index a8241b2b14e..38bb2f09bf4 100644 --- a/packages/yew/src/tests/layout_tests.rs +++ b/packages/yew/src/tests/layout_tests.rs @@ -1,6 +1,6 @@ -use crate::dom_bundle::{BNode, Reconcilable}; +use crate::dom_bundle::{BNode, DomBundle, Reconcilable}; use crate::html::AnyScope; -use crate::virtual_dom::{VNode, VText}; +use crate::virtual_dom::VNode; use crate::{Component, Context, Html}; use gloo::console::log; use web_sys::Node; @@ -42,7 +42,6 @@ pub fn diff_layouts(layouts: Vec>) { let parent_node: Node = parent_element.clone().into(); let end_node = document.create_text_node("END"); parent_node.append_child(&end_node).unwrap(); - let empty_node: VNode = VText::new("").into(); // Tests each layout independently let next_sibling = NodeRef::new(end_node.into()); @@ -51,7 +50,7 @@ pub fn diff_layouts(layouts: Vec>) { let vnode = layout.node.clone(); log!("Independently apply layout '{}'", layout.name); - let (_, mut node) = vnode.attach(&parent_scope, &parent_element, next_sibling.clone()); + let (_, mut bundle) = vnode.attach(&parent_scope, &parent_element, next_sibling.clone()); assert_eq!( parent_element.inner_html(), format!("{}END", layout.expected), @@ -68,7 +67,7 @@ pub fn diff_layouts(layouts: Vec>) { &parent_scope, &parent_element, next_sibling.clone(), - &mut node, + &mut bundle, ); assert_eq!( parent_element.inner_html(), @@ -78,12 +77,7 @@ pub fn diff_layouts(layouts: Vec>) { ); // Detach - empty_node.clone().reconcile( - &parent_scope, - &parent_element, - next_sibling.clone(), - &mut node, - ); + bundle.detach(&parent_element); assert_eq!( parent_element.inner_html(), "END", @@ -93,7 +87,7 @@ pub fn diff_layouts(layouts: Vec>) { } // Sequentially apply each layout - let mut ancestor: Option = None; + let mut bundle: Option = None; for layout in layouts.iter() { let next_vnode = layout.node.clone(); @@ -102,7 +96,7 @@ pub fn diff_layouts(layouts: Vec>) { &parent_scope, &parent_element, next_sibling.clone(), - &mut ancestor, + &mut bundle, ); assert_eq!( parent_element.inner_html(), @@ -121,7 +115,7 @@ pub fn diff_layouts(layouts: Vec>) { &parent_scope, &parent_element, next_sibling.clone(), - &mut ancestor, + &mut bundle, ); assert_eq!( parent_element.inner_html(), @@ -132,7 +126,9 @@ pub fn diff_layouts(layouts: Vec>) { } // Detach last layout - empty_node.reconcile_sequentially(&parent_scope, &parent_element, next_sibling, &mut ancestor); + if let Some(bundle) = bundle { + bundle.detach(&parent_element); + } assert_eq!( parent_element.inner_html(), "END", diff --git a/packages/yew/src/virtual_dom/vnode.rs b/packages/yew/src/virtual_dom/vnode.rs index 6adfaa19f1f..4b03eadd89d 100644 --- a/packages/yew/src/virtual_dom/vnode.rs +++ b/packages/yew/src/virtual_dom/vnode.rs @@ -64,17 +64,15 @@ mod test { parent_scope: &AnyScope, parent: &Element, next_sibling: NodeRef, - ancestor: &mut Option, + bundle: &mut Option, ) -> NodeRef { - match ancestor { + match bundle { None => { - let (node_ref, node) = self.attach(parent_scope, parent, next_sibling); - *ancestor = Some(node); - node_ref - } - Some(ref mut ancestor) => { - self.reconcile(parent_scope, parent, next_sibling, ancestor) + let (self_ref, node) = self.attach(parent_scope, parent, next_sibling); + *bundle = Some(node); + self_ref } + Some(bundle) => self.reconcile(parent_scope, parent, next_sibling, bundle), } } } diff --git a/packages/yew/src/virtual_dom/vportal.rs b/packages/yew/src/virtual_dom/vportal.rs index 593ab5cb4a3..abcb4f1a19b 100644 --- a/packages/yew/src/virtual_dom/vportal.rs +++ b/packages/yew/src/virtual_dom/vportal.rs @@ -8,8 +8,8 @@ use web_sys::{Element, Node}; pub struct VPortal { /// The element under which the content is inserted. pub host: Element, - /// The next sibling after the inserted content - pub next_sibling: NodeRef, + /// The next sibling after the inserted content. Most be a child of `host`. + pub inner_sibling: NodeRef, /// The inserted node pub node: Box, } @@ -19,19 +19,19 @@ impl VPortal { pub fn new(content: VNode, host: Element) -> Self { Self { host, - next_sibling: NodeRef::default(), + inner_sibling: NodeRef::default(), node: Box::new(content), } } /// Creates a [VPortal] rendering `content` in the DOM hierarchy under `host`. /// If `next_sibling` is given, the content is inserted before that [Node]. /// The parent of `next_sibling`, if given, must be `host`. - pub fn new_before(content: VNode, host: Element, next_sibling: Option) -> Self { + pub fn new_before(content: VNode, host: Element, inner_sibling: Option) -> Self { Self { host, - next_sibling: { + inner_sibling: { let sib_ref = NodeRef::default(); - sib_ref.set(next_sibling); + sib_ref.set(inner_sibling); sib_ref }, node: Box::new(content),