use crate::layout::BlobGuid;
use crate::store::{AllocError, FreeError};
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
BackendIo(std::io::Error),
Alloc(AllocError),
Free(FreeError),
KeyTooLong {
len: usize,
},
ValueTooLong {
len: usize,
},
NotYetImplemented(&'static str),
Internal(&'static str),
NodeCorrupt {
context: &'static str,
blob_guid: Option<BlobGuid>,
slot: Option<u16>,
},
ReplaySanityFailed {
context: &'static str,
record_offset: u64,
},
NotFound,
DstExists,
}
impl Error {
#[must_use]
pub const fn node_corrupt(context: &'static str) -> Self {
Self::NodeCorrupt {
context,
blob_guid: None,
slot: None,
}
}
#[must_use]
pub fn with_blob_guid(mut self, guid: BlobGuid) -> Self {
if let Self::NodeCorrupt { blob_guid, .. } = &mut self {
if blob_guid.is_none() {
*blob_guid = Some(guid);
}
}
self
}
#[must_use]
pub fn with_slot(mut self, slot_index: u16) -> Self {
if let Self::NodeCorrupt { slot, .. } = &mut self {
if slot.is_none() {
*slot = Some(slot_index);
}
}
self
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::BackendIo(e) => write!(f, "backend I/O: {e}"),
Self::Alloc(e) => write!(f, "alloc: {e}"),
Self::Free(e) => write!(f, "free: {e}"),
Self::KeyTooLong { len } => write!(f, "key too long ({len} bytes; max {})", u16::MAX),
Self::ValueTooLong { len } => {
write!(f, "value too long ({len} bytes; max {})", u16::MAX)
}
Self::NotYetImplemented(where_) => write!(f, "not yet implemented: {where_}"),
Self::Internal(what) => write!(f, "internal invariant violated: {what}"),
Self::NodeCorrupt {
context,
blob_guid,
slot,
} => {
write!(f, "node corrupt at {context}")?;
if let Some(g) = blob_guid {
write!(f, " (blob={:02x?})", &g[..4])?;
}
if let Some(s) = slot {
write!(f, " (slot={s})")?;
}
Ok(())
}
Self::ReplaySanityFailed {
context,
record_offset,
} => {
write!(
f,
"WAL replay sanity-check failed at offset {record_offset}: {context}"
)
}
Self::NotFound => write!(f, "key not found"),
Self::DstExists => write!(
f,
"destination key already exists (use force=true to overwrite)"
),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::BackendIo(e) => Some(e),
Self::Alloc(e) => Some(e),
Self::Free(e) => Some(e),
_ => None,
}
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Self::BackendIo(e)
}
}
impl From<AllocError> for Error {
fn from(e: AllocError) -> Self {
Self::Alloc(e)
}
}
impl From<FreeError> for Error {
fn from(e: FreeError) -> Self {
Self::Free(e)
}
}