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 #[cfg(feature = "noml")]
104 #[error("NOML error: {source}")]
105 Noml {
106 #[from]
108 source: noml::NomlError,
109 },
110
111 #[error("Internal error: {message}")]
113 Internal {
114 message: String,
116 context: Option<String>,
118 },
119}
120
121impl Error {
122 pub fn parse(message: impl Into<String>, line: usize, column: usize) -> Self {
124 Self::Parse {
125 message: message.into(),
126 line,
127 column,
128 file: None,
129 }
130 }
131
132 pub fn parse_with_file(
134 message: impl Into<String>,
135 line: usize,
136 column: usize,
137 file: impl Into<String>,
138 ) -> Self {
139 Self::Parse {
140 message: message.into(),
141 line,
142 column,
143 file: Some(file.into()),
144 }
145 }
146
147 pub fn key_not_found(key: impl Into<String>) -> Self {
149 Self::KeyNotFound {
150 key: key.into(),
151 available: Vec::new(),
152 }
153 }
154
155 pub fn key_not_found_with_suggestions(
157 key: impl Into<String>,
158 available: Vec<String>,
159 ) -> Self {
160 Self::KeyNotFound {
161 key: key.into(),
162 available,
163 }
164 }
165
166 pub fn type_error(
168 value: impl Into<String>,
169 expected: impl Into<String>,
170 actual: impl Into<String>,
171 ) -> Self {
172 Self::Type {
173 value: value.into(),
174 expected_type: expected.into(),
175 actual_type: actual.into(),
176 }
177 }
178
179 pub fn io(path: impl Into<String>, source: io::Error) -> Self {
181 Self::Io {
182 path: path.into(),
183 source,
184 }
185 }
186
187 pub fn unknown_format(format: impl Into<String>) -> Self {
189 Self::UnknownFormat {
190 format: format.into(),
191 }
192 }
193
194 pub fn feature_not_enabled(feature: impl Into<String>) -> Self {
196 Self::FeatureNotEnabled {
197 feature: feature.into(),
198 }
199 }
200
201 pub fn serialize(message: impl Into<String>) -> Self {
203 Self::General {
204 message: message.into(),
205 }
206 }
207
208 #[cfg(feature = "schema")]
210 pub fn schema(path: impl Into<String>, message: impl Into<String>) -> Self {
211 Self::Schema {
212 path: path.into(),
213 message: message.into(),
214 expected: None,
215 }
216 }
217
218 #[cfg(feature = "schema")]
220 pub fn schema_with_expected(
221 path: impl Into<String>,
222 message: impl Into<String>,
223 expected: impl Into<String>,
224 ) -> Self {
225 Self::Schema {
226 path: path.into(),
227 message: message.into(),
228 expected: Some(expected.into()),
229 }
230 }
231
232 pub fn validation(message: impl Into<String>) -> Self {
234 Self::Validation {
235 message: message.into(),
236 }
237 }
238
239 pub fn general(message: impl Into<String>) -> Self {
241 Self::General {
242 message: message.into(),
243 }
244 }
245
246 pub fn internal(message: impl Into<String>) -> Self {
248 Self::Internal {
249 message: message.into(),
250 context: None,
251 }
252 }
253
254 pub fn internal_with_context(
256 message: impl Into<String>,
257 context: impl Into<String>,
258 ) -> Self {
259 Self::Internal {
260 message: message.into(),
261 context: Some(context.into()),
262 }
263 }
264}
265
266impl From<io::Error> for Error {
268 fn from(source: io::Error) -> Self {
269 Self::Io {
270 path: "unknown".to_string(),
271 source,
272 }
273 }
274}