use std::fmt;
use std::io;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
Database(String),
Serialization(String),
SerializationError(String),
Deserialization(String),
Io(io::Error),
NotFound,
NotInitialized,
InvalidConfig(String),
Replication(String),
BatchError(String),
IteratorError(String),
SnapshotError(String),
RuntimeError(String),
InvalidKey(String),
InvalidValue(String),
InvalidData(String),
AlreadyExists(String),
Unsupported(String),
LockPoisoned(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Database(msg) => write!(f, "Database error: {}", msg),
Error::Serialization(msg) => write!(f, "Serialization error: {}", msg),
Error::SerializationError(msg) => write!(f, "Serialization error: {}", msg),
Error::Deserialization(msg) => write!(f, "Deserialization error: {}", msg),
Error::Io(err) => write!(f, "I/O error: {}", err),
Error::NotFound => write!(f, "Key not found in database"),
Error::NotInitialized => write!(f, "Database not properly initialized"),
Error::InvalidConfig(msg) => write!(f, "Invalid configuration: {}", msg),
Error::Replication(msg) => write!(f, "Replication error: {}", msg),
Error::BatchError(msg) => write!(f, "Batch operation error: {}", msg),
Error::IteratorError(msg) => write!(f, "Iterator error: {}", msg),
Error::SnapshotError(msg) => write!(f, "Snapshot error: {}", msg),
Error::RuntimeError(msg) => write!(f, "Runtime error: {}", msg),
Error::InvalidKey(msg) => write!(f, "Invalid key: {}", msg),
Error::InvalidValue(msg) => write!(f, "Invalid value: {}", msg),
Error::InvalidData(msg) => write!(f, "Invalid data: {}", msg),
Error::AlreadyExists(msg) => write!(f, "Already exists: {}", msg),
Error::Unsupported(msg) => write!(f, "Unsupported operation: {}", msg),
Error::LockPoisoned(msg) => write!(f, "Lock poisoned: {}", msg),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Io(err) => Some(err),
_ => None,
}
}
}
impl From<rocksdb::Error> for Error {
fn from(err: rocksdb::Error) -> Self {
Error::Database(err.to_string())
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
match err.kind() {
std::io::ErrorKind::InvalidData => {
Error::Deserialization(format!("Borsh decode error: {}", err))
}
_ => Error::Io(err),
}
}
}
#[macro_export]
macro_rules! db_error {
($msg:expr) => {
$crate::Error::Database($msg.to_string())
};
($fmt:expr, $($arg:tt)*) => {
$crate::Error::Database(format!($fmt, $($arg)*))
};
}
#[macro_export]
macro_rules! serialization_error {
($msg:expr) => {
$crate::Error::Serialization($msg.to_string())
};
($fmt:expr, $($arg:tt)*) => {
$crate::Error::Serialization(format!($fmt, $($arg)*))
};
}
#[macro_export]
macro_rules! replication_error {
($msg:expr) => {
$crate::Error::Replication($msg.to_string())
};
($fmt:expr, $($arg:tt)*) => {
$crate::Error::Replication(format!($fmt, $($arg)*))
};
}
impl Error {
pub fn is_not_found(&self) -> bool {
matches!(self, Error::NotFound)
}
pub fn is_io_error(&self) -> bool {
matches!(self, Error::Io(_))
}
pub fn is_serialization_error(&self) -> bool {
matches!(self, Error::Serialization(_) | Error::Deserialization(_))
}
pub fn is_database_error(&self) -> bool {
matches!(self, Error::Database(_))
}
pub fn as_str(&self) -> &str {
match self {
Error::Database(msg)
| Error::Serialization(msg)
| Error::SerializationError(msg)
| Error::Deserialization(msg)
| Error::InvalidConfig(msg)
| Error::Replication(msg)
| Error::BatchError(msg)
| Error::IteratorError(msg)
| Error::SnapshotError(msg)
| Error::RuntimeError(msg)
| Error::InvalidKey(msg)
| Error::InvalidValue(msg)
| Error::InvalidData(msg)
| Error::AlreadyExists(msg)
| Error::Unsupported(msg)
| Error::LockPoisoned(msg) => msg,
Error::Io(_err) => {
"I/O error occurred"
}
Error::NotFound => "Not found",
Error::NotInitialized => "Not initialized",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = Error::Database("test error".to_string());
assert_eq!(err.to_string(), "Database error: test error");
let err = Error::NotFound;
assert_eq!(err.to_string(), "Key not found in database");
}
#[test]
fn test_error_checks() {
let err = Error::NotFound;
assert!(err.is_not_found());
assert!(!err.is_io_error());
let err = Error::Serialization("test".to_string());
assert!(err.is_serialization_error());
assert!(!err.is_database_error());
}
#[test]
fn test_error_macros() {
let err = db_error!("test");
assert!(matches!(err, Error::Database(_)));
let err = serialization_error!("test {}", 123);
assert!(matches!(err, Error::Serialization(_)));
}
}