1use nom;
2use serde::de;
3use serde::ser;
4use std::borrow::Cow;
5use std::error::Error;
6use std::fmt;
7use std::result;
8
9#[derive(Debug)]
10pub enum Unexpected {
11 Bool(bool),
12 Integer(i64),
13 Float(f64),
14 Str(String),
15 Unit,
16 Seq,
17 Map,
18}
19
20impl fmt::Display for Unexpected {
21 fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
22 match *self {
23 Unexpected::Bool(b) => write!(f, "boolean `{}`", b),
24 Unexpected::Integer(i) => write!(f, "integer `{}`", i),
25 Unexpected::Float(v) => write!(f, "floating point `{}`", v),
26 Unexpected::Str(ref s) => write!(f, "string {:?}", s),
27 Unexpected::Unit => write!(f, "unit value"),
28 Unexpected::Seq => write!(f, "sequence"),
29 Unexpected::Map => write!(f, "map"),
30 }
31 }
32}
33
34pub enum ConfigError {
37 Frozen,
39
40 NotFound(String),
42
43 PathParse(nom::error::ErrorKind),
45
46 FileParse {
48 uri: Option<String>,
51
52 cause: Box<dyn Error + Send + Sync>,
55 },
56
57 Type {
59 origin: Option<String>,
63
64 unexpected: Unexpected,
66
67 expected: &'static str,
69
70 key: Option<String>,
73 },
74
75 Message(String),
77
78 Foreign(Box<dyn Error + Send + Sync>),
80}
81
82impl ConfigError {
83 #[doc(hidden)]
85 pub fn invalid_type(
86 origin: Option<String>,
87 unexpected: Unexpected,
88 expected: &'static str,
89 ) -> Self {
90 ConfigError::Type {
91 origin,
92 unexpected,
93 expected,
94 key: None,
95 }
96 }
97
98 #[doc(hidden)]
100 pub fn extend_with_key(self, key: &str) -> Self {
101 match self {
102 ConfigError::Type {
103 origin,
104 unexpected,
105 expected,
106 ..
107 } => ConfigError::Type {
108 origin,
109 unexpected,
110 expected,
111 key: Some(key.into()),
112 },
113
114 _ => self,
115 }
116 }
117
118 fn prepend(self, segment: String, add_dot: bool) -> Self {
119 let concat = |key: Option<String>| {
120 let key = key.unwrap_or_else(String::new);
121 let dot = if add_dot && key.as_bytes().get(0).unwrap_or(&b'[') != &b'[' {
122 "."
123 } else {
124 ""
125 };
126 format!("{}{}{}", segment, dot, key)
127 };
128 match self {
129 ConfigError::Type {
130 origin,
131 unexpected,
132 expected,
133 key,
134 } => ConfigError::Type {
135 origin,
136 unexpected,
137 expected,
138 key: Some(concat(key)),
139 },
140 ConfigError::NotFound(key) => ConfigError::NotFound(concat(Some(key))),
141 _ => self,
142 }
143 }
144
145 pub(crate) fn prepend_key(self, key: String) -> Self {
146 self.prepend(key, true)
147 }
148
149 pub(crate) fn prepend_index(self, idx: usize) -> Self {
150 self.prepend(format!("[{}]", idx), false)
151 }
152}
153
154pub type Result<T> = result::Result<T, ConfigError>;
156
157impl fmt::Debug for ConfigError {
159 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160 write!(f, "{}", *self)
161 }
162}
163
164impl fmt::Display for ConfigError {
165 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
166 match *self {
167 ConfigError::Frozen => write!(f, "configuration is frozen"),
168
169 ConfigError::PathParse(ref kind) => write!(f, "{}", kind.description()),
170
171 ConfigError::Message(ref s) => write!(f, "{}", s),
172
173 ConfigError::Foreign(ref cause) => write!(f, "{}", cause),
174
175 ConfigError::NotFound(ref key) => {
176 write!(f, "configuration property {:?} not found", key)
177 }
178
179 ConfigError::Type {
180 ref origin,
181 ref unexpected,
182 expected,
183 ref key,
184 } => {
185 write!(f, "invalid type: {}, expected {}", unexpected, expected)?;
186
187 if let Some(ref key) = *key {
188 write!(f, " for key `{}`", key)?;
189 }
190
191 if let Some(ref origin) = *origin {
192 write!(f, " in {}", origin)?;
193 }
194
195 Ok(())
196 }
197
198 ConfigError::FileParse { ref cause, ref uri } => {
199 write!(f, "{}", cause)?;
200
201 if let Some(ref uri) = *uri {
202 write!(f, " in {}", uri)?;
203 }
204
205 Ok(())
206 }
207 }
208 }
209}
210
211impl Error for ConfigError {}
212
213impl de::Error for ConfigError {
214 fn custom<T: fmt::Display>(msg: T) -> Self {
215 ConfigError::Message(msg.to_string())
216 }
217}
218
219impl ser::Error for ConfigError {
220 fn custom<T: fmt::Display>(msg: T) -> Self {
221 ConfigError::Message(msg.to_string())
222 }
223}