1use std::fmt::{self, Display};
4
5use serde::{de, ser};
6
7pub type Result<T> = std::result::Result<T, Error>;
9
10#[derive(Debug)]
16pub struct Error {
17 kind: ErrorKind,
18 line: Option<usize>,
19 column: Option<usize>,
20}
21
22impl Error {
23 pub fn kind(&self) -> &ErrorKind {
25 &self.kind
26 }
27
28 pub fn line(&self) -> Option<usize> {
30 self.line
31 }
32
33 pub fn column(&self) -> Option<usize> {
35 self.column
36 }
37
38 pub(crate) fn with_location(mut self, line: usize, column: usize) -> Self {
40 if self.line.is_none() {
41 self.line = Some(line);
42 self.column = Some(column);
43 }
44 self
45 }
46}
47
48impl From<ErrorKind> for Error {
49 fn from(kind: ErrorKind) -> Self {
50 Error {
51 kind,
52 line: None,
53 column: None,
54 }
55 }
56}
57
58#[non_exhaustive]
60#[derive(Debug, Clone, PartialEq)]
61pub enum ErrorKind {
62 Message(String),
64
65 Io(String),
67
68 Eof,
70
71 Syntax,
73
74 ExpectedBoolean,
76
77 ExpectedInteger,
79
80 ExpectedFloat,
82
83 ExpectedString,
85
86 ExpectedArray,
88
89 ExpectedArrayComma,
91
92 ExpectedArrayEnd,
94
95 ExpectedArraySemicolon,
97
98 ExpectedList,
100
101 ExpectedListComma,
103
104 ExpectedListEnd,
106
107 ExpectedGroup,
109
110 ExpectedEquals,
112
113 ExpectedSemicolon,
115
116 ExpectedCommaOrSemicolon,
118
119 ExpectedGroupEnd,
121
122 ExpectedIdentifier,
124
125 TrailingCharacters,
127
128 HeterogeneousArray,
130
131 InvalidEscape,
133
134 InvalidNumber,
136
137 KeyMustBeAString,
139
140 UnitNotSupported,
142
143 TypeNotSupported(String),
145
146 IntegerOutOfRange,
148
149 FloatOutOfRange,
151
152 NonFiniteFloat,
154
155 InvalidSettingName(String),
157
158 InvalidPath(String),
160
161 PathTraversal(String),
163
164 ArrayElementNotScalar,
166
167 TopLevelBraces,
171
172 UnterminatedComment,
175
176 Include(String),
178}
179
180impl ser::Error for Error {
181 fn custom<T: Display>(msg: T) -> Self {
182 ErrorKind::Message(msg.to_string()).into()
183 }
184}
185
186impl de::Error for Error {
187 fn custom<T: Display>(msg: T) -> Self {
188 ErrorKind::Message(msg.to_string()).into()
189 }
190}
191
192impl Display for ErrorKind {
193 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
194 match self {
195 ErrorKind::Message(msg) => formatter.write_str(msg),
196 ErrorKind::Io(msg) => write!(formatter, "i/o error: {}", msg),
197 ErrorKind::Eof => formatter.write_str("unexpected end of input"),
198 ErrorKind::Syntax => formatter.write_str("syntax error"),
199 ErrorKind::ExpectedBoolean => formatter.write_str("expected boolean"),
200 ErrorKind::ExpectedInteger => formatter.write_str("expected integer"),
201 ErrorKind::ExpectedFloat => formatter.write_str("expected float"),
202 ErrorKind::ExpectedString => formatter.write_str("expected string"),
203 ErrorKind::ExpectedArray => formatter.write_str("expected array"),
204 ErrorKind::ExpectedArrayComma => formatter.write_str("expected comma in array"),
205 ErrorKind::ExpectedArrayEnd => formatter.write_str("expected end of array"),
206 ErrorKind::ExpectedArraySemicolon => {
207 formatter.write_str("expected semicolon after array")
208 }
209 ErrorKind::ExpectedList => formatter.write_str("expected list"),
210 ErrorKind::ExpectedListComma => formatter.write_str("expected comma in list"),
211 ErrorKind::ExpectedListEnd => formatter.write_str("expected end of list"),
212 ErrorKind::ExpectedGroup => formatter.write_str("expected group"),
213 ErrorKind::ExpectedEquals => formatter.write_str("expected '=' or ':'"),
214 ErrorKind::ExpectedSemicolon => formatter.write_str("expected semicolon"),
215 ErrorKind::ExpectedCommaOrSemicolon => {
216 formatter.write_str("expected comma or semicolon")
217 }
218 ErrorKind::ExpectedGroupEnd => formatter.write_str("expected end of group"),
219 ErrorKind::ExpectedIdentifier => formatter.write_str("expected identifier"),
220 ErrorKind::TrailingCharacters => formatter.write_str("trailing characters"),
221 ErrorKind::HeterogeneousArray => {
222 formatter.write_str("heterogeneous arrays not supported")
223 }
224 ErrorKind::InvalidEscape => formatter.write_str("invalid escape sequence"),
225 ErrorKind::InvalidNumber => formatter.write_str("invalid number"),
226 ErrorKind::KeyMustBeAString => formatter.write_str("map keys must be strings"),
227 ErrorKind::UnitNotSupported => formatter.write_str("unit type not supported"),
228 ErrorKind::TypeNotSupported(ty) => write!(formatter, "type not supported: {}", ty),
229 ErrorKind::IntegerOutOfRange => {
230 formatter.write_str("integer value out of range for target type")
231 }
232 ErrorKind::FloatOutOfRange => {
233 formatter.write_str("float value out of range for target type")
234 }
235 ErrorKind::NonFiniteFloat => {
236 formatter.write_str("non-finite floats (inf, NaN) cannot be represented")
237 }
238 ErrorKind::InvalidSettingName(name) => write!(
239 formatter,
240 "invalid setting name '{}': names must match [A-Za-z*][-A-Za-z0-9_*]*",
241 name
242 ),
243 ErrorKind::InvalidPath(path) => write!(formatter, "invalid path '{}'", path),
244 ErrorKind::PathTraversal(msg) => write!(formatter, "path traversal failed: {}", msg),
245 ErrorKind::ArrayElementNotScalar => {
246 formatter.write_str("arrays may only contain scalar values")
247 }
248 ErrorKind::TopLevelBraces => formatter.write_str(
249 "braces are not allowed around the top level of a configuration; \
250 write settings directly (name = value;)",
251 ),
252 ErrorKind::UnterminatedComment => {
253 formatter.write_str("unterminated block comment: missing '*/'")
254 }
255 ErrorKind::Include(msg) => write!(formatter, "include error: {}", msg),
256 }
257 }
258}
259
260impl Display for Error {
261 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
262 match (self.line, self.column) {
263 (Some(line), Some(column)) => {
264 write!(formatter, "{} at line {}, column {}", self.kind, line, column)
265 }
266 _ => self.kind.fmt(formatter),
267 }
268 }
269}
270
271impl std::error::Error for Error {}