In a situation like this, I prefer to use a copy-on-write approach so that I'm sure I'm not accidentally changing the interior of a datastructure that I don't mean to:
#[derive(Clone,Debug)]
struct Person<'a> {
name: &'a str,
age: i32,
children: Vec<Arc<Person<'a>>>,
}
impl<'a> Person<'a> {
fn new(name: &'a str, age: i32) -> Person<'a> {
Person {
name: name,
age,
children: Vec::new(),
}
}
fn add(&mut self, name: &'a str, age: i32) -> &mut Person<'a> {
self.children.push(
Arc::new(Self::new(name, age))
);
self
}
fn get(&self, idx:&[usize])->&Person<'a> {
if idx.len() == 0 { self }
else { self.children[idx[0]].get(&idx[1..]) }
}
fn get_arc(self: &Arc<Self>, idx:&[usize])->Arc<Self> {
if idx.len() == 0 { self.clone() }
else { self.children[idx[0]].get_arc(&idx[1..]) }
}
fn update(&mut self, idx:&[usize])->&mut Self {
if idx.len() == 0 { self }
else { Arc::make_mut(&mut self.children[idx[0]]).update(&idx[1..]) }
}
fn update_arc<'s>(self: &'s mut Arc<Self>, idx:&[usize])->&'s mut Arc<Self> {
if idx.len() == 0 { self }
else {
(&mut Arc::make_mut(self).children[idx[0]]).update_arc(&idx[1..])
}
}
fn show(&self) {
self.show_w_tab(0);
}
fn show_w_tab(&self, tab: usize) {
println!("{:>1$}, {age} yrs old",
self.name, tab + self.name.len(), age=self.age);
}
fn show_family_tree(&self) {
self.walk(|i,c| c.show_w_tab(i.len()*4));
}
fn walk<'s>(&'s self, mut f: impl FnMut(&[usize], &'s Self)) {
let mut idx = vec![0];
let mut stack = vec![self];
f(&[], self);
while stack.len() > 0 {
let &i = idx.last().unwrap();
let &c = stack.last().unwrap();
if c.children.len() > i {
f(&idx, &c.children[i]);
idx.push(0);
stack.push(&c.children[i]);
} else {
idx.pop();
idx.last_mut().map(|i| *i+= 1);
stack.pop();
}
}
}
fn collect_val(&self, filter: impl Fn(&Self)->bool) -> Vec<&Self> {
let mut result = vec![];
self.walk(|_,c| {
if filter(c) { result.push(c); }
});
result
}
fn collect_idx(&self, filter: impl Fn(&Self)->bool) -> Vec<Vec<usize>> {
let mut result = vec![];
self.walk(|i,c| {
if filter(c) { result.push(Vec::from(i)); }
});
result
}
}
fn main() {
let mut tree1 = Person::new("Ruth", 120);
tree1
.add("Pat", 91)
.add("John", 89);
tree1.update(&[0])
.add("Jim", 65)
.add("Chuck", 65);
tree1.update(&[1])
.add("Stan", 57)
.add("Anne", 55);
tree1.update(&[1,0])
.add("Mary", 20);
tree1.update(&[1,1])
.add("Helena", 21)
.add("Peter", 19);
let mut tree1 = Arc::new(tree1);
let mut tree2 = Person::new("Murial", 91);
tree2
.add("Maya", 55)
.add("Matt", 59);
tree2.update(&[0])
.add("Julia", 26)
.add("Andria", 28);
tree2.update(&[0,0])
.add("Tom", 2);
let mut tree2 = Arc::new(tree2);
let (fifties1, fifties2) =
(tree1.collect_idx(|p| p.age >= 50 && p.age < 60),
tree2.collect_idx(|p| p.age >= 50 && p.age < 60));
println!("tree1 people in their fifties...");
for p in fifties1.iter() {
tree1.get(&p).show();
}
println!("tree2 people in their fifties...");
for p in fifties2.iter() {
tree2.get(&p).show();
}
println!("Before Swap");
tree1.show_family_tree();
tree2.show_family_tree();
let mut rng = rand::thread_rng();
let swap_idx1 = fifties1.choose(&mut rng).unwrap();
let swap_idx2 = fifties2.choose(&mut rng).unwrap();
let swap_val1 = tree2.get_arc(&swap_idx2);
let swap_val2 = tree1.get_arc(&swap_idx1);
print!("swap target 1 is: "); swap_val1.show();
print!("swap target 2 is: "); swap_val2.show();
*tree1.update_arc(&swap_idx1) = swap_val1;
*tree2.update_arc(&swap_idx2) = swap_val2;
println!("After Swap");
tree1.show_family_tree();
tree2.show_family_tree();
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=1a393c045e49700e7a71ebe8ca35e6c6