use std::fmt;
use crate::db::DatabaseError;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SequenceConflict {
pub expected: u64,
pub actual: u64,
}
impl SequenceConflict {
#[must_use]
pub const fn new(expected: u64, actual: u64) -> Self {
Self { expected, actual }
}
}
impl fmt::Display for SequenceConflict {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"sequence conflict: expected {}, actual {}",
self.expected, self.actual
)
}
}
impl std::error::Error for SequenceConflict {}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CasMismatch {
pub expected: Option<u64>,
pub actual: Option<u64>,
}
impl CasMismatch {
#[must_use]
pub const fn new(expected: Option<u64>, actual: Option<u64>) -> Self {
Self { expected, actual }
}
}
impl fmt::Display for CasMismatch {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"cas mismatch: expected {:?}, actual {:?}",
self.expected, self.actual
)
}
}
impl std::error::Error for CasMismatch {}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HistoryCompacted {
pub stream_key: Vec<u8>,
}
impl HistoryCompacted {
#[must_use]
pub const fn new(stream_key: Vec<u8>) -> Self {
Self { stream_key }
}
}
impl fmt::Display for HistoryCompacted {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"event history compacted for stream {:?}",
self.stream_key
)
}
}
impl std::error::Error for HistoryCompacted {}
#[derive(Debug)]
pub enum ApiError {
SequenceConflict(SequenceConflict),
CasMismatch(CasMismatch),
HistoryCompacted(HistoryCompacted),
CorruptEvent(String),
Storage(DatabaseError),
}
impl fmt::Display for ApiError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::SequenceConflict(conflict) => write!(formatter, "{conflict}"),
Self::CasMismatch(mismatch) => write!(formatter, "{mismatch}"),
Self::HistoryCompacted(compacted) => write!(formatter, "{compacted}"),
Self::CorruptEvent(message) => {
write!(formatter, "corrupt event record: {message}")
}
Self::Storage(error) => write!(formatter, "storage error: {error}"),
}
}
}
impl std::error::Error for ApiError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::SequenceConflict(conflict) => Some(conflict),
Self::CasMismatch(mismatch) => Some(mismatch),
Self::HistoryCompacted(compacted) => Some(compacted),
Self::Storage(error) => Some(error),
Self::CorruptEvent(_) => None,
}
}
}
impl From<SequenceConflict> for ApiError {
fn from(conflict: SequenceConflict) -> Self {
Self::SequenceConflict(conflict)
}
}
impl From<CasMismatch> for ApiError {
fn from(mismatch: CasMismatch) -> Self {
Self::CasMismatch(mismatch)
}
}
impl From<HistoryCompacted> for ApiError {
fn from(compacted: HistoryCompacted) -> Self {
Self::HistoryCompacted(compacted)
}
}
impl From<DatabaseError> for ApiError {
fn from(error: DatabaseError) -> Self {
match error {
DatabaseError::SequenceConflict { expected, actual } => {
Self::SequenceConflict(SequenceConflict { expected, actual })
}
other => Self::Storage(other),
}
}
}