use std::path::PathBuf;
use error_forge::ForgeError;
use iqdb_types::IqdbError;
#[non_exhaustive]
#[derive(Debug)]
pub enum EvalError {
Io {
path: PathBuf,
source: std::io::Error,
},
Parse {
path: PathBuf,
reason: &'static str,
},
DimensionMismatch {
expected: usize,
found: usize,
},
LengthMismatch {
kind: &'static str,
expected: usize,
found: usize,
},
KExceedsCorpus {
k: usize,
corpus_size: usize,
},
EmptyInput {
kind: &'static str,
},
Search(IqdbError),
UnsupportedVectorId {
found: &'static str,
},
}
impl std::fmt::Display for EvalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Io { path, source } => {
write!(f, "I/O error reading {}: {source}", path.display())
}
Self::Parse { path, reason } => {
write!(f, "parse error in {}: {reason}", path.display())
}
Self::DimensionMismatch { expected, found } => {
write!(
f,
"vector dimension mismatch: expected {expected}, found {found}",
)
}
Self::LengthMismatch {
kind,
expected,
found,
} => {
write!(
f,
"length mismatch ({kind}): expected {expected}, found {found}",
)
}
Self::KExceedsCorpus { k, corpus_size } => {
write!(f, "k exceeds corpus size: k={k}, corpus_size={corpus_size}")
}
Self::EmptyInput { kind } => write!(f, "empty input: {kind}"),
Self::Search(e) => write!(f, "search failed: {e}"),
Self::UnsupportedVectorId { found } => {
write!(f, "unsupported VectorId variant for ground truth: {found}")
}
}
}
}
impl std::error::Error for EvalError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io { source, .. } => Some(source),
Self::Search(e) => Some(e),
_ => None,
}
}
}
impl ForgeError for EvalError {
fn kind(&self) -> &'static str {
match self {
Self::Io { .. } => "Io",
Self::Parse { .. } => "Parse",
Self::DimensionMismatch { .. } => "DimensionMismatch",
Self::LengthMismatch { .. } => "LengthMismatch",
Self::KExceedsCorpus { .. } => "KExceedsCorpus",
Self::EmptyInput { .. } => "EmptyInput",
Self::Search(_) => "Search",
Self::UnsupportedVectorId { .. } => "UnsupportedVectorId",
}
}
fn caption(&self) -> &'static str {
match self {
Self::Io { .. } => "OS-level I/O failure reading a dataset file",
Self::Parse { .. } => "dataset file could not be parsed",
Self::DimensionMismatch { .. } => "vector dimension does not match the index",
Self::LengthMismatch { .. } => "two collections that must share a length did not",
Self::KExceedsCorpus { .. } => "requested top-k exceeds the corpus size",
Self::EmptyInput { .. } => "a required input collection was empty",
Self::Search(_) => "a downstream index operation returned an error",
Self::UnsupportedVectorId { .. } => "ground truth requires VectorId::U64-shaped ids",
}
}
}
impl From<IqdbError> for EvalError {
fn from(value: IqdbError) -> Self {
Self::Search(value)
}
}
pub type Result<T> = core::result::Result<T, EvalError>;