1use std::io;
7use thiserror::Error;
8
9pub type Result<T> = std::result::Result<T, Error>;
11
12#[derive(Error, Debug)]
18pub enum Error {
19 #[error("Parse error at line {line}, column {column}: {message}")]
21 Parse {
22 message: String,
24 line: usize,
26 column: usize,
28 file: Option<String>,
30 },
31
32 #[error("Unknown format: {format}")]
34 UnknownFormat {
35 format: String,
37 },
38
39 #[error("Key '{key}' not found")]
41 KeyNotFound {
42 key: String,
44 available: Vec<String>,
46 },
47
48 #[error("Type error: cannot convert '{value}' to {expected_type}")]
50 Type {
51 value: String,
53 expected_type: String,
55 actual_type: String,
57 },
58
59 #[error("File error for '{path}': {source}")]
61 Io {
62 path: String,
64 #[source]
66 source: io::Error,
67 },
68
69 #[cfg(feature = "schema")]
71 #[error("Schema error at '{path}': {message}")]
72 Schema {
73 path: String,
75 message: String,
77 expected: Option<String>,
79 },
80
81 #[error("Validation error: {message}")]
83 Validation {
84 message: String,
86 },
87
88 #[error("{message}")]
90 General {
91 message: String,
93 },
94
95 #[error("Feature '{feature}' is not enabled. Enable with features = [\"{feature}\"]")]
97 FeatureNotEnabled {
98 feature: String,
100 },
101
102 #[error("Concurrency error: {message}")]
104 Concurrency {
105 message: String,
107 },
108
109 #[cfg(feature = "noml")]
111 #[error("NOML error: {source}")]
112 Noml {
113 #[from]
115 source: noml::NomlError,
116 },
117
118 #[error("Internal error: {message}")]
120 Internal {
121 message: String,
123 context: Option<String>,
125 },
126}
127
128impl Error {
129 pub fn parse(message: impl Into<String>, line: usize, column: usize) -> Self {
131 Self::Parse {
132 message: message.into(),
133 line,
134 column,
135 file: None,
136 }
137 }
138
139 pub fn parse_with_file(
141 message: impl Into<String>,
142 line: usize,
143 column: usize,
144 file: impl Into<String>,
145 ) -> Self {
146 Self::Parse {
147 message: message.into(),
148 line,
149 column,
150 file: Some(file.into()),
151 }
152 }
153
154 pub fn key_not_found(key: impl Into<String>) -> Self {
156 Self::KeyNotFound {
157 key: key.into(),
158 available: Vec::new(),
159 }
160 }
161
162 pub fn key_not_found_with_suggestions(key: impl Into<String>, available: Vec<String>) -> Self {
164 Self::KeyNotFound {
165 key: key.into(),
166 available,
167 }
168 }
169
170 pub fn type_error(
172 value: impl Into<String>,
173 expected: impl Into<String>,
174 actual: impl Into<String>,
175 ) -> Self {
176 Self::Type {
177 value: value.into(),
178 expected_type: expected.into(),
179 actual_type: actual.into(),
180 }
181 }
182
183 pub fn io(path: impl Into<String>, source: io::Error) -> Self {
185 Self::Io {
186 path: path.into(),
187 source,
188 }
189 }
190
191 pub fn unknown_format(format: impl Into<String>) -> Self {
193 Self::UnknownFormat {
194 format: format.into(),
195 }
196 }
197
198 pub fn feature_not_enabled(feature: impl Into<String>) -> Self {
200 Self::FeatureNotEnabled {
201 feature: feature.into(),
202 }
203 }
204
205 pub fn concurrency(message: impl Into<String>) -> Self {
207 Self::Concurrency {
208 message: message.into(),
209 }
210 }
211
212 pub fn serialize(message: impl Into<String>) -> Self {
214 Self::General {
215 message: message.into(),
216 }
217 }
218
219 #[cfg(feature = "schema")]
221 pub fn schema(path: impl Into<String>, message: impl Into<String>) -> Self {
222 Self::Schema {
223 path: path.into(),
224 message: message.into(),
225 expected: None,
226 }
227 }
228
229 #[cfg(feature = "schema")]
231 pub fn schema_with_expected(
232 path: impl Into<String>,
233 message: impl Into<String>,
234 expected: impl Into<String>,
235 ) -> Self {
236 Self::Schema {
237 path: path.into(),
238 message: message.into(),
239 expected: Some(expected.into()),
240 }
241 }
242
243 pub fn validation(message: impl Into<String>) -> Self {
245 Self::Validation {
246 message: message.into(),
247 }
248 }
249
250 pub fn general(message: impl Into<String>) -> Self {
252 Self::General {
253 message: message.into(),
254 }
255 }
256
257 pub fn internal(message: impl Into<String>) -> Self {
259 Self::Internal {
260 message: message.into(),
261 context: None,
262 }
263 }
264
265 pub fn internal_with_context(message: impl Into<String>, context: impl Into<String>) -> Self {
267 Self::Internal {
268 message: message.into(),
269 context: Some(context.into()),
270 }
271 }
272}
273
274impl From<io::Error> for Error {
276 fn from(source: io::Error) -> Self {
277 Self::Io {
278 path: "unknown".to_string(),
279 source,
280 }
281 }
282}