fix: tree diff improvements

Search for the old child state with matching index
This commit is contained in:
Ashley Wulber 2024-11-06 22:31:05 -05:00
parent 37085bc8ec
commit f1353e1ce2
No known key found for this signature in database
GPG key ID: 5216D4F46A90A820

View file

@ -3,7 +3,7 @@ use crate::Widget;
use crate::id::{Id, Internal}; use crate::id::{Id, Internal};
use std::any::{self, Any}; use std::any::{self, Any};
use std::borrow::{Borrow, BorrowMut, Cow}; use std::borrow::{Borrow, BorrowMut, Cow};
use std::collections::HashMap; use std::collections::{HashMap, VecDeque};
use std::hash::Hash; use std::hash::Hash;
use std::{fmt, mem}; use std::{fmt, mem};
@ -164,93 +164,96 @@ impl Tree {
{ {
let borrowed: &mut dyn Widget<Message, Theme, Renderer> = let borrowed: &mut dyn Widget<Message, Theme, Renderer> =
new.borrow_mut(); new.borrow_mut();
let mut needs_reset = false;
let tag_match = self.tag == borrowed.tag(); let mut tag_match = self.tag == borrowed.tag();
if let Some(Id(Internal::Custom(_, n))) = borrowed.id() { if tag_match {
if let Some((mut state, children)) = NAMED if let Some(Id(Internal::Custom(_, n))) = borrowed.id() {
.with(|named| named.borrow_mut().remove(&n)) let mut named = NAMED
.or_else(|| { .with(|named| named.borrow_mut().remove(&n))
//check self.id .or_else(|| {
if let Some(Id(Internal::Custom(_, ref name))) = self.id { //check self.id
if name == &n { if let Some(Id(Internal::Custom(_, ref name))) = self.id
Some(( {
mem::replace(&mut self.state, State::None), if name == &n {
self.children Some((
.iter_mut() mem::replace(&mut self.state, State::None),
.map(|s| { self.children
// take the data .iter_mut()
mem::replace( .map(|s| {
s, // take the data
Tree { mem::replace(
id: s.id.clone(), s,
tag: s.tag, Tree {
..Tree::empty() id: s.id.clone(),
}, tag: s.tag,
) ..Tree::empty()
}) },
.enumerate() )
.collect(), })
)) .enumerate()
.collect(),
))
} else {
None
}
} else { } else {
None None
} }
});
if let Some((mut state, children)) = named {
std::mem::swap(&mut self.state, &mut state);
let widget_children = borrowed.children();
if !tag_match
|| self.children.len() != widget_children.len()
{
self.children = borrowed.children();
} else { } else {
None for (old_i, mut old) in children {
} let Some(my_state) = self.children.get_mut(old_i)
}) else {
{ continue;
std::mem::swap(&mut self.state, &mut state); };
let widget_children = borrowed.children(); if my_state.tag != old.tag || {
if !tag_match || self.children.len() != widget_children.len() { !match (&old.id, &my_state.id) {
self.children = borrowed.children(); (
} else { Some(Id(Internal::Custom(_, old_name))),
for (old_i, mut old) in children { Some(Id(Internal::Custom(_, my_name))),
let Some(my_state) = self.children.get_mut(old_i) ) => old_name == my_name,
else { (
continue; Some(Id(Internal::Set(a))),
}; Some(Id(Internal::Set(b))),
if my_state.tag != old.tag || { ) => a.len() == b.len(),
!match (&old.id, &my_state.id) { (
( Some(Id(Internal::Unique(_))),
Some(Id(Internal::Custom(_, old_name))), Some(Id(Internal::Unique(_))),
Some(Id(Internal::Custom(_, my_name))), ) => true,
) => old_name == my_name, (None, None) => true,
( _ => false,
Some(Id(Internal::Set(a))), }
Some(Id(Internal::Set(b))), } {
) => a.len() == b.len(), continue;
(
Some(Id(Internal::Unique(_))),
Some(Id(Internal::Unique(_))),
) => true,
(None, None) => true,
_ => false,
} }
} {
continue;
}
mem::swap(my_state, &mut old); mem::swap(my_state, &mut old);
}
} }
} else {
tag_match = false;
} }
} else { } else {
needs_reset = true; if let Some(id) = self.id.clone() {
borrowed.set_id(id);
}
if self.children.len() != borrowed.children().len() {
self.children = borrowed.children();
}
} }
} else if tag_match {
if let Some(id) = self.id.clone() {
borrowed.set_id(id);
}
if self.children.len() != borrowed.children().len() {
self.children = borrowed.children();
}
} else {
needs_reset = true;
} }
if needs_reset { if tag_match {
*self = Self::new(borrowed);
let borrowed = new.borrow_mut();
borrowed.diff(self); borrowed.diff(self);
} else { } else {
*self = Self::new(borrowed);
let borrowed = new.borrow_mut();
borrowed.diff(self); borrowed.diff(self);
} }
} }
@ -269,6 +272,7 @@ impl Tree {
new_children.iter().map(|c| c.borrow().id()).collect(), new_children.iter().map(|c| c.borrow().id()).collect(),
|tree, widget| { |tree, widget| {
let borrowed: &mut dyn Widget<_, _, _> = widget.borrow_mut(); let borrowed: &mut dyn Widget<_, _, _> = widget.borrow_mut();
tree.diff(borrowed); tree.diff(borrowed);
}, },
|widget| { |widget| {
@ -291,29 +295,26 @@ impl Tree {
self.children.truncate(new_children.len()); self.children.truncate(new_children.len());
} }
let len_changed = self.children.len() != new_children.len();
let children_len = self.children.len(); let children_len = self.children.len();
let (mut id_map, mut id_list): ( let (mut id_map, mut id_list): (
HashMap<String, &mut Tree>, HashMap<String, &mut Tree>,
Vec<&mut Tree>, VecDeque<(usize, &mut Tree)>,
) = self.children.iter_mut().fold( ) = self.children.iter_mut().enumerate().fold(
(HashMap::new(), Vec::with_capacity(children_len)), (HashMap::new(), VecDeque::with_capacity(children_len)),
|(mut id_map, mut id_list), c| { |(mut id_map, mut id_list), (i, c)| {
if let Some(id) = c.id.as_ref() { if let Some(id) = c.id.as_ref() {
if let Internal::Custom(_, ref name) = id.0 { if let Internal::Custom(_, ref name) = id.0 {
let _ = id_map.insert(name.to_string(), c); let _ = id_map.insert(name.to_string(), c);
} else { } else {
id_list.push(c); id_list.push_back((i, c));
} }
} else { } else {
id_list.push(c); id_list.push_back((i, c));
} }
(id_map, id_list) (id_map, id_list)
}, },
); );
let mut child_state_i = 0;
let mut new_trees: Vec<(Tree, usize)> = let mut new_trees: Vec<(Tree, usize)> =
Vec::with_capacity(new_children.len()); Vec::with_capacity(new_children.len());
for (i, (new, new_id)) in for (i, (new, new_id)) in
@ -327,14 +328,20 @@ impl Tree {
} }
}) { }) {
c c
} else if child_state_i < id_list.len() } else if let Some(i) = {
&& !matches!( let mut found = None;
id_list[child_state_i].id, for c_i in 0..id_list.len() {
Some(Id(Internal::Custom(_, _))) if id_list[c_i].0 == i {
) found = Some(c_i);
{ break;
let c = &mut id_list[child_state_i]; }
child_state_i += 1; if i < c_i {
break;
}
}
found
} {
let c = id_list.remove(i).unwrap().1;
c c
} else { } else {
let mut my_new_state = new_state(new); let mut my_new_state = new_state(new);