use crate::error::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ErrorCategory {
Io,
Serialization,
Corruption,
Schema,
Parsing,
Storage,
Concurrency,
Constraints,
Query,
Cancelled,
Other,
}
impl ErrorCategory {
pub fn as_str(self) -> &'static str {
match self {
ErrorCategory::Io => "io",
ErrorCategory::Serialization => "serialization",
ErrorCategory::Corruption => "corruption",
ErrorCategory::Schema => "schema",
ErrorCategory::Parsing => "parsing",
ErrorCategory::Storage => "storage",
ErrorCategory::Concurrency => "concurrency",
ErrorCategory::Constraints => "constraints",
ErrorCategory::Query => "query",
ErrorCategory::Cancelled => "cancelled",
ErrorCategory::Other => "other",
}
}
pub const ALL: &'static [ErrorCategory] = &[
ErrorCategory::Io,
ErrorCategory::Serialization,
ErrorCategory::Corruption,
ErrorCategory::Schema,
ErrorCategory::Parsing,
ErrorCategory::Storage,
ErrorCategory::Concurrency,
ErrorCategory::Constraints,
ErrorCategory::Query,
ErrorCategory::Cancelled,
ErrorCategory::Other,
];
}
impl std::fmt::Display for ErrorCategory {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
pub(crate) fn classify(err: &Error) -> ErrorCategory {
match err {
Error::Io(_) | Error::InvalidPath(_) | Error::Timeout(_) => ErrorCategory::Io,
Error::Serialization { .. } | Error::TypeConversion(_) => ErrorCategory::Serialization,
Error::Corruption(_) => ErrorCategory::Corruption,
Error::Schema(_) | Error::Table(_) => ErrorCategory::Schema,
Error::Parse(_)
| Error::CqlParse(_)
| Error::InvalidFormat(_)
| Error::UnsupportedFormat(_)
| Error::UnsupportedVersion { .. } => ErrorCategory::Parsing,
Error::Storage(_)
| Error::Memory(_)
| Error::Index(_)
| Error::Compaction(_)
| Error::WriteDirLocked { .. } => ErrorCategory::Storage,
Error::Concurrency(_) | Error::Transaction(_) => ErrorCategory::Concurrency,
Error::ConstraintViolation(_) | Error::AlreadyExists(_) => ErrorCategory::Constraints,
Error::QueryExecution(_)
| Error::ResultTooLarge { .. }
| Error::UnsupportedQuery(_)
| Error::ForcedReadPathUnavailable { .. }
| Error::InvalidReadPath { .. }
| Error::InvalidInput(_) => ErrorCategory::Query,
Error::Cancelled => ErrorCategory::Cancelled,
Error::Configuration(_)
| Error::InvalidState(_)
| Error::InvalidOperation(_)
| Error::NotFound(_)
| Error::Internal(_) => ErrorCategory::Other,
#[cfg(target_arch = "wasm32")]
Error::Wasm(_) => ErrorCategory::Other,
}
}
impl Error {
pub fn obs_category(&self) -> ErrorCategory {
classify(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::Error;
#[test]
fn as_str_is_lowercase_and_unique() {
let mut seen = std::collections::HashSet::new();
for c in ErrorCategory::ALL {
let s = c.as_str();
assert_eq!(s, s.to_ascii_lowercase());
assert!(seen.insert(s), "duplicate category label {s}");
}
assert_eq!(seen.len(), ErrorCategory::ALL.len());
}
#[test]
fn display_matches_as_str() {
for c in ErrorCategory::ALL {
assert_eq!(c.to_string(), c.as_str());
}
}
#[test]
fn classify_every_error_variant() {
use ErrorCategory::*;
let io = std::io::Error::other("x");
assert_eq!(Error::from(io).obs_category(), Io);
assert_eq!(Error::invalid_path("p").obs_category(), Io);
assert_eq!(Error::Timeout("t".into()).obs_category(), Io);
assert_eq!(Error::serialization("s").obs_category(), Serialization);
assert_eq!(Error::type_conversion("t").obs_category(), Serialization);
assert_eq!(Error::corruption("c").obs_category(), Corruption);
assert_eq!(Error::schema("s").obs_category(), Schema);
assert_eq!(Error::Table("t".into()).obs_category(), Schema);
assert_eq!(Error::parse("p").obs_category(), Parsing);
assert_eq!(Error::cql_parse("p").obs_category(), Parsing);
assert_eq!(Error::invalid_format("f").obs_category(), Parsing);
assert_eq!(Error::unsupported_format("f").obs_category(), Parsing);
assert_eq!(Error::storage("s").obs_category(), Storage);
assert_eq!(Error::memory("m").obs_category(), Storage);
assert_eq!(Error::index("i").obs_category(), Storage);
assert_eq!(Error::compaction("c").obs_category(), Storage);
assert_eq!(Error::write_dir_locked("/d").obs_category(), Storage);
assert_eq!(Error::concurrency("c").obs_category(), Concurrency);
assert_eq!(Error::transaction("t").obs_category(), Concurrency);
assert_eq!(Error::constraint_violation("c").obs_category(), Constraints);
assert_eq!(Error::already_exists("a").obs_category(), Constraints);
assert_eq!(Error::query_execution("q").obs_category(), Query);
assert_eq!(Error::unsupported_query("q").obs_category(), Query);
assert_eq!(Error::invalid_input("i").obs_category(), Query);
assert_eq!(Error::configuration("c").obs_category(), Other);
assert_eq!(Error::invalid_state("s").obs_category(), Other);
assert_eq!(Error::invalid_operation("o").obs_category(), Other);
assert_eq!(Error::not_found("n").obs_category(), Other);
assert_eq!(Error::internal("i").obs_category(), Other);
assert_eq!(Error::Cancelled.obs_category(), Cancelled);
}
}