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