use std::error::Error;
use std::fmt;
use frame_core::capability::{CapabilityCheckError, CapabilityDenied};
use frame_core::component::ComponentId;
use haematite::{
BranchCommitError, BranchError, BranchKind, BranchPolicyError, BranchRefError, CheckoutError,
MergeError, NodeError, SnapshotError, StoreError, TreeError,
};
use crate::types::{MergePolicy, ReferenceTargetState};
#[derive(Debug)]
pub enum ReconcileInconsistency {
BranchWithoutMeta {
branch: String,
kind: BranchKind,
},
ActiveWithoutBranch {
component: ComponentId,
},
ArchivedWithBranch {
component: ComponentId,
},
RemovedWithoutSnapshot {
component: ComponentId,
snapshot: String,
},
SnapshotRootMismatch {
snapshot: String,
expected: haematite::Hash,
actual: haematite::Hash,
},
}
impl fmt::Display for ReconcileInconsistency {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BranchWithoutMeta { branch, kind } => write!(
formatter,
"durable branch '{branch}' ({kind}) has no frame-state meta record"
),
Self::ActiveWithoutBranch { component } => {
write!(
formatter,
"active component {component} has no Namespace branch"
)
}
Self::ArchivedWithBranch { component } => write!(
formatter,
"archived component {component} still has a Namespace branch"
),
Self::RemovedWithoutSnapshot {
component,
snapshot,
} => write!(
formatter,
"component {component} branch was removed without required snapshot '{snapshot}'"
),
Self::SnapshotRootMismatch {
snapshot,
expected,
actual,
} => write!(
formatter,
"snapshot '{snapshot}' names root {actual}, expected {expected}"
),
}
}
}
impl Error for ReconcileInconsistency {}
#[derive(Debug)]
pub enum StateError {
Io(std::io::Error),
Store(StoreError),
Node(NodeError),
Tree(TreeError),
BranchCommit(BranchCommitError),
BranchPolicy(BranchPolicyError),
Merge(MergeError),
BranchRef(BranchRefError),
Branch(BranchError),
Snapshot(SnapshotError),
Checkout(CheckoutError),
CapabilityBinding {
handle_component: ComponentId,
checker_component: ComponentId,
},
CapabilityDenied(CapabilityDenied),
CapabilityCheck(CapabilityCheckError),
DanglingReference {
target: ComponentId,
state: ReferenceTargetState,
},
SynchronizationPoisoned,
SchemaNotDeclared {
component: ComponentId,
},
SchemaAlreadyDeclared {
component: ComponentId,
},
UnsupportedPolicy {
policy: MergePolicy,
},
ResolverNotRegistered {
name: String,
},
ResolverAlreadyRegistered {
name: String,
},
InstallInProgress {
component: ComponentId,
},
ArchiveInProgress {
component: ComponentId,
},
WorkInProgress {
component: ComponentId,
},
AlreadyActive {
component: ComponentId,
},
NotActive {
component: ComponentId,
},
StaleHandle {
component: ComponentId,
held: u64,
current: u64,
},
WorkNotFound {
branch: String,
},
ForeignWorkHandle,
CorruptRecord {
detail: String,
},
Reconcile(ReconcileInconsistency),
}
impl fmt::Display for StateError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(error) => write!(formatter, "frame-state filesystem error: {error}"),
Self::Store(error) => write!(formatter, "frame-state node store error: {error}"),
Self::Node(error) => write!(formatter, "frame-state node encoding error: {error}"),
Self::Tree(error) => write!(formatter, "frame-state tree traversal error: {error}"),
Self::BranchCommit(error) => error.fmt(formatter),
Self::BranchPolicy(error) => error.fmt(formatter),
Self::Merge(error) => error.fmt(formatter),
Self::BranchRef(error) => error.fmt(formatter),
Self::Branch(error) => error.fmt(formatter),
Self::Snapshot(error) => error.fmt(formatter),
Self::Checkout(error) => error.fmt(formatter),
Self::CapabilityBinding {
handle_component,
checker_component,
} => fmt_capability_binding(formatter, *handle_component, *checker_component),
Self::CapabilityDenied(denial) => fmt_capability_denied(formatter, denial),
Self::CapabilityCheck(error) => error.fmt(formatter),
Self::DanglingReference { target, state } => {
fmt_dangling_reference(formatter, *target, *state)
}
Self::SynchronizationPoisoned => {
formatter.write_str("frame-state synchronization poisoned")
}
Self::SchemaNotDeclared { component } => {
write!(
formatter,
"component {component} has no declared storage schema"
)
}
Self::SchemaAlreadyDeclared { component } => {
write!(
formatter,
"component {component} storage schema is already declared"
)
}
Self::UnsupportedPolicy { policy } => {
write!(
formatter,
"haematite 0.5.0 cannot execute merge policy {policy}"
)
}
Self::ResolverNotRegistered { name } => {
write!(
formatter,
"custom merge resolver '{name}' is not registered"
)
}
Self::ResolverAlreadyRegistered { name } => {
write!(
formatter,
"custom merge resolver '{name}' is already registered"
)
}
Self::InstallInProgress { component } => {
write!(
formatter,
"component {component} storage install is in progress"
)
}
Self::ArchiveInProgress { component } => {
write!(
formatter,
"component {component} storage archive is in progress"
)
}
Self::WorkInProgress { component } => {
write!(
formatter,
"component {component} Work operation is in progress"
)
}
Self::AlreadyActive { component } => {
write!(formatter, "component {component} storage is already active")
}
Self::NotActive { component } => {
write!(formatter, "component {component} storage is not active")
}
Self::StaleHandle {
component,
held,
current,
} => write!(
formatter,
"stale handle for component {component}: held incarnation {held}, current incarnation {current}"
),
Self::WorkNotFound { branch } => {
write!(formatter, "Work branch '{branch}' is not outstanding")
}
Self::ForeignWorkHandle => formatter
.write_str("Work handle belongs to another store, component, or incarnation"),
Self::CorruptRecord { detail } => {
write!(formatter, "corrupt frame-state record: {detail}")
}
Self::Reconcile(error) => error.fmt(formatter),
}
}
}
fn fmt_capability_binding(
formatter: &mut fmt::Formatter<'_>,
handle_component: ComponentId,
checker_component: ComponentId,
) -> fmt::Result {
write!(
formatter,
"capability checker for component {checker_component} cannot resolve through component {handle_component}'s storage handle"
)
}
fn fmt_capability_denied(
formatter: &mut fmt::Formatter<'_>,
denial: &CapabilityDenied,
) -> fmt::Result {
write!(
formatter,
"cross-component resolution denied for component {}: kind {:?}, scope {:?}, declared {}",
denial.component_id, denial.kind, denial.scope, denial.declared
)
}
fn fmt_dangling_reference(
formatter: &mut fmt::Formatter<'_>,
target: ComponentId,
state: ReferenceTargetState,
) -> fmt::Result {
write!(
formatter,
"cross-component reference target {target} is {state}"
)
}
impl Error for StateError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Io(error) => Some(error),
Self::Store(error) => Some(error),
Self::Node(error) => Some(error),
Self::Tree(error) => Some(error),
Self::BranchCommit(error) => Some(error),
Self::BranchPolicy(error) => Some(error),
Self::Merge(error) => Some(error),
Self::BranchRef(error) => Some(error),
Self::Branch(error) => Some(error),
Self::Snapshot(error) => Some(error),
Self::Checkout(error) => Some(error),
Self::CapabilityCheck(error) => Some(error),
Self::Reconcile(error) => Some(error),
_ => None,
}
}
}
impl From<std::io::Error> for StateError {
fn from(error: std::io::Error) -> Self {
Self::Io(error)
}
}
impl From<StoreError> for StateError {
fn from(error: StoreError) -> Self {
Self::Store(error)
}
}
impl From<NodeError> for StateError {
fn from(error: NodeError) -> Self {
Self::Node(error)
}
}
impl From<TreeError> for StateError {
fn from(error: TreeError) -> Self {
Self::Tree(error)
}
}
impl From<BranchRefError> for StateError {
fn from(error: BranchRefError) -> Self {
Self::BranchRef(error)
}
}
impl From<BranchError> for StateError {
fn from(error: BranchError) -> Self {
Self::Branch(error)
}
}
impl From<SnapshotError> for StateError {
fn from(error: SnapshotError) -> Self {
Self::Snapshot(error)
}
}
impl From<CheckoutError> for StateError {
fn from(error: CheckoutError) -> Self {
Self::Checkout(error)
}
}
impl From<CapabilityCheckError> for StateError {
fn from(error: CapabilityCheckError) -> Self {
Self::CapabilityCheck(error)
}
}
impl From<ReconcileInconsistency> for StateError {
fn from(error: ReconcileInconsistency) -> Self {
Self::Reconcile(error)
}
}
impl From<BranchCommitError> for StateError {
fn from(error: BranchCommitError) -> Self {
match error {
BranchCommitError::Policy(policy) => Self::BranchPolicy(policy),
BranchCommitError::Merge(merge) => Self::Merge(merge),
other => Self::BranchCommit(other),
}
}
}