haematite 0.7.0

Content-addressed, branchable, actor-native storage engine
Documentation
use std::fmt;

use crate::tree::{Hash, TreeError};

use super::handle::BranchError;
use super::merge::MergeError;
use super::policy::BranchPolicyError;
use super::refstore::BranchRefError;

/// Errors raised by branch commit, merge, and named-branch lifecycle paths.
#[derive(Debug)]
pub enum BranchCommitError {
    /// The handle holds no registry guard, so advancing it would race prune.
    Unregistered,
    /// An operation requiring durable identity received an anonymous handle.
    UnnamedBranch,
    /// Parent links were supplied for a volatile commit, which has no record.
    VolatileExtraParents,
    /// A fork-by-hash anchor has no live or durable protection.
    UnprotectedAnchor {
        /// The refused anchor root.
        root: Hash,
    },
    /// A kind or Namespace-lineage boundary refused a fork or merge.
    Policy(BranchPolicyError),
    /// A branch-handle operation failed.
    Branch(BranchError),
    /// Materialising a shard buffer into the shared tree failed.
    Tree(TreeError),
    /// Three-way content merge failed after branch policy accepted it.
    Merge(MergeError),
    /// The store's dirty-directory barrier failed before durable install.
    Barrier(String),
    /// The durable ref store refused or failed an operation.
    Ref(BranchRefError),
    /// The §4.2 step-5 fork crossing's working-root build violated its
    /// one-root-per-anchor contract (unreachable by construction; surfaced as a
    /// loud typed error rather than a silent fallback to the un-rebuilt anchor,
    /// which would be the §4.1 forbidden mixed-policy state).
    WorkingRootCountMismatch {
        /// Anchors the crossing was asked to rebuild.
        expected: usize,
        /// Working roots the build returned.
        got: usize,
    },
}

impl fmt::Display for BranchCommitError {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Unregistered => write!(
                formatter,
                "branch handle is not registered against a branch registry; \
                 fork it via a registering constructor before committing"
            ),
            Self::UnnamedBranch => write!(
                formatter,
                "operation requires a named branch handle from create_branch/open_branch"
            ),
            Self::VolatileExtraParents => write!(
                formatter,
                "extra parents require a durable commit: volatile commits install no record to carry them"
            ),
            Self::UnprotectedAnchor { root } => write!(
                formatter,
                "fork anchor {root} is protected by no live branch, no named branch record, and \
                 no named snapshot, so a prune could reclaim it at any moment; name a snapshot \
                 at this root first (SnapshotRegistry::name), then fork"
            ),
            Self::Policy(error) => error.fmt(formatter),
            Self::Branch(error) => write!(formatter, "branch commit handle error: {error}"),
            Self::Tree(error) => write!(formatter, "branch commit tree error: {error}"),
            Self::Merge(error) => write!(formatter, "branch merge error: {error}"),
            Self::Barrier(reason) => {
                write!(
                    formatter,
                    "branch commit durability barrier failed: {reason}"
                )
            }
            Self::Ref(error) => write!(formatter, "branch commit ref store error: {error}"),
            Self::WorkingRootCountMismatch { expected, got } => write!(
                formatter,
                "fork crossing produced {got} working root(s) for {expected} anchor(s); \
                 refusing to register a partial or mismatched pin set"
            ),
        }
    }
}

impl std::error::Error for BranchCommitError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::Policy(error) => Some(error),
            Self::Branch(error) => Some(error),
            Self::Tree(error) => Some(error),
            Self::Merge(error) => Some(error),
            Self::Ref(error) => Some(error),
            Self::Unregistered
            | Self::UnnamedBranch
            | Self::VolatileExtraParents
            | Self::UnprotectedAnchor { .. }
            | Self::Barrier(_)
            | Self::WorkingRootCountMismatch { .. } => None,
        }
    }
}

impl From<BranchError> for BranchCommitError {
    fn from(error: BranchError) -> Self {
        Self::Branch(error)
    }
}

impl From<TreeError> for BranchCommitError {
    fn from(error: TreeError) -> Self {
        Self::Tree(error)
    }
}

impl From<MergeError> for BranchCommitError {
    fn from(error: MergeError) -> Self {
        Self::Merge(error)
    }
}

impl From<BranchPolicyError> for BranchCommitError {
    fn from(error: BranchPolicyError) -> Self {
        Self::Policy(error)
    }
}

impl From<BranchRefError> for BranchCommitError {
    fn from(error: BranchRefError) -> Self {
        Self::Ref(error)
    }
}