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