use crate::store::NodeStore;
use crate::tree::{Hash, TreeError, TreePolicy, stream_and_rebuild};
use super::commit::BranchCommitError;
use super::registry::{BranchRegistry, BranchRegistryGuard, CrossRegisterError};
pub(super) struct Crossed {
pub fork_anchor: Hash,
pub working_root: Hash,
pub guard: BranchRegistryGuard,
}
fn build_working<S: NodeStore + ?Sized>(
anchors: &[Hash],
store: &mut S,
policy: TreePolicy,
) -> Result<Vec<Hash>, TreeError> {
if policy.is_v2() {
anchors
.iter()
.map(|&anchor| stream_and_rebuild(store, anchor, policy))
.collect()
} else {
Ok(anchors.to_vec())
}
}
const fn map_cross_error(error: CrossRegisterError<TreeError>) -> BranchCommitError {
match error {
CrossRegisterError::UnprotectedAnchor(root) => {
BranchCommitError::UnprotectedAnchor { root }
}
CrossRegisterError::Build(error) => BranchCommitError::Tree(error),
CrossRegisterError::WorkingRootCountMismatch { expected, got } => {
BranchCommitError::WorkingRootCountMismatch { expected, got }
}
}
}
pub(super) fn cross_anchor<S, P>(
anchor: Hash,
store: &mut S,
policy: TreePolicy,
registry: &BranchRegistry,
is_protected: P,
) -> Result<Crossed, BranchCommitError>
where
S: NodeStore + ?Sized,
P: Fn(&Hash) -> bool,
{
let (working, guard) = registry
.cross_and_register(&[anchor], is_protected, |anchors| {
build_working(anchors, store, policy)
})
.map_err(map_cross_error)?;
let [working_root] = working.as_slice() else {
return Err(map_cross_error(
CrossRegisterError::WorkingRootCountMismatch {
expected: 1,
got: working.len(),
},
));
};
Ok(Crossed {
fork_anchor: anchor,
working_root: *working_root,
guard,
})
}
#[cfg(test)]
#[path = "crossing_tests.rs"]
mod crossing_tests;