fn diff_rose_trees(lhs: &RoseHashTree, rhs: &RoseHashTree) -> Changes {
    fn insert_subtree(t: &RoseHashTree, path: &mut Path, changes: &mut Changes) {
        match t {
            RoseHashTree::Leaf(hash) => {
                changes.insert(path.clone(), Change::InsertLeaf(hash.clone()));
            }
            RoseHashTree::Fork { children, .. } => {
                if children.is_empty() {
                    changes.insert(path.clone(), Change::InsertEmptyFork);
                } else {
                    for (label, child) in children.iter() {
                        path.push(label.clone());
                        insert_subtree(child, path, changes);
                        path.pop();
                    }
                }
            }
        }
    }

    fn go_rec(lhs: &RoseHashTree, rhs: &RoseHashTree, path: &mut Path, changes: &mut Changes) {
        match (lhs, rhs) {
            (RoseHashTree::Leaf(lhash), RoseHashTree::Leaf(rhash)) => {
                if lhash != rhash {
                    changes.insert(path.clone(), Change::InsertLeaf(rhash.clone()));
                }
            }
            (RoseHashTree::Leaf(_), RoseHashTree::Fork { children, .. }) => {
                if children.is_empty() {
                    changes.insert(path.clone(), Change::InsertEmptyFork);
                } else {
                    changes.insert(path.clone(), Change::DeleteSubtree);
                    for (label, rchild) in children {
                        path.push(label.clone());
                        insert_subtree(rchild, path, changes);
                        path.pop();
                    }
                }
            }
            (RoseHashTree::Fork { .. }, RoseHashTree::Leaf(digest)) => {
                changes.insert(path.clone(), Change::InsertLeaf(digest.clone()));
            }
            (
                RoseHashTree::Fork {
                    digest: lhash,
                    children: lchildren,
                },
                RoseHashTree::Fork {
                    digest: rhash,
                    children: rchildren,
                },
            ) => {
                if lhash != rhash {
                    // Traverse the left tree to find changed and deleted nodes.
                    for (llabel, lchild) in lchildren.iter() {
                        path.push(llabel.clone());
                        match rchildren.get(llabel) {
                            Some(rchild) => {
                                go_rec(lchild, rchild, path, changes);
                            }
                            None => {
                                changes.insert(path.clone(), Change::DeleteSubtree);
                            }
                        }
                        path.pop();
                    }
                    // Traverse the right tree to find newly added nodes.
                    for (rlabel, rchild) in rchildren.iter() {
                        if lchildren.get(rlabel).is_none() {
                            path.push(rlabel.clone());
                            insert_subtree(rchild, path, changes);
                            path.pop();
                        }
                    }
                }
            }
        }
    }

    let mut path = Path::new(vec![]);
    let mut changes = BTreeMap::new();

    go_rec(lhs, rhs, &mut path, &mut changes);

    changes
}
/// Produces a set of changes required to transform Merkle tree `lhs` to Merkle
/// tree `rhs`.
///
/// The change set is not guaranteed to be the shortest one.  I.e. it could be
/// possible that there is a shorter sequence of changes having the same effect.
///
/// # Prerequisites
///
/// The trees are expected to be proper Merkle trees built using SHA-256 hashes:
/// if two nodes are not equal, their hashes must be different.
///
/// # Complexity
///
/// `O(N + M)` where `N` and `M` are sizes of the input trees.
///
/// # Panics
///
/// This function uses recursive calls and can panic on deep hash trees.
Produces a set of changes required to transform Merkle tree `lhs` to Merkle
tree `rhs`.

