1use std::io;
7use thiserror::Error;
8
9pub type Result<T> = std::result::Result<T, Error>;
11
12#[derive(Error, Debug)]
25#[non_exhaustive]
26pub enum Error {
27 #[error("Parse error at line {line}, column {column}: {message}")]
29 Parse {
30 message: String,
32 line: usize,
34 column: usize,
36 file: Option<String>,
38 },
39
40 #[error("Unknown format: {format}")]
42 UnknownFormat {
43 format: String,
45 },
46
47 #[error("Key '{key}' not found")]
49 KeyNotFound {
50 key: String,
52 available: Vec<String>,
54 },
55
56 #[error("Type error: cannot convert '{value}' to {expected_type}")]
58 Type {
59 value: String,
61 expected_type: String,
63 actual_type: String,
65 },
66
67 #[error("File error for '{path}': {source}")]
69 Io {
70 path: String,
72 #[source]
74 source: io::Error,
75 },
76
77 #[cfg(feature = "schema")]
79 #[error("Schema error at '{path}': {message}")]
80 Schema {
81 path: String,
83 message: String,
85 expected: Option<String>,
87 },
88
89 #[error("Validation error: {message}")]
91 Validation {
92 message: String,
94 },
95
96 #[error("{message}")]
98 General {
99 message: String,
101 },
102
103 #[error("Feature '{feature}' is not enabled. Enable with features = [\"{feature}\"]")]
105 FeatureNotEnabled {
106 feature: String,
108 },
109
110 #[error("Concurrency error: {message}")]
112 Concurrency {
113 message: String,
115 },
116
117 #[cfg(feature = "noml")]
119 #[error("NOML error: {source}")]
120 Noml {
121 #[from]
123 source: noml::NomlError,
124 },
125
126 #[error("Internal error: {message}")]
128 Internal {
129 message: String,
131 context: Option<String>,
133 },
134}
135
136impl Error {
137 pub fn parse(message: impl Into<String>, line: usize, column: usize) -> Self {
139 Self::Parse {
140 message: message.into(),
141 line,
142 column,
143 file: None,
144 }
145 }
146
147 pub fn parse_with_file(
149 message: impl Into<String>,
150 line: usize,
151 column: usize,
152 file: impl Into<String>,
153 ) -> Self {
154 Self::Parse {
155 message: message.into(),
156 line,
157 column,
158 file: Some(file.into()),
159 }
160 }
161
162 pub fn key_not_found(key: impl Into<String>) -> Self {
164 Self::KeyNotFound {
165 key: key.into(),
166 available: Vec::new(),
167 }
168 }
169
170 pub fn key_not_found_with_suggestions(key: impl Into<String>, available: Vec<String>) -> Self {
172 Self::KeyNotFound {
173 key: key.into(),
174 available,
175 }
176 }
177
178 pub fn type_error(
180 value: impl Into<String>,
181 expected: impl Into<String>,
182 actual: impl Into<String>,
183 ) -> Self {
184 Self::Type {
185 value: value.into(),
186 expected_type: expected.into(),
187 actual_type: actual.into(),
188 }
189 }
190
191 pub fn io(path: impl Into<String>, source: io::Error) -> Self {
193 Self::Io {
194 path: path.into(),
195 source,
196 }
197 }
198
199 pub fn unknown_format(format: impl Into<String>) -> Self {
201 Self::UnknownFormat {
202 format: format.into(),
203 }
204 }
205
206 pub fn feature_not_enabled(feature: impl Into<String>) -> Self {
208 Self::FeatureNotEnabled {
209 feature: feature.into(),
210 }
211 }
212
213 pub fn concurrency(message: impl Into<String>) -> Self {
215 Self::Concurrency {
216 message: message.into(),
217 }
218 }
219
220 pub fn serialize(message: impl Into<String>) -> Self {
222 Self::General {
223 message: message.into(),
224 }
225 }
226
227 #[cfg(feature = "schema")]
229 pub fn schema(path: impl Into<String>, message: impl Into<String>) -> Self {
230 Self::Schema {
231 path: path.into(),
232 message: message.into(),
233 expected: None,
234 }
235 }
236
237 #[cfg(feature = "schema")]
239 pub fn schema_with_expected(
240 path: impl Into<String>,
241 message: impl Into<String>,
242 expected: impl Into<String>,
243 ) -> Self {
244 Self::Schema {
245 path: path.into(),
246 message: message.into(),
247 expected: Some(expected.into()),
248 }
249 }
250
251 pub fn validation(message: impl Into<String>) -> Self {
253 Self::Validation {
254 message: message.into(),
255 }
256 }
257
258 pub fn general(message: impl Into<String>) -> Self {
260 Self::General {
261 message: message.into(),
262 }
263 }
264
265 pub fn internal(message: impl Into<String>) -> Self {
267 Self::Internal {
268 message: message.into(),
269 context: None,
270 }
271 }
272
273 pub fn internal_with_context(message: impl Into<String>, context: impl Into<String>) -> Self {
275 Self::Internal {
276 message: message.into(),
277 context: Some(context.into()),
278 }
279 }
280}
281
282impl From<io::Error> for Error {
284 fn from(source: io::Error) -> Self {
285 Self::Io {
286 path: "unknown".to_string(),
287 source,
288 }
289 }
290}