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
93impl ConfigError {
94 #[doc(hidden)]
96 pub fn invalid_type(
97 origin: Option<String>,
98 unexpected: Unexpected,
99 expected: &'static str,
100 ) -> Self {
101 Self::Type { origin, unexpected, expected, key: None }
102 }
103
104 #[doc(hidden)]
107 pub fn invalid_root(origin: Option<&String>, unexpected: Unexpected) -> Box<Self> {
108 Box::new(Self::Type { origin: origin.cloned(), unexpected, expected: "a map", key: None })
109 }
110
111 #[doc(hidden)]
113 #[must_use]
114 pub fn extend_with_key(self, key: &str) -> Self {
115 match self {
116 Self::Type { origin, unexpected, expected, .. } => {
117 Self::Type { origin, unexpected, expected, key: Some(key.into()) }
118 }
119
120 _ => self,
121 }
122 }
123
124 #[must_use]
125 fn prepend(self, segment: &str, add_dot: bool) -> Self {
126 let concat = |key: Option<String>| {
127 let key = key.unwrap_or_default();
128 let dot = if add_dot && key.as_bytes().first().unwrap_or(&b'[') != &b'[' { "." } else { "" };
129 format!("{}{}{}", segment, dot, key)
130 };
131 match self {
132 Self::Type { origin, unexpected, expected, key } => {
133 Self::Type { origin, unexpected, expected, key: Some(concat(key)) }
134 }
135 Self::NotFound(key) => Self::NotFound(concat(Some(key))),
136 _ => self,
137 }
138 }
139
140 #[must_use]
141 pub(crate) fn prepend_key(self, key: &str) -> Self {
142 self.prepend(key, true)
143 }
144
145 #[must_use]
146 pub(crate) fn prepend_index(self, idx: usize) -> Self {
147 self.prepend(&format!("[{}]", idx), false)
148 }
149}
150
151pub type Result<T> = result::Result<T, ConfigError>;
153
154impl fmt::Debug for ConfigError {
156 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157 write!(f, "{}", *self)
158 }
159}
160
161impl fmt::Display for ConfigError {
162 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163 match *self {
164 ConfigError::Frozen => write!(f, "configuration is frozen"),
165
166 ConfigError::PathParse(ref kind) => write!(f, "{}", kind.description()),
167
168 ConfigError::Message(ref s) => write!(f, "{}", s),
169
170 ConfigError::Foreign(ref cause) => write!(f, "{}", cause),
171
172 ConfigError::NotFound(ref key) => {
173 write!(f, "configuration property {:?} not found", key)
174 }
175
176 ConfigError::Type { ref origin, ref unexpected, expected, ref key } => {
177 write!(f, "invalid type: {}, expected {}", unexpected, expected)?;
178
179 if let Some(ref key) = *key {
180 write!(f, " for key `{}`", key)?;
181 }
182
183 if let Some(ref origin) = *origin {
184 write!(f, " in {}", origin)?;
185 }
186
187 Ok(())
188 }
189
190 ConfigError::FileParse { ref cause, ref uri } => {
191 write!(f, "{}", cause)?;
192
193 if let Some(ref uri) = *uri {
194 write!(f, " in {}", uri)?;
195 }
196
197 Ok(())
198 }
199 }
200 }
201}
202
203impl Error for ConfigError {}
204
205impl de::Error for ConfigError {
206 fn custom<T: fmt::Display>(msg: T) -> Self {
207 Self::Message(msg.to_string())
208 }
209}
210
211impl ser::Error for ConfigError {
212 fn custom<T: fmt::Display>(msg: T) -> Self {
213 Self::Message(msg.to_string())
214 }
215}