The change set is not guaranteed to be the shortest one.
Produces a set of changes required to transform Merkle tree ` lhs ` to Merkle tree ` rhs ` . The change set is not guaranteed to be the shortest one .
fn diff_rose_trees(lhs: &RoseHashTree, rhs: &RoseHashTree) -> Changes {
    fn insert_subtree(t: &RoseHashTree, path: &mut Path, changes: &mut Changes) {
        match t {
            RoseHashTree::Leaf(hash) => {
                changes.insert(path.clone(), Change::InsertLeaf(hash.clone()));
            }
            RoseHashTree::Fork { children, .. } => {
                if children.is_empty() {
                    changes.insert(path.clone(), Change::InsertEmptyFork);
                } else {
                    for (label, child) in children.iter() {
                        path.push(label.clone());
                        insert_subtree(child, path, changes);
                        path.pop();
                    }
                }
            }
        }
    }
    fn go_rec(lhs: &RoseHashTree, rhs: &RoseHashTree, path: &mut Path, changes: &mut Changes) {
        match (lhs, rhs) {
            (RoseHashTree::Leaf(lhash), RoseHashTree::Leaf(rhash)) => {
                if lhash != rhash {
                    changes.insert(path.clone(), Change::InsertLeaf(rhash.clone()));
                }
            }
            (RoseHashTree::Leaf(_), RoseHashTree::Fork { children, .. }) => {
                if children.is_empty() {
                    changes.insert(path.clone(), Change::InsertEmptyFork);
                } else {
                    changes.insert(path.clone(), Change::DeleteSubtree);
                    for (label, rchild) in children {
                        path.push(label.clone());
                        insert_subtree(rchild, path, changes);
                        path.pop();
                    }
                }
            }
            (RoseHashTree::Fork { .. }, RoseHashTree::Leaf(digest)) => {
                changes.insert(path.clone(), Change::InsertLeaf(digest.clone()));
            }
            (
                RoseHashTree::Fork {
                    digest: lhash,
                    children: lchildren,
                },
                RoseHashTree::Fork {
                    digest: rhash,
                    children: rchildren,
                },
            ) => {
                if lhash != rhash {
                    // Traverse the left tree to find changed and deleted nodes.
                    for (llabel, lchild) in lchildren.iter() {
                        path.push(llabel.clone());
                        match rchildren.get(llabel) {
                            Some(rchild) => {
                                go_rec(lchild, rchild, path, changes);
                            }
                            None => {
                                changes.insert(path.clone(), Change::DeleteSubtree);
                            }
                        }
                        path.pop();
                    }
                    // Traverse the right tree to find newly added nodes.
                    for (rlabel, rchild) in rchildren.iter() {
                        if lchildren.get(rlabel).is_none() {
                            path.push(rlabel.clone());
                            insert_subtree(rchild, path, changes);
                            path.pop();
                        }
                    }
                }
            }
        }
    }
    let mut path = Path::new(vec![]);
    let mut changes = BTreeMap::new();
    go_rec(lhs, rhs, &mut path, &mut changes);
    changes
}
fn diff_rose_trees ( lhs : & RoseHashTree , rhs : & RoseHashTree ) -> Changes { fn insert_subtree ( t : & RoseHashTree , path : & mut Path , changes : & mut Changes ) { match t { RoseHashTree :: Leaf ( hash ) => { changes . insert ( path . clone ( ) , Change :: InsertLeaf ( hash . clone ( ) ) ) ; } RoseHashTree :: Fork { children , .. } => { if children . is_empty ( ) { changes . insert ( path . clone ( ) , Change :: InsertEmptyFork ) ; } else { for ( label , child ) in children . iter ( ) { path . push ( label . clone ( ) ) ; insert_subtree ( child , path , changes ) ; path . pop ( ) ; } } } } } fn go_rec ( lhs : & RoseHashTree , rhs : & RoseHashTree , path : & mut Path , changes : & mut Changes ) { match ( lhs , rhs ) { ( RoseHashTree :: Leaf ( lhash ) , RoseHashTree :: Leaf ( rhash ) ) => { if lhash != rhash { changes . insert ( path . clone ( ) , Change :: InsertLeaf ( rhash . clone ( ) ) ) ; } } ( RoseHashTree :: Leaf ( _ ) , RoseHashTree :: Fork { children , .. } ) => { if children . is_empty ( ) { changes . insert ( path . clone ( ) , Change :: InsertEmptyFork ) ; } else { changes . insert ( path . clone ( ) , Change :: DeleteSubtree ) ; for ( label , rchild ) in children { path . push ( label . clone ( ) ) ; insert_subtree ( rchild , path , changes ) ; path . pop ( ) ; } } } ( RoseHashTree :: Fork { .. } , RoseHashTree :: Leaf ( digest ) ) => { changes . insert ( path . clone ( ) , Change :: InsertLeaf ( digest . clone ( ) ) ) ; } ( RoseHashTree :: Fork { digest : lhash , children : lchildren , } , RoseHashTree :: Fork { digest : rhash , children : rchildren , } , ) => { if lhash != rhash { // Traverse the left tree to find changed and deleted nodes. for ( llabel , lchild ) in lchildren . iter ( ) { path . push ( llabel . clone ( ) ) ; match rchildren . get ( llabel ) { Some ( rchild ) => { go_rec ( lchild , rchild , path , changes ) ; } None => { changes . insert ( path . clone ( ) , Change :: DeleteSubtree ) ; } } path . pop ( ) ; } // Traverse the right tree to find newly added nodes. for ( rlabel , rchild ) in rchildren . iter ( ) { if lchildren . get ( rlabel ) . is_none ( ) { path . push ( rlabel . clone ( ) ) ; insert_subtree ( rchild , path , changes ) ; path . pop ( ) ; } } } } } } let mut path = Path :: new ( vec ! [ ] ) ; let mut changes = BTreeMap :: new ( ) ; go_rec ( lhs , rhs , & mut path , & mut changes ) ; changes }
Produces a set of changes required to transform Merkle tree `lhs` to Merkle
tree `rhs`.
Produces a set of changes required to transform Merkle tree ` lhs ` to Merkle tree ` rhs ` .
lhs
&RoseHashTree
rhs
&RoseHashTree
lhs
&RoseHashTree
rhs
&RoseHashTree
prerequisites
The trees are expected to be proper Merkle trees built using SHA-256 hashes:
if two nodes are not equal, their hashes must be different.
The trees are expected to be proper Merkle trees built using SHA - 256 hashes : if two nodes are not equal their hashes must be different .
complexity
`O(N + M)` where `N` and `M` are sizes of the input trees.
` O ( N + M ) ` where ` N ` and ` M ` are sizes of the input trees .
panics
This function uses recursive calls and can panic on deep hash trees.
This function uses recursive calls and can panic on deep hash trees .