cargo/util/context/
error.rs

1use std::fmt;
2
3use crate::util::ConfigValue;
4use crate::util::context::ConfigKey;
5use crate::util::context::Definition;
6
7/// Internal error for serde errors.
8#[derive(Debug)]
9pub struct ConfigError {
10    error: anyhow::Error,
11    definition: Option<Definition>,
12}
13
14impl ConfigError {
15    pub(super) fn new(message: String, definition: Definition) -> ConfigError {
16        ConfigError {
17            error: anyhow::Error::msg(message),
18            definition: Some(definition),
19        }
20    }
21
22    pub(super) fn expected(key: &ConfigKey, expected: &str, found: &ConfigValue) -> ConfigError {
23        ConfigError {
24            error: anyhow::anyhow!(
25                "`{}` expected {}, but found a {}",
26                key,
27                expected,
28                found.desc()
29            ),
30            definition: Some(found.definition().clone()),
31        }
32    }
33
34    pub(super) fn is_missing_field(&self) -> bool {
35        self.error.downcast_ref::<MissingFieldError>().is_some()
36    }
37
38    pub(super) fn missing(key: &ConfigKey) -> ConfigError {
39        ConfigError {
40            error: anyhow::anyhow!("missing config key `{}`", key),
41            definition: None,
42        }
43    }
44
45    pub(super) fn with_key_context(
46        self,
47        key: &ConfigKey,
48        definition: Option<Definition>,
49    ) -> ConfigError {
50        ConfigError {
51            error: anyhow::Error::from(self)
52                .context(format!("could not load config key `{}`", key)),
53            definition: definition,
54        }
55    }
56}
57
58impl std::error::Error for ConfigError {
59    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
60        self.error.source()
61    }
62}
63
64impl fmt::Display for ConfigError {
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        if let Some(definition) = &self.definition {
67            write!(f, "error in {}: {}", definition, self.error)
68        } else {
69            self.error.fmt(f)
70        }
71    }
72}
73
74#[derive(Debug)]
75struct MissingFieldError(String);
76
77impl fmt::Display for MissingFieldError {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        write!(f, "missing field `{}`", self.0)
80    }
81}
82
83impl std::error::Error for MissingFieldError {}
84
85impl serde::de::Error for ConfigError {
86    fn custom<T: fmt::Display>(msg: T) -> Self {
87        ConfigError {
88            error: anyhow::Error::msg(msg.to_string()),
89            definition: None,
90        }
91    }
92
93    fn missing_field(field: &'static str) -> Self {
94        ConfigError {
95            error: anyhow::Error::new(MissingFieldError(field.to_string())),
96            definition: None,
97        }
98    }
99}
100
101impl From<anyhow::Error> for ConfigError {
102    fn from(error: anyhow::Error) -> Self {
103        ConfigError {
104            error,
105            definition: None,
106        }
107    }
108}