1use super::builder::ErrorContext;
4use super::types::*;
5
6#[cfg(feature = "std")]
7use std::path::Path;
8
9impl IoError {
10 pub fn code(&self) -> &'static str {
12 match self {
13 Self::NotFound { .. } => "E100",
14 Self::PermissionDenied { .. } => "E101",
15 Self::Network { .. } => "E102",
16 Self::UnexpectedEof { .. } => "E103",
17 Self::Read { .. } => "E104",
18 Self::Write { .. } => "E105",
19 Self::Seek { .. } => "E106",
20 Self::Http { .. } => "E107",
21 }
22 }
23
24 pub fn suggestion(&self) -> Option<&'static str> {
26 match self {
27 Self::NotFound { .. } => Some("Verify the file path is correct and the file exists"),
28 Self::PermissionDenied { .. } => {
29 Some("Check file permissions or run with appropriate privileges")
30 }
31 Self::Network { .. } => Some("Check network connectivity and firewall settings"),
32 Self::UnexpectedEof { .. } => Some("The file may be truncated or corrupted"),
33 Self::Read { .. } => {
34 Some("Ensure the file is accessible and not locked by another process")
35 }
36 Self::Write { .. } => Some("Check available disk space and write permissions"),
37 Self::Seek { .. } => Some("The file position may be invalid for this file type"),
38 Self::Http { status, .. } if *status == 404 => {
39 Some("The requested resource was not found on the server")
40 }
41 Self::Http { status, .. } if *status == 403 => {
42 Some("Access to this resource is forbidden. Check authentication credentials")
43 }
44 Self::Http { status, .. } if *status >= 500 => {
45 Some("The server is experiencing issues. Try again later")
46 }
47 Self::Http { .. } => Some("Check the HTTP request parameters and server status"),
48 }
49 }
50
51 pub fn context(&self) -> ErrorContext {
53 match self {
54 Self::NotFound { path } => {
55 ErrorContext::new("file_not_found").with_detail("path", path.clone())
56 }
57 Self::PermissionDenied { path } => {
58 ErrorContext::new("permission_denied").with_detail("path", path.clone())
59 }
60 Self::Network { message } => {
61 ErrorContext::new("network_error").with_detail("message", message.clone())
62 }
63 Self::UnexpectedEof { offset } => {
64 ErrorContext::new("unexpected_eof").with_detail("offset", offset.to_string())
65 }
66 Self::Read { message } => {
67 ErrorContext::new("read_error").with_detail("message", message.clone())
68 }
69 Self::Write { message } => {
70 ErrorContext::new("write_error").with_detail("message", message.clone())
71 }
72 Self::Seek { position } => {
73 ErrorContext::new("seek_error").with_detail("position", position.to_string())
74 }
75 Self::Http { status, message } => ErrorContext::new("http_error")
76 .with_detail("status", status.to_string())
77 .with_detail("message", message.clone()),
78 }
79 }
80}
81
82impl FormatError {
83 pub fn code(&self) -> &'static str {
85 match self {
86 Self::InvalidMagic { .. } => "E200",
87 Self::InvalidHeader { .. } => "E201",
88 Self::UnsupportedVersion { .. } => "E202",
89 Self::InvalidTag { .. } => "E203",
90 Self::MissingTag { .. } => "E204",
91 Self::InvalidDataType { .. } => "E205",
92 Self::CorruptData { .. } => "E206",
93 Self::InvalidGeoKey { .. } => "E207",
94 }
95 }
96
97 pub fn suggestion(&self) -> Option<&'static str> {
99 match self {
100 Self::InvalidMagic { .. } => {
101 Some("The file may not be in the expected format. Verify the file type")
102 }
103 Self::InvalidHeader { .. } => {
104 Some("The file header is corrupted or invalid. Try opening a different file")
105 }
106 Self::UnsupportedVersion { .. } => Some(
107 "This file version is not supported. Consider converting to a newer or older version",
108 ),
109 Self::InvalidTag { .. } => {
110 Some("The file contains invalid metadata tags. The file may be corrupted")
111 }
112 Self::MissingTag { .. } => {
113 Some("Required metadata is missing. The file may be incomplete or corrupted")
114 }
115 Self::InvalidDataType { .. } => {
116 Some("The data type is not recognized. The file may be from a newer version")
117 }
118 Self::CorruptData { .. } => {
119 Some("Data corruption detected. Try recovering from a backup")
120 }
121 Self::InvalidGeoKey { .. } => {
122 Some("Geographic metadata is invalid. Check the coordinate reference system")
123 }
124 }
125 }
126
127 pub fn context(&self) -> ErrorContext {
129 match self {
130 Self::InvalidMagic { expected, actual } => ErrorContext::new("invalid_magic")
131 .with_detail("expected", format!("{:?}", expected))
132 .with_detail("actual", format!("{:?}", actual)),
133 Self::InvalidHeader { message } => {
134 ErrorContext::new("invalid_header").with_detail("message", message.clone())
135 }
136 Self::UnsupportedVersion { version } => {
137 ErrorContext::new("unsupported_version").with_detail("version", version.to_string())
138 }
139 Self::InvalidTag { tag, message } => ErrorContext::new("invalid_tag")
140 .with_detail("tag", tag.to_string())
141 .with_detail("message", message.clone()),
142 Self::MissingTag { tag } => {
143 ErrorContext::new("missing_tag").with_detail("tag", tag.to_string())
144 }
145 Self::InvalidDataType { type_id } => {
146 ErrorContext::new("invalid_data_type").with_detail("type_id", type_id.to_string())
147 }
148 Self::CorruptData { offset, message } => ErrorContext::new("corrupt_data")
149 .with_detail("offset", offset.to_string())
150 .with_detail("message", message.clone()),
151 Self::InvalidGeoKey { key_id, message } => ErrorContext::new("invalid_geokey")
152 .with_detail("key_id", key_id.to_string())
153 .with_detail("message", message.clone()),
154 }
155 }
156}
157
158impl CrsError {
159 pub fn code(&self) -> &'static str {
161 match self {
162 Self::UnknownCrs { .. } => "E300",
163 Self::InvalidWkt { .. } => "E301",
164 Self::InvalidEpsg { .. } => "E302",
165 Self::TransformationError { .. } => "E303",
166 Self::DatumNotFound { .. } => "E304",
167 }
168 }
169
170 pub fn suggestion(&self) -> Option<&'static str> {
172 match self {
173 Self::UnknownCrs { .. } => {
174 Some("Verify the CRS identifier or use a standard EPSG code")
175 }
176 Self::InvalidWkt { .. } => {
177 Some("Check the WKT string syntax. Ensure proper bracketing and spacing")
178 }
179 Self::InvalidEpsg { .. } => Some("Use a valid EPSG code from https://epsg.io"),
180 Self::TransformationError { .. } => {
181 Some("Ensure both CRS are compatible and transformation parameters are available")
182 }
183 Self::DatumNotFound { .. } => {
184 Some("The datum definition may be missing. Check CRS database installation")
185 }
186 }
187 }
188
189 pub fn context(&self) -> ErrorContext {
191 match self {
192 Self::UnknownCrs { identifier } => {
193 ErrorContext::new("unknown_crs").with_detail("identifier", identifier.clone())
194 }
195 Self::InvalidWkt { message } => {
196 ErrorContext::new("invalid_wkt").with_detail("message", message.clone())
197 }
198 Self::InvalidEpsg { code } => {
199 ErrorContext::new("invalid_epsg").with_detail("code", code.to_string())
200 }
201 Self::TransformationError {
202 source_crs,
203 target_crs,
204 message,
205 } => ErrorContext::new("transformation_error")
206 .with_detail("source_crs", source_crs.clone())
207 .with_detail("target_crs", target_crs.clone())
208 .with_detail("message", message.clone()),
209 Self::DatumNotFound { datum } => {
210 ErrorContext::new("datum_not_found").with_detail("datum", datum.clone())
211 }
212 }
213 }
214}
215
216impl CompressionError {
217 pub fn code(&self) -> &'static str {
219 match self {
220 Self::UnknownMethod { .. } => "E400",
221 Self::DecompressionFailed { .. } => "E401",
222 Self::CompressionFailed { .. } => "E402",
223 Self::InvalidData { .. } => "E403",
224 }
225 }
226
227 pub fn suggestion(&self) -> Option<&'static str> {
229 match self {
230 Self::UnknownMethod { .. } => Some(
231 "The compression method is not supported. Check available compression features",
232 ),
233 Self::DecompressionFailed { .. } => {
234 Some("The compressed data may be corrupted. Try a backup or re-download the file")
235 }
236 Self::CompressionFailed { .. } => Some(
237 "Compression failed. Try a different compression method or lower compression level",
238 ),
239 Self::InvalidData { .. } => Some("The compressed data is invalid or corrupted"),
240 }
241 }
242
243 pub fn context(&self) -> ErrorContext {
245 match self {
246 Self::UnknownMethod { method } => {
247 ErrorContext::new("unknown_compression").with_detail("method", method.to_string())
248 }
249 Self::DecompressionFailed { message } => {
250 ErrorContext::new("decompression_failed").with_detail("message", message.clone())
251 }
252 Self::CompressionFailed { message } => {
253 ErrorContext::new("compression_failed").with_detail("message", message.clone())
254 }
255 Self::InvalidData { message } => {
256 ErrorContext::new("invalid_compressed_data").with_detail("message", message.clone())
257 }
258 }
259 }
260}
261
262impl OxiGdalError {
263 pub fn allocation_error(message: impl Into<String>) -> Self {
265 Self::Internal {
266 message: format!("Allocation error: {}", message.into()),
267 }
268 }
269
270 pub fn allocation_error_builder(message: impl Into<String>) -> crate::error::ErrorBuilder {
272 crate::error::ErrorBuilder::new(Self::allocation_error(message))
273 }
274
275 pub fn invalid_state(message: impl Into<String>) -> Self {
277 Self::Internal {
278 message: format!("Invalid state: {}", message.into()),
279 }
280 }
281
282 pub fn invalid_state_builder(message: impl Into<String>) -> crate::error::ErrorBuilder {
284 crate::error::ErrorBuilder::new(Self::invalid_state(message))
285 }
286
287 pub fn invalid_operation(message: impl Into<String>) -> Self {
289 Self::NotSupported {
290 operation: message.into(),
291 }
292 }
293
294 pub fn invalid_operation_builder(message: impl Into<String>) -> crate::error::ErrorBuilder {
296 crate::error::ErrorBuilder::new(Self::invalid_operation(message))
297 }
298
299 pub fn io_error(message: impl Into<String>) -> Self {
301 Self::Io(IoError::Read {
302 message: message.into(),
303 })
304 }
305
306 pub fn io_error_builder(message: impl Into<String>) -> crate::error::ErrorBuilder {
308 crate::error::ErrorBuilder::new(Self::io_error(message))
309 }
310
311 pub fn invalid_parameter(parameter: &'static str, message: impl Into<String>) -> Self {
313 Self::InvalidParameter {
314 parameter,
315 message: message.into(),
316 }
317 }
318
319 pub fn invalid_parameter_builder(
321 parameter: &'static str,
322 message: impl Into<String>,
323 ) -> crate::error::ErrorBuilder {
324 crate::error::ErrorBuilder::new(Self::invalid_parameter(parameter, message))
325 }
326
327 pub fn not_supported(operation: impl Into<String>) -> Self {
329 Self::NotSupported {
330 operation: operation.into(),
331 }
332 }
333
334 pub fn not_supported_builder(operation: impl Into<String>) -> crate::error::ErrorBuilder {
336 crate::error::ErrorBuilder::new(Self::not_supported(operation))
337 }
338
339 #[cfg(feature = "std")]
341 pub fn from_path(path: &Path, kind: std::io::ErrorKind) -> Self {
342 let path_str = path.display().to_string();
343 match kind {
344 std::io::ErrorKind::NotFound => Self::Io(IoError::NotFound { path: path_str }),
345 std::io::ErrorKind::PermissionDenied => {
346 Self::Io(IoError::PermissionDenied { path: path_str })
347 }
348 _ => Self::Io(IoError::Read {
349 message: format!("Error accessing {}", path_str),
350 }),
351 }
352 }
353
354 #[cfg(feature = "std")]
356 pub fn from_path_builder(path: &Path, kind: std::io::ErrorKind) -> crate::error::ErrorBuilder {
357 crate::error::ErrorBuilder::new(Self::from_path(path, kind)).with_path(path)
358 }
359
360 pub fn code(&self) -> &'static str {
365 match self {
366 Self::Io(e) => e.code(),
367 Self::Format(e) => e.code(),
368 Self::Crs(e) => e.code(),
369 Self::Compression(e) => e.code(),
370 Self::InvalidParameter { .. } => "E001",
371 Self::NotSupported { .. } => "E002",
372 Self::OutOfBounds { .. } => "E003",
373 Self::Internal { .. } => "E004",
374 }
375 }
376
377 pub fn suggestion(&self) -> Option<&'static str> {
381 match self {
382 Self::Io(e) => e.suggestion(),
383 Self::Format(e) => e.suggestion(),
384 Self::Crs(e) => e.suggestion(),
385 Self::Compression(e) => e.suggestion(),
386 Self::InvalidParameter { .. } => {
387 Some("Check the parameter documentation for valid values")
388 }
389 Self::NotSupported { .. } => {
390 Some("Check if the feature is enabled or use an alternative approach")
391 }
392 Self::OutOfBounds { .. } => Some("Verify the indices are within valid range"),
393 Self::Internal { .. } => {
394 Some("This is likely a bug. Please report it with steps to reproduce")
395 }
396 }
397 }
398
399 pub fn context(&self) -> ErrorContext {
403 match self {
404 Self::Io(e) => e.context(),
405 Self::Format(e) => e.context(),
406 Self::Crs(e) => e.context(),
407 Self::Compression(e) => e.context(),
408 Self::InvalidParameter { parameter, message } => {
409 ErrorContext::new("parameter_validation")
410 .with_detail("parameter", *parameter)
411 .with_detail("reason", message.clone())
412 }
413 Self::NotSupported { operation } => ErrorContext::new("unsupported_operation")
414 .with_detail("operation", operation.clone()),
415 Self::OutOfBounds { message } => {
416 ErrorContext::new("bounds_check").with_detail("reason", message.clone())
417 }
418 Self::Internal { message } => {
419 ErrorContext::new("internal_error").with_detail("details", message.clone())
420 }
421 }
422 }
423}