From 1163bf662c014f1a03a6bd7b013a26331cd31e17 Mon Sep 17 00:00:00 2001 From: Johann Tuffe Date: Wed, 14 Aug 2019 10:33:13 +0800 Subject: [PATCH 1/9] avoid allocating in diff_classes --- src/virtual_dom/vtag.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/virtual_dom/vtag.rs b/src/virtual_dom/vtag.rs index 021d359425e..245cb6b8137 100644 --- a/src/virtual_dom/vtag.rs +++ b/src/virtual_dom/vtag.rs @@ -179,34 +179,33 @@ impl VTag { /// - items that are the same stay the same. /// /// Otherwise just add everything. - fn diff_classes(&mut self, ancestor: &mut Option) -> Vec> { + fn diff_classes<'a>(&'a self, ancestor: &'a Option) -> Vec> { // TODO: Use generator in order to avoid useless alloc - let mut changes = Vec::new(); if let Some(ref ancestor) = ancestor { // Only change what is necessary. + let mut changes = Vec::with_capacity(self.classes.set.len() + ancestor.classes.set.len()); let to_add = self .classes .set .difference(&ancestor.classes.set) - .map(|class| Patch::Add(class.to_owned(), ())); - changes.extend(to_add); + .map(|class| Patch::Add(&**class, ())); let to_remove = ancestor .classes .set .difference(&self.classes.set) - .map(|class| Patch::Remove(class.to_owned())); - changes.extend(to_remove); + .map(|class| Patch::Remove(&**class)); + changes.extend(to_add.chain(to_remove)); + changes } else { // Add everything - let to_add = self + self .classes .set .iter() - .map(|class| Patch::Add(class.to_owned(), ())); - changes.extend(to_add); + .map(|class| Patch::Add(&**class, ())) + .collect() } - changes } /// Similar to diff_classes except for attributes. @@ -297,10 +296,10 @@ impl VTag { let list = element.class_list(); match change { Patch::Add(class, _) | Patch::Replace(class, _) => { - list.add(&class).expect("can't add a class"); + list.add(class).expect("can't add a class"); } Patch::Remove(class) => { - list.remove(&class).expect("can't remove a class"); + list.remove(class).expect("can't remove a class"); } } } From b2dfe0dc3794d7e200ad674a26b69fbbe7f77beb Mon Sep 17 00:00:00 2001 From: Johann Tuffe Date: Wed, 14 Aug 2019 10:40:19 +0800 Subject: [PATCH 2/9] avoid allocating for diff_kind --- src/virtual_dom/vtag.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/virtual_dom/vtag.rs b/src/virtual_dom/vtag.rs index 245cb6b8137..33f870f088b 100644 --- a/src/virtual_dom/vtag.rs +++ b/src/virtual_dom/vtag.rs @@ -252,20 +252,20 @@ impl VTag { } /// Similar to `diff_attributers` except there is only a single `kind`. - fn diff_kind(&mut self, ancestor: &mut Option) -> Option> { + fn diff_kind<'a>(&'a self, ancestor: &'a Option) -> Option> { match ( - &self.kind, - ancestor.as_mut().and_then(|anc| anc.kind.take()), + &self.kind.as_ref(), + ancestor.as_ref().and_then(|anc| anc.kind.as_ref()), ) { (&Some(ref left), Some(ref right)) => { if left != right { - Some(Patch::Replace(left.to_string(), ())) + Some(Patch::Replace(&**left, ())) } else { None } } - (&Some(ref left), None) => Some(Patch::Add(left.to_string(), ())), - (&None, Some(right)) => Some(Patch::Remove(right)), + (&Some(ref left), None) => Some(Patch::Add(&**left, ())), + (&None, Some(right)) => Some(Patch::Remove(&**right)), (&None, None) => None, } } From b3024efd9179eb23c4c258c3082c98bc0c975561 Mon Sep 17 00:00:00 2001 From: Johann Tuffe Date: Wed, 14 Aug 2019 10:42:04 +0800 Subject: [PATCH 3/9] avoid allocating for diff_value --- src/virtual_dom/vtag.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/virtual_dom/vtag.rs b/src/virtual_dom/vtag.rs index 33f870f088b..2c0a42cf2be 100644 --- a/src/virtual_dom/vtag.rs +++ b/src/virtual_dom/vtag.rs @@ -271,20 +271,20 @@ impl VTag { } /// Almost identical in spirit to `diff_kind` - fn diff_value(&mut self, ancestor: &mut Option) -> Option> { + fn diff_value<'a>(&'a self, ancestor: &'a Option) -> Option> { match ( - &self.value, - ancestor.as_mut().and_then(|anc| anc.value.take()), + &self.value.as_ref(), + ancestor.as_ref().and_then(|anc| anc.value.as_ref()), ) { (&Some(ref left), Some(ref right)) => { if left != right { - Some(Patch::Replace(left.to_string(), ())) + Some(Patch::Replace(&**left, ())) } else { None } } - (&Some(ref left), None) => Some(Patch::Add(left.to_string(), ())), - (&None, Some(right)) => Some(Patch::Remove(right)), + (&Some(ref left), None) => Some(Patch::Add(&**left, ())), + (&None, Some(right)) => Some(Patch::Remove(&**right)), (&None, None) => None, } } From 2d466f905222605ee1c4e1cb288d450ea871fa24 Mon Sep 17 00:00:00 2001 From: Johann Tuffe Date: Wed, 14 Aug 2019 11:03:54 +0800 Subject: [PATCH 4/9] simplify diff_attributes and avoid allocations --- src/virtual_dom/vtag.rs | 54 +++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/src/virtual_dom/vtag.rs b/src/virtual_dom/vtag.rs index 2c0a42cf2be..9c276fad31a 100644 --- a/src/virtual_dom/vtag.rs +++ b/src/virtual_dom/vtag.rs @@ -5,7 +5,6 @@ use crate::html::{Component, Scope}; use log::warn; use std::borrow::Cow; use std::cmp::PartialEq; -use std::collections::HashSet; use std::fmt; use stdweb::unstable::TryFrom; use stdweb::web::html_element::InputElement; @@ -212,43 +211,30 @@ impl VTag { /// /// This also handles patching of attributes when the keys are equal but /// the values are different. - fn diff_attributes(&mut self, ancestor: &mut Option) -> Vec> { - let mut changes = Vec::new(); - if let Some(ref mut ancestor) = ancestor { + fn diff_attributes<'a>(&'a self, ancestor: &'a Option) -> Vec> { + if let Some(ref ancestor) = ancestor { // Only change what is necessary. - let self_keys = self.attributes.keys().collect::>(); - let ancestor_keys = ancestor.attributes.keys().collect::>(); - let to_add = self_keys.difference(&ancestor_keys).map(|key| { - let value = self.attributes.get(*key).expect("attribute of vtag lost"); - Patch::Add(key.to_string(), value.to_string()) - }); - changes.extend(to_add); - for key in self_keys.intersection(&ancestor_keys) { - let self_value = self - .attributes - .get(*key) - .expect("attribute of self side lost"); - let ancestor_value = ancestor - .attributes - .get(*key) - .expect("attribute of ancestor side lost"); - if self_value != ancestor_value { - let mutator = Patch::Replace(key.to_string(), self_value.to_string()); - changes.push(mutator); - } - } - let to_remove = ancestor_keys - .difference(&self_keys) - .map(|key| Patch::Remove(key.to_string())); - changes.extend(to_remove); + let mut changes = Vec::with_capacity(self.attributes.len() + ancestor.attributes.len()); + let to_add_or_replace = self.attributes + .iter() + .filter_map(|(key, value)| match ancestor.attributes.get(&**key) { + None => Some(Patch::Add(&**key, &**value)), + Some(ancestor_value) if value == ancestor_value => { + Some(Patch::Replace(&**key, &**value)) + } + _ => None, + }); + let to_remove = ancestor + .attributes + .keys() + .filter(|key| !self.attributes.contains_key(&**key)) + .map(|key| Patch::Remove(&**key)); + changes.extend(to_add_or_replace.chain(to_remove)); + changes } else { // Add everything - for (key, value) in &self.attributes { - let mutator = Patch::Add(key.to_string(), value.to_string()); - changes.push(mutator); - } + self.attributes.iter().map(|(key, value)| Patch::Add(&**key, &**value)).collect() } - changes } /// Similar to `diff_attributers` except there is only a single `kind`. From a3bda76f26fc57815015c4395b4d621c0695ab25 Mon Sep 17 00:00:00 2001 From: Johann Tuffe Date: Wed, 14 Aug 2019 11:38:48 +0800 Subject: [PATCH 5/9] return iterator for diff_classes and diff_attributes --- src/virtual_dom/vtag.rs | 74 ++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 46 deletions(-) diff --git a/src/virtual_dom/vtag.rs b/src/virtual_dom/vtag.rs index 9c276fad31a..ae3870efb0f 100644 --- a/src/virtual_dom/vtag.rs +++ b/src/virtual_dom/vtag.rs @@ -178,63 +178,45 @@ impl VTag { /// - items that are the same stay the same. /// /// Otherwise just add everything. - fn diff_classes<'a>(&'a self, ancestor: &'a Option) -> Vec> { - // TODO: Use generator in order to avoid useless alloc - - if let Some(ref ancestor) = ancestor { - // Only change what is necessary. - let mut changes = Vec::with_capacity(self.classes.set.len() + ancestor.classes.set.len()); - let to_add = self - .classes - .set - .difference(&ancestor.classes.set) - .map(|class| Patch::Add(&**class, ())); - let to_remove = ancestor - .classes - .set - .difference(&self.classes.set) - .map(|class| Patch::Remove(&**class)); - changes.extend(to_add.chain(to_remove)); - changes - } else { - // Add everything - self - .classes - .set - .iter() - .map(|class| Patch::Add(&**class, ())) - .collect() - } + fn diff_classes<'a>(&'a self, ancestor: &'a Option) -> impl Iterator> + 'a { + let to_add = self.classes.set.iter() + .filter(move |class| ancestor.as_ref().map_or(true, |ancestor| !ancestor.classes.set.contains(&**class))) + .map(|class| Patch::Add(&**class, ())); + + let to_remove = ancestor + .iter() + .flat_map(move |ancestor| ancestor.classes.set.difference(&self.classes.set)) + .map(|class| Patch::Remove(&**class)); + + to_add.chain(to_remove) } /// Similar to diff_classes except for attributes. /// /// This also handles patching of attributes when the keys are equal but /// the values are different. - fn diff_attributes<'a>(&'a self, ancestor: &'a Option) -> Vec> { - if let Some(ref ancestor) = ancestor { - // Only change what is necessary. - let mut changes = Vec::with_capacity(self.attributes.len() + ancestor.attributes.len()); - let to_add_or_replace = self.attributes - .iter() - .filter_map(|(key, value)| match ancestor.attributes.get(&**key) { + fn diff_attributes<'a>(&'a self, ancestor: &'a Option) + -> impl Iterator> + 'a + { + // Only change what is necessary. + let to_add_or_replace = self.attributes + .iter() + .filter_map(move |(key, value)| { + match ancestor.as_ref().and_then(|ancestor| ancestor.attributes.get(&**key)) { None => Some(Patch::Add(&**key, &**value)), Some(ancestor_value) if value == ancestor_value => { Some(Patch::Replace(&**key, &**value)) } _ => None, - }); - let to_remove = ancestor - .attributes - .keys() - .filter(|key| !self.attributes.contains_key(&**key)) - .map(|key| Patch::Remove(&**key)); - changes.extend(to_add_or_replace.chain(to_remove)); - changes - } else { - // Add everything - self.attributes.iter().map(|(key, value)| Patch::Add(&**key, &**value)).collect() - } + } + }); + let to_remove = ancestor + .iter() + .flat_map(|ancestor| ancestor.attributes.keys()) + .filter(move |key| !self.attributes.contains_key(&**key)) + .map(|key| Patch::Remove(&**key)); + + to_add_or_replace.chain(to_remove) } /// Similar to `diff_attributers` except there is only a single `kind`. From bd4659a399b5030e893b86363af38abb026842e1 Mon Sep 17 00:00:00 2001 From: Johann Tuffe Date: Wed, 14 Aug 2019 11:43:39 +0800 Subject: [PATCH 6/9] rustfmt on vtags --- src/virtual_dom/vtag.rs | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/virtual_dom/vtag.rs b/src/virtual_dom/vtag.rs index ae3870efb0f..bf8a72593ba 100644 --- a/src/virtual_dom/vtag.rs +++ b/src/virtual_dom/vtag.rs @@ -178,9 +178,19 @@ impl VTag { /// - items that are the same stay the same. /// /// Otherwise just add everything. - fn diff_classes<'a>(&'a self, ancestor: &'a Option) -> impl Iterator> + 'a { - let to_add = self.classes.set.iter() - .filter(move |class| ancestor.as_ref().map_or(true, |ancestor| !ancestor.classes.set.contains(&**class))) + fn diff_classes<'a>( + &'a self, + ancestor: &'a Option, + ) -> impl Iterator> + 'a { + let to_add = self + .classes + .set + .iter() + .filter(move |class| { + ancestor + .as_ref() + .map_or(true, |ancestor| !ancestor.classes.set.contains(&**class)) + }) .map(|class| Patch::Add(&**class, ())); let to_remove = ancestor @@ -195,14 +205,17 @@ impl VTag { /// /// This also handles patching of attributes when the keys are equal but /// the values are different. - fn diff_attributes<'a>(&'a self, ancestor: &'a Option) - -> impl Iterator> + 'a - { + fn diff_attributes<'a>( + &'a self, + ancestor: &'a Option, + ) -> impl Iterator> + 'a { // Only change what is necessary. - let to_add_or_replace = self.attributes - .iter() - .filter_map(move |(key, value)| { - match ancestor.as_ref().and_then(|ancestor| ancestor.attributes.get(&**key)) { + let to_add_or_replace = + self.attributes.iter().filter_map(move |(key, value)| { + match ancestor + .as_ref() + .and_then(|ancestor| ancestor.attributes.get(&**key)) + { None => Some(Patch::Add(&**key, &**value)), Some(ancestor_value) if value == ancestor_value => { Some(Patch::Replace(&**key, &**value)) From 02771be405a4ec57d12c1e05303f04a101e87983 Mon Sep 17 00:00:00 2001 From: Johann Tuffe Date: Wed, 14 Aug 2019 15:17:43 +0800 Subject: [PATCH 7/9] clean apply_diff --- src/virtual_dom/vnode.rs | 17 +++--------- src/virtual_dom/vtag.rs | 57 ++++++++++++++++------------------------ 2 files changed, 26 insertions(+), 48 deletions(-) diff --git a/src/virtual_dom/vnode.rs b/src/virtual_dom/vnode.rs index 679df81c3b7..703babcfe34 100644 --- a/src/virtual_dom/vnode.rs +++ b/src/virtual_dom/vnode.rs @@ -121,19 +121,10 @@ impl fmt::Debug for VNode { impl PartialEq for VNode { fn eq(&self, other: &VNode) -> bool { - match *self { - VNode::VTag(ref vtag_a) => match *other { - VNode::VTag(ref vtag_b) => vtag_a == vtag_b, - _ => false, - }, - VNode::VText(ref vtext_a) => match *other { - VNode::VText(ref vtext_b) => vtext_a == vtext_b, - _ => false, - }, - _ => { - // TODO Implement it - false - } + match (self, other) { + (VNode::VTag(vtag_a), VNode::VTag(vtag_b)) => vtag_a == vtag_b, + (VNode::VText(vtext_a), VNode::VText(vtext_b)) => vtext_a == vtext_b, + _ => false, // TODO: Implement other variants } } } diff --git a/src/virtual_dom/vtag.rs b/src/virtual_dom/vtag.rs index bf8a72593ba..0c17b90702e 100644 --- a/src/virtual_dom/vtag.rs +++ b/src/virtual_dom/vtag.rs @@ -270,7 +270,7 @@ impl VTag { } } - fn apply_diffs(&mut self, element: &Element, ancestor: &mut Option) { + fn apply_diffs(&mut self, element: &Element, ancestor: &Option) { // Update parameters let changes = self.diff_classes(ancestor); for change in changes { @@ -303,34 +303,24 @@ impl VTag { // attribute as `checked` parameter, not `defaultChecked` as browsers do if let Ok(input) = InputElement::try_from(element.clone()) { if let Some(change) = self.diff_kind(ancestor) { - match change { - Patch::Add(kind, _) | Patch::Replace(kind, _) => { - //https://github.com/koute/stdweb/commit/3b85c941db00b8e3c942624afd50c5929085fb08 - //input.set_kind(&kind); - let input = &input; - js! { @(no_return) - @{input}.type = @{kind}; - } - } - Patch::Remove(_) => { - //input.set_kind(""); - let input = &input; - js! { @(no_return) - @{input}.type = ""; - } - } + let kind = match change { + Patch::Add(kind, _) | Patch::Replace(kind, _) => kind, + Patch::Remove(_) => "", + }; + //https://github.com/koute/stdweb/commit/3b85c941db00b8e3c942624afd50c5929085fb08 + //input.set_kind(&kind); + let input = &input; + js! { @(no_return) + @{input}.type = @{kind}; } } if let Some(change) = self.diff_value(ancestor) { - match change { - Patch::Add(kind, _) | Patch::Replace(kind, _) => { - input.set_raw_value(&kind); - } - Patch::Remove(_) => { - input.set_raw_value(""); - } - } + let raw_value = match change { + Patch::Add(kind, _) | Patch::Replace(kind, _) => kind, + Patch::Remove(_) => "", + }; + input.set_raw_value(raw_value); } // IMPORTANT! This parameter has to be set every time @@ -338,14 +328,11 @@ impl VTag { set_checked(&input, self.checked); } else if let Ok(tae) = TextAreaElement::try_from(element.clone()) { if let Some(change) = self.diff_value(ancestor) { - match change { - Patch::Add(value, _) | Patch::Replace(value, _) => { - tae.set_value(&value); - } - Patch::Remove(_) => { - tae.set_value(""); - } - } + let value = match change { + Patch::Add(kind, _) | Patch::Replace(kind, _) => kind, + Patch::Remove(_) => "", + }; + tae.set_value(value); } } } @@ -411,7 +398,7 @@ impl VDiff for VTag { Reform::Keep => {} Reform::Before(before) => { let element = if self.tag == "svg" - || parent.namespace_uri() == Some(SVG_NAMESPACE.to_string()) + || parent.namespace_uri().map_or(false, |ns| ns == SVG_NAMESPACE) { document() .create_element_ns(SVG_NAMESPACE, &self.tag) @@ -448,7 +435,7 @@ impl VDiff for VTag { std::mem::swap(&mut ancestor_childs, &mut a.childs); } - self.apply_diffs(&element, &mut ancestor); + self.apply_diffs(&element, &ancestor); // Every render it removes all listeners and attach it back later // TODO Compare references of handler to do listeners update better From 2f1a46be1ce9a5b9e9c313bb17325ecbaa0bdd78 Mon Sep 17 00:00:00 2001 From: Johann Tuffe Date: Wed, 14 Aug 2019 15:51:03 +0800 Subject: [PATCH 8/9] more cleaning --- src/virtual_dom/vtag.rs | 78 ++++++++++------------------------------- 1 file changed, 19 insertions(+), 59 deletions(-) diff --git a/src/virtual_dom/vtag.rs b/src/virtual_dom/vtag.rs index 0c17b90702e..6da401d5292 100644 --- a/src/virtual_dom/vtag.rs +++ b/src/virtual_dom/vtag.rs @@ -398,7 +398,9 @@ impl VDiff for VTag { Reform::Keep => {} Reform::Before(before) => { let element = if self.tag == "svg" - || parent.namespace_uri().map_or(false, |ns| ns == SVG_NAMESPACE) + || parent + .namespace_uri() + .map_or(false, |ns| ns == SVG_NAMESPACE) { document() .create_element_ns(SVG_NAMESPACE, &self.tag) @@ -430,16 +432,11 @@ impl VDiff for VTag { let element = self.reference.clone().expect("element expected"); { - let mut ancestor_childs = Vec::new(); - if let Some(ref mut a) = ancestor { - std::mem::swap(&mut ancestor_childs, &mut a.childs); - } - self.apply_diffs(&element, &ancestor); // Every render it removes all listeners and attach it back later // TODO Compare references of handler to do listeners update better - if let Some(mut ancestor) = ancestor { + if let Some(ref mut ancestor) = ancestor { for handle in ancestor.captured.drain(..) { handle.remove(); } @@ -454,7 +451,7 @@ impl VDiff for VTag { // Start with an empty precursor, because it put childs to itself let mut precursor = None; let mut self_childs = self.childs.iter_mut(); - let mut ancestor_childs = ancestor_childs.drain(..); + let mut ancestor_childs = ancestor.into_iter().flat_map(|a| a.childs); loop { match (self_childs.next(), ancestor_childs.next()) { (Some(left), right) => { @@ -495,56 +492,19 @@ fn set_checked(input: &InputElement, value: bool) { impl PartialEq for VTag { fn eq(&self, other: &VTag) -> bool { - if self.tag != other.tag { - return false; - } - - if self.value != other.value { - return false; - } - - if self.kind != other.kind { - return false; - } - - if self.checked != other.checked { - return false; - } - - if self.listeners.len() != other.listeners.len() { - return false; - } - - for i in 0..self.listeners.len() { - let a = &self.listeners[i]; - let b = &other.listeners[i]; - - if a.kind() != b.kind() { - return false; - } - } - - if self.attributes != other.attributes { - return false; - } - - if self.classes.set.iter().ne(other.classes.set.iter()) { - return false; - } - - if self.childs.len() != other.childs.len() { - return false; - } - - for i in 0..self.childs.len() { - let a = &self.childs[i]; - let b = &other.childs[i]; - - if a != b { - return false; - } - } - - true + self.tag == other.tag + && self.value == other.value + && self.kind == other.kind + && self.checked == other.checked + && self.listeners.len() == other.listeners.len() + && self + .listeners + .iter() + .map(|l| l.kind()) + .eq(other.listeners.iter().map(|l| l.kind())) + && self.attributes == other.attributes + && self.classes.set.len() == other.classes.set.len() + && self.classes.set.iter().eq(other.classes.set.iter()) + && &self.childs == &other.childs } } From 048865f7031cffd3dc5c6913bd9f64138f8a2a0f Mon Sep 17 00:00:00 2001 From: Johann Tuffe Date: Mon, 19 Aug 2019 09:07:03 +0800 Subject: [PATCH 9/9] apply suggestions --- src/virtual_dom/vtag.rs | 53 +++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/src/virtual_dom/vtag.rs b/src/virtual_dom/vtag.rs index 6da401d5292..f0f320d4e60 100644 --- a/src/virtual_dom/vtag.rs +++ b/src/virtual_dom/vtag.rs @@ -182,16 +182,19 @@ impl VTag { &'a self, ancestor: &'a Option, ) -> impl Iterator> + 'a { - let to_add = self - .classes - .set - .iter() - .filter(move |class| { - ancestor - .as_ref() - .map_or(true, |ancestor| !ancestor.classes.set.contains(&**class)) - }) - .map(|class| Patch::Add(&**class, ())); + let to_add = { + let all_or_nothing = not(ancestor) + .iter() + .flat_map(move |_| self.classes.set.iter()) + .map(|class| Patch::Add(&**class, ())); + + let ancestor_difference = ancestor + .iter() + .flat_map(move |ancestor| self.classes.set.difference(&ancestor.classes.set)) + .map(|class| Patch::Add(&**class, ())); + + all_or_nothing.chain(ancestor_difference) + }; let to_remove = ancestor .iter() @@ -235,38 +238,38 @@ impl VTag { /// Similar to `diff_attributers` except there is only a single `kind`. fn diff_kind<'a>(&'a self, ancestor: &'a Option) -> Option> { match ( - &self.kind.as_ref(), + self.kind.as_ref(), ancestor.as_ref().and_then(|anc| anc.kind.as_ref()), ) { - (&Some(ref left), Some(ref right)) => { + (Some(ref left), Some(ref right)) => { if left != right { Some(Patch::Replace(&**left, ())) } else { None } } - (&Some(ref left), None) => Some(Patch::Add(&**left, ())), - (&None, Some(right)) => Some(Patch::Remove(&**right)), - (&None, None) => None, + (Some(ref left), None) => Some(Patch::Add(&**left, ())), + (None, Some(right)) => Some(Patch::Remove(&**right)), + (None, None) => None, } } /// Almost identical in spirit to `diff_kind` fn diff_value<'a>(&'a self, ancestor: &'a Option) -> Option> { match ( - &self.value.as_ref(), + self.value.as_ref(), ancestor.as_ref().and_then(|anc| anc.value.as_ref()), ) { - (&Some(ref left), Some(ref right)) => { + (Some(ref left), Some(ref right)) => { if left != right { Some(Patch::Replace(&**left, ())) } else { None } } - (&Some(ref left), None) => Some(Patch::Add(&**left, ())), - (&None, Some(right)) => Some(Patch::Remove(&**right)), - (&None, None) => None, + (Some(ref left), None) => Some(Patch::Add(&**left, ())), + (None, Some(right)) => Some(Patch::Remove(&**right)), + (None, None) => None, } } @@ -436,7 +439,7 @@ impl VDiff for VTag { // Every render it removes all listeners and attach it back later // TODO Compare references of handler to do listeners update better - if let Some(ref mut ancestor) = ancestor { + if let Some(ancestor) = ancestor.as_mut() { for handle in ancestor.captured.drain(..) { handle.remove(); } @@ -508,3 +511,11 @@ impl PartialEq for VTag { && &self.childs == &other.childs } } + +pub(crate) fn not(option: &Option) -> &Option<()> { + if option.is_some() { + &None + } else { + &Some(()) + } +}