#[derive(Debug)]
pub enum Error {
NotFound,
Invalid,
Rejected(String),
Conflict,
Db(rusqlite::Error),
Unavailable(String),
Other(String),
}
impl From<rusqlite::Error> for Error {
fn from(e: rusqlite::Error) -> Self {
Error::Db(e)
}
}
impl From<anyhow::Error> for Error {
fn from(e: anyhow::Error) -> Self {
Error::Other(e.to_string())
}
}
impl From<videre_core::face_learning::FeatureError> for Error {
fn from(e: videre_core::face_learning::FeatureError) -> Self {
Error::Other(e.to_string())
}
}
impl From<videre_core::face_learning::LearningEventError> for Error {
fn from(e: videre_core::face_learning::LearningEventError) -> Self {
Error::Other(e.to_string())
}
}
impl From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Self {
Error::Other(e.to_string())
}
}
impl From<videre_core::face_learning::ProfileError> for Error {
fn from(e: videre_core::face_learning::ProfileError) -> Self {
Error::Other(e.to_string())
}
}
impl From<videre_core::face_learning::TrainingError> for Error {
fn from(e: videre_core::face_learning::TrainingError) -> Self {
Error::Other(e.to_string())
}
}
impl From<videre_core::face_learning::QuestionError> for Error {
fn from(e: videre_core::face_learning::QuestionError) -> Self {
Error::Other(e.to_string())
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::NotFound => write!(f, "not found"),
Error::Invalid => write!(f, "invalid input"),
Error::Rejected(msg) => write!(f, "{msg}"),
Error::Conflict => write!(f, "stale state, refetch and retry"),
Error::Db(e) => write!(f, "database error: {e}"),
Error::Unavailable(msg) => write!(f, "library unavailable: {msg}"),
Error::Other(msg) => write!(f, "{msg}"),
}
}
}
impl std::error::Error for Error {}
pub type Result<T> = std::result::Result<T, Error>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_matches_each_variant() {
assert_eq!(Error::NotFound.to_string(), "not found");
assert_eq!(Error::Invalid.to_string(), "invalid input");
assert_eq!(Error::Rejected("why".into()).to_string(), "why");
assert_eq!(
Error::Unavailable("root gone".to_string()).to_string(),
"library unavailable: root gone"
);
assert_eq!(Error::Other("boom".to_string()).to_string(), "boom");
}
#[test]
fn conflict_variant_has_a_display_message() {
assert_eq!(
Error::Conflict.to_string(),
"stale state, refetch and retry"
);
}
#[test]
fn display_for_db_variant_includes_the_underlying_error() {
let e = Error::Db(rusqlite::Error::QueryReturnedNoRows);
assert!(e.to_string().starts_with("database error: "));
assert!(e.to_string().contains("Query returned no rows"));
}
#[test]
fn from_rusqlite_error_wraps_as_db_variant() {
let e: Error = rusqlite::Error::QueryReturnedNoRows.into();
assert!(matches!(e, Error::Db(_)));
}
#[test]
fn from_anyhow_error_wraps_message_as_other_variant() {
let e: Error = anyhow::anyhow!("something broke").into();
match e {
Error::Other(msg) => assert_eq!(msg, "something broke"),
other => panic!("expected Error::Other, got {other:?}"),
}
}
}