use core::fmt;
use iqdb_persist::PersistError;
use iqdb_types::IqdbError;
#[non_exhaustive]
#[derive(Debug)]
pub enum Error {
Index(IqdbError),
Persist(PersistError),
Config(&'static str),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Index(e) => write!(f, "{e}"),
Self::Persist(e) => write!(f, "{e}"),
Self::Config(reason) => write!(f, "invalid configuration: {reason}"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Index(e) => Some(e),
Self::Persist(e) => Some(e),
Self::Config(_) => None,
}
}
}
impl From<IqdbError> for Error {
fn from(value: IqdbError) -> Self {
Self::Index(value)
}
}
impl From<PersistError> for Error {
fn from(value: PersistError) -> Self {
Self::Persist(value)
}
}
pub type Result<T> = core::result::Result<T, Error>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_iqdb_error_wraps_in_index_variant() {
let err: Error = IqdbError::NotFound.into();
assert!(matches!(err, Error::Index(IqdbError::NotFound)));
}
#[test]
fn from_persist_error_wraps_in_persist_variant() {
let err: Error = PersistError::Unsupported {
feature: "compression",
available_in: "the `zstd` cargo feature",
}
.into();
assert!(matches!(
err,
Error::Persist(PersistError::Unsupported { .. })
));
}
#[test]
fn display_delegates_to_inner_index_error() {
let err = Error::Index(IqdbError::DimensionMismatch {
expected: 3,
found: 2,
});
assert_eq!(
err.to_string(),
"vector dimension mismatch: expected 3, found 2"
);
}
#[test]
fn display_config_variant_is_prefixed() {
let err = Error::Config("dim must be greater than zero");
assert_eq!(
err.to_string(),
"invalid configuration: dim must be greater than zero"
);
}
#[test]
fn source_is_present_for_wrapped_errors_and_absent_for_config() {
use std::error::Error as _;
assert!(Error::Index(IqdbError::NotFound).source().is_some());
assert!(Error::Config("x").source().is_none());
}
}