use std::collections::HashSet;
use state_tree::{
patch::{CopyFromPatch, apply_patches},
tree::{StateTree, StateTreeSkeleton, deserialize_tree_untagged, serialize_tree_untagged},
tree_diff::take_diff,
};
fn take_diff_from_trees(old_tree: &StateTree, new_tree: &StateTree) -> HashSet<CopyFromPatch> {
let old_skeleton = old_tree.to_skeleton();
let new_skeleton = new_tree.to_skeleton();
take_diff(&old_skeleton, &new_skeleton)
}
#[test]
fn test_simple_diff() {
let old_tree = StateTree::Delay {
readidx: 1,
writeidx: 1,
data: vec![1, 2],
};
let new_tree = StateTree::Delay {
readidx: 0,
writeidx: 0,
data: vec![0, 0],
};
let patches = take_diff_from_trees(&old_tree, &new_tree);
assert_eq!(
patches,
[CopyFromPatch {
src_addr: 0,
dst_addr: 0,
size: 4,
}]
.into_iter()
.collect()
);
}
#[test]
fn test_node_insertion() {
let old_tree = StateTree::FnCall(vec![
StateTree::Delay {
readidx: 1,
writeidx: 1,
data: vec![1],
}, StateTree::Mem { data: vec![3] }, ]);
let new_tree = StateTree::FnCall(vec![
StateTree::Delay {
readidx: 0,
writeidx: 0,
data: vec![0],
}, StateTree::Feed { data: vec![0] }, StateTree::Mem { data: vec![0] }, ]);
let patches = take_diff_from_trees(&old_tree, &new_tree);
assert_eq!(
patches,
[
CopyFromPatch {
src_addr: 0,
dst_addr: 0,
size: 3,
},
CopyFromPatch {
src_addr: 3,
dst_addr: 4,
size: 1,
},
]
.into_iter()
.collect()
);
}
#[test]
fn test_apply_simple_patch() {
let old_tree = StateTree::Delay {
readidx: 42,
writeidx: 84,
data: vec![1, 2, 3],
};
let new_tree = StateTree::Delay {
readidx: 0,
writeidx: 0,
data: vec![0, 0, 0],
};
let old_storage = serialize_tree_untagged(old_tree.clone());
let mut new_storage = serialize_tree_untagged(new_tree.clone());
let patches = take_diff_from_trees(&old_tree, &new_tree)
.into_iter()
.collect::<Vec<_>>();
apply_patches(&mut new_storage, &old_storage, patches.as_slice());
assert_eq!(new_storage, old_storage);
}
#[test]
fn test_apply_with_structural_changes() {
let old_tree = StateTree::FnCall(vec![
StateTree::Delay {
readidx: 10,
writeidx: 11,
data: vec![1],
}, StateTree::Mem { data: vec![2, 3] }, StateTree::Feed { data: vec![4] }, ]);
let new_tree = StateTree::FnCall(vec![
StateTree::Mem { data: vec![0, 0] }, StateTree::Delay {
readidx: 0,
writeidx: 0,
data: vec![0],
}, StateTree::Mem {
data: vec![0, 0, 0],
}, ]);
let expected_tree = StateTree::FnCall(vec![
StateTree::Mem { data: vec![2, 3] }, StateTree::Delay {
readidx: 0,
writeidx: 0,
data: vec![0],
},
StateTree::Mem {
data: vec![0, 0, 0],
}, ]);
let old_storage = serialize_tree_untagged(old_tree.clone());
let mut new_storage = serialize_tree_untagged(new_tree.clone());
let patches = take_diff_from_trees(&old_tree, &new_tree);
assert_eq!(
patches,
[CopyFromPatch {
src_addr: 3,
dst_addr: 0,
size: 2,
}]
.into_iter()
.collect()
);
apply_patches(
&mut new_storage,
&old_storage,
&patches.into_iter().collect::<Vec<_>>(),
);
let result_tree = deserialize_tree_untagged(&new_storage, &new_tree.to_skeleton())
.expect("Failed to deserialize result tree");
assert_eq!(result_tree, expected_tree);
}
type Skeleton = StateTreeSkeleton<usize>;
#[test]
fn test_complex() {
let old_tree = Skeleton::FnCall(vec![
Box::new(Skeleton::FnCall(vec![Box::new(Skeleton::Feed(1))])), Box::new(Skeleton::FnCall(vec![Box::new(Skeleton::FnCall(vec![
Box::new(Skeleton::Feed(1)), ]))])),
Box::new(Skeleton::FnCall(vec![
Box::new(Skeleton::Delay { len: 4 }), Box::new(Skeleton::Feed(1)), ])),
]);
let new_tree = Skeleton::FnCall(vec![
Box::new(Skeleton::FnCall(vec![Box::new(Skeleton::Feed(1))])), Box::new(Skeleton::FnCall(vec![
Box::new(Skeleton::FnCall(vec![Box::new(Skeleton::Feed(1))])), Box::new(Skeleton::FnCall(vec![Box::new(Skeleton::FnCall(vec![
Box::new(Skeleton::FnCall(vec![Box::new(Skeleton::Feed(1))])), ]))])),
])),
Box::new(Skeleton::FnCall(vec![
Box::new(Skeleton::Delay { len: 4 }), Box::new(Skeleton::Feed(1)), ])),
Box::new(Skeleton::FnCall(vec![
Box::new(Skeleton::Delay { len: 4 }), Box::new(Skeleton::Feed(1)), ])),
]);
let patches = take_diff(&old_tree, &new_tree);
let answer = [
CopyFromPatch {
src_addr: 1,
dst_addr: 1,
size: 1,
},
CopyFromPatch {
src_addr: 0,
dst_addr: 0,
size: 1,
},
CopyFromPatch {
src_addr: 2,
dst_addr: 10,
size: 7,
},
]
.into_iter()
.collect();
assert_eq!(patches, answer);
}