1#[derive(Debug)]
4pub enum Error {
5 NotFound,
7 Invalid,
9 Conflict,
12 Db(rusqlite::Error),
14 Unavailable(String),
19 Other(String),
22}
23
24impl From<rusqlite::Error> for Error {
25 fn from(e: rusqlite::Error) -> Self {
26 Error::Db(e)
27 }
28}
29
30impl From<anyhow::Error> for Error {
31 fn from(e: anyhow::Error) -> Self {
32 Error::Other(e.to_string())
33 }
34}
35
36impl From<videre_core::face_learning::FeatureError> for Error {
37 fn from(e: videre_core::face_learning::FeatureError) -> Self {
38 Error::Other(e.to_string())
39 }
40}
41
42impl From<videre_core::face_learning::LearningEventError> for Error {
43 fn from(e: videre_core::face_learning::LearningEventError) -> Self {
44 Error::Other(e.to_string())
45 }
46}
47
48impl From<serde_json::Error> for Error {
49 fn from(e: serde_json::Error) -> Self {
50 Error::Other(e.to_string())
51 }
52}
53
54impl From<videre_core::face_learning::ProfileError> for Error {
55 fn from(e: videre_core::face_learning::ProfileError) -> Self {
56 Error::Other(e.to_string())
57 }
58}
59
60impl From<videre_core::face_learning::TrainingError> for Error {
61 fn from(e: videre_core::face_learning::TrainingError) -> Self {
62 Error::Other(e.to_string())
63 }
64}
65
66impl From<videre_core::face_learning::QuestionError> for Error {
67 fn from(e: videre_core::face_learning::QuestionError) -> Self {
68 Error::Other(e.to_string())
69 }
70}
71
72impl std::fmt::Display for Error {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 match self {
75 Error::NotFound => write!(f, "not found"),
76 Error::Invalid => write!(f, "invalid input"),
77 Error::Conflict => write!(f, "stale state, refetch and retry"),
78 Error::Db(e) => write!(f, "database error: {e}"),
79 Error::Unavailable(msg) => write!(f, "library unavailable: {msg}"),
80 Error::Other(msg) => write!(f, "{msg}"),
81 }
82 }
83}
84
85impl std::error::Error for Error {}
86
87pub type Result<T> = std::result::Result<T, Error>;
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn display_matches_each_variant() {
95 assert_eq!(Error::NotFound.to_string(), "not found");
96 assert_eq!(Error::Invalid.to_string(), "invalid input");
97 assert_eq!(
98 Error::Unavailable("root gone".to_string()).to_string(),
99 "library unavailable: root gone"
100 );
101 assert_eq!(Error::Other("boom".to_string()).to_string(), "boom");
102 }
103
104 #[test]
105 fn conflict_variant_has_a_display_message() {
106 assert_eq!(
107 Error::Conflict.to_string(),
108 "stale state, refetch and retry"
109 );
110 }
111
112 #[test]
113 fn display_for_db_variant_includes_the_underlying_error() {
114 let e = Error::Db(rusqlite::Error::QueryReturnedNoRows);
115 assert!(e.to_string().starts_with("database error: "));
116 assert!(e.to_string().contains("Query returned no rows"));
117 }
118
119 #[test]
120 fn from_rusqlite_error_wraps_as_db_variant() {
121 let e: Error = rusqlite::Error::QueryReturnedNoRows.into();
122 assert!(matches!(e, Error::Db(_)));
123 }
124
125 #[test]
126 fn from_anyhow_error_wraps_message_as_other_variant() {
127 let e: Error = anyhow::anyhow!("something broke").into();
128 match e {
129 Error::Other(msg) => assert_eq!(msg, "something broke"),
130 other => panic!("expected Error::Other, got {other:?}"),
131 }
132 }
133}