use core::fmt;
use super::{BackendError, ConfigError, IntegrityError, QueryError};
use crate::error::Rejection;
use crate::log::ProofError;
use crate::model::{AmountError, DecodeError, SealOrderError, ValueError, pad};
use crate::transparency;
#[derive(Clone)]
#[non_exhaustive]
pub enum Error {
Rejected(Rejection),
BatchRejected {
index: usize,
rejection: Rejection,
},
Value(ValueError),
Amount(AmountError),
Query(QueryError),
Transparency(transparency::Error),
Integrity(IntegrityError),
Backend(BackendError),
Config(ConfigError),
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !f.alternate() {
return fmt::Display::fmt(self, f);
}
match self {
Self::Rejected(rejection) => f.debug_tuple("Rejected").field(rejection).finish(),
Self::BatchRejected { index, rejection } => f
.debug_struct("BatchRejected")
.field("index", index)
.field("rejection", rejection)
.finish(),
Self::Value(error) => f.debug_tuple("Value").field(error).finish(),
Self::Amount(error) => f.debug_tuple("Amount").field(error).finish(),
Self::Query(error) => f.debug_tuple("Query").field(error).finish(),
Self::Transparency(error) => f.debug_tuple("Transparency").field(error).finish(),
Self::Integrity(error) => f.debug_tuple("Integrity").field(error).finish(),
Self::Backend(error) => f.debug_tuple("Backend").field(error).finish(),
Self::Config(error) => f.debug_tuple("Config").field(error).finish(),
}
}
}
fn position_suffix(position: Option<u64>) -> String {
position.map_or_else(String::new, |position| format!(" at position {position}"))
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let text = match self {
Self::Rejected(rejection) => format!("rejected: {rejection}"),
Self::BatchRejected { index, rejection } => {
format!("rejected: draft {index} of the batch: {rejection}")
}
Self::Value(error) => format!("invalid value: {error}"),
Self::Amount(error) => format!("amount: {error}"),
Self::Query(error) => format!("query: {error}"),
Self::Transparency(error) => format!("transparency: {error}"),
Self::Integrity(error) => format!(
"integrity failure{}: {error}",
position_suffix(error.position())
),
Self::Backend(error) => format!("backend failure: {error}"),
Self::Config(error) => format!("configuration: {error}"),
};
pad(f, &text)
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(match self {
Self::Rejected(rejection) | Self::BatchRejected { rejection, .. } => rejection,
Self::Value(error) => error,
Self::Amount(error) => error,
Self::Query(error) => error,
Self::Transparency(error) => error,
Self::Integrity(error) => error,
Self::Backend(error) => error,
Self::Config(error) => error,
})
}
}
pub type Result<T, E = Error> = core::result::Result<T, E>;
impl Error {
#[must_use]
pub fn is_transient(&self) -> bool {
matches!(self, Self::Backend(backend) if backend.is_transient())
}
#[must_use]
pub fn may_have_applied(&self) -> bool {
matches!(self, Self::Backend(backend) if backend.may_have_applied())
}
#[must_use]
pub fn code(&self) -> Option<u16> {
self.rejection().map(Rejection::code)
}
#[must_use]
pub fn rejection(&self) -> Option<&Rejection> {
match self {
Self::Rejected(rejection) | Self::BatchRejected { rejection, .. } => Some(rejection),
_ => None,
}
}
}
impl From<Rejection> for Error {
fn from(rejection: Rejection) -> Self {
Self::Rejected(rejection)
}
}
impl From<ValueError> for Error {
fn from(error: ValueError) -> Self {
Self::Value(error)
}
}
impl From<AmountError> for Error {
fn from(error: AmountError) -> Self {
Self::Amount(error)
}
}
impl From<QueryError> for Error {
fn from(error: QueryError) -> Self {
Self::Query(error)
}
}
impl From<transparency::Error> for Error {
fn from(error: transparency::Error) -> Self {
Self::Transparency(error)
}
}
impl From<ProofError> for Error {
fn from(error: ProofError) -> Self {
Self::Transparency(error.into())
}
}
impl From<DecodeError> for Error {
fn from(error: DecodeError) -> Self {
Self::Transparency(error.into())
}
}
impl From<SealOrderError> for Error {
fn from(error: SealOrderError) -> Self {
Self::Transparency(error.into())
}
}
impl From<ConfigError> for Error {
fn from(error: ConfigError) -> Self {
Self::Config(error)
}
}
impl From<IntegrityError> for Error {
fn from(error: IntegrityError) -> Self {
Self::Integrity(error)
}
}
impl From<BackendError> for Error {
fn from(error: BackendError) -> Self {
Self::Backend(error)
}
}