use crate::coordinate::CoordinateError;
#[derive(Debug)]
#[non_exhaustive]
pub enum StoreError {
Io(std::io::Error),
Coordinate(CoordinateError),
Serialization(Box<dyn std::error::Error + Send + Sync>),
CrcMismatch {
segment_id: u64,
offset: u64,
},
CorruptSegment {
segment_id: u64,
detail: String,
},
NotFound(u128),
SequenceMismatch {
entity: String,
expected: u32,
actual: u32,
},
WriterCrashed,
CacheFailed(Box<dyn std::error::Error + Send + Sync>),
Configuration(String),
IdempotencyRequired,
}
impl std::fmt::Display for StoreError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Io(e) => write!(f, "IO error: {e}"),
Self::Coordinate(e) => write!(f, "coordinate error: {e}"),
Self::Serialization(e) => write!(f, "serialization error: {e}"),
Self::CrcMismatch { segment_id, offset } => {
write!(f, "CRC mismatch in segment {segment_id} at offset {offset}")
}
Self::CorruptSegment { segment_id, detail } => {
write!(f, "corrupt segment {segment_id}: {detail}")
}
Self::NotFound(id) => write!(f, "event {id:032x} not found"),
Self::SequenceMismatch {
entity,
expected,
actual,
} => write!(
f,
"CAS failed for {entity}: expected seq {expected}, got {actual}"
),
Self::WriterCrashed => write!(f, "writer thread crashed"),
Self::CacheFailed(e) => write!(f, "cache error: {e}"),
Self::Configuration(msg) => write!(f, "invalid config: {msg}"),
Self::IdempotencyRequired => write!(
f,
"group commit (batch > 1) requires an idempotency key on every append"
),
}
}
}
impl std::error::Error for StoreError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Coordinate(e) => Some(e),
Self::Serialization(e) => Some(e.as_ref()),
Self::CacheFailed(e) => Some(e.as_ref()),
Self::CrcMismatch { .. }
| Self::CorruptSegment { .. }
| Self::NotFound(_)
| Self::SequenceMismatch { .. }
| Self::WriterCrashed
| Self::Configuration(_)
| Self::IdempotencyRequired => None,
}
}
}
impl StoreError {
pub(crate) fn corrupt_magic(segment_id: u64) -> Self {
Self::CorruptSegment {
segment_id,
detail: "bad magic".into(),
}
}
pub(crate) fn corrupt_eof(segment_id: u64) -> Self {
Self::CorruptSegment {
segment_id,
detail: "unexpected EOF during read".into(),
}
}
pub(crate) fn corrupt_version(segment_id: u64, version: u16) -> Self {
Self::CorruptSegment {
segment_id,
detail: format!("unsupported segment version: {version}"),
}
}
pub(crate) fn cache_msg(msg: &str) -> Self {
Self::CacheFailed(msg.into())
}
pub(crate) fn ser_msg(msg: &str) -> Self {
Self::Serialization(msg.into())
}
pub(crate) fn corrupt_frame(segment_id: u64, detail: impl Into<String>) -> Self {
Self::CorruptSegment {
segment_id,
detail: detail.into(),
}
}
}
impl From<CoordinateError> for StoreError {
fn from(e: CoordinateError) -> Self {
Self::Coordinate(e)
}
}
impl From<std::io::Error> for StoreError {
fn from(e: std::io::Error) -> Self {
Self::Io(e)
}
}