1use std::error::Error as StdError;
4use std::fmt;
5
6#[derive(Debug, thiserror::Error)]
9#[non_exhaustive]
10pub enum Error {
11 #[error("name detection is on, but no name-detection model was given")]
14 RecognizerMissing,
15 #[error("name detection failed: {0}")]
17 Recognizer(#[from] RecognizerError),
18 #[error("vault: {0}")]
20 Vault(#[from] VaultError),
21}
22
23macro_rules! wrapped_error {
26 ($(#[$doc:meta])* $name:ident) => {
27 $(#[$doc])*
28 #[derive(Debug)]
29 pub struct $name(Box<dyn StdError + Send + Sync>);
30
31 impl $name {
32 pub fn new(error: impl Into<Box<dyn StdError + Send + Sync>>) -> Self {
34 $name(error.into())
35 }
36
37 pub fn get_ref(&self) -> &(dyn StdError + Send + Sync + 'static) {
39 &*self.0
40 }
41
42 pub fn into_inner(self) -> Box<dyn StdError + Send + Sync> {
44 self.0
45 }
46 }
47
48 impl fmt::Display for $name {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 self.0.fmt(f)
51 }
52 }
53
54 impl StdError for $name {
55 fn source(&self) -> Option<&(dyn StdError + 'static)> {
56 self.0.source()
57 }
58 }
59 };
60}
61
62wrapped_error! {
63 VaultError
65}
66
67wrapped_error! {
68 RecognizerError
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn wrapped_errors_show_the_inner_message() {
78 let io = std::io::Error::other("disk full");
79 let e = Error::from(VaultError::new(io));
80 assert_eq!(e.to_string(), "vault: disk full");
81 let Error::Vault(v) = e else { unreachable!() };
82 assert!(v.get_ref().downcast_ref::<std::io::Error>().is_some());
83 assert_eq!(
84 Error::from(RecognizerError::new("model crashed")).to_string(),
85 "name detection failed: model crashed"
86 );
87 }
88}