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