Skip to main content

nd2_rs/
error.rs

1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum Nd2Error {
5    #[error("file error: {source}")]
6    File { source: FileError },
7
8    #[error("input error: {source}")]
9    Input { source: InputError },
10
11    #[error("internal error: {source}")]
12    Internal { source: InternalError },
13
14    #[error("unsupported: {source}")]
15    Unsupported { source: UnsupportedError },
16}
17
18#[derive(Error, Debug)]
19pub enum FileError {
20    #[error("IO error: {0}")]
21    Io(#[from] std::io::Error),
22
23    #[error("Invalid ND2 file: {context}")]
24    InvalidFormat { context: String },
25
26    #[error("Invalid magic number: expected 0x{expected:08X}, got 0x{actual:08X}")]
27    InvalidMagic { expected: u32, actual: u32 },
28
29    #[error("Corrupt chunk header at position {position}")]
30    CorruptChunkHeader { position: u64 },
31
32    #[error("Chunk '{name}' not found in chunkmap")]
33    ChunkNotFound { name: String },
34
35    #[error("Invalid chunkmap signature")]
36    InvalidChunkmapSignature,
37
38    #[error("Chunkmap error: {context}")]
39    ChunkmapParse { context: String },
40
41    #[error("CLX parsing error: {context}")]
42    ClxParse { context: String },
43
44    #[error("Decompression error: {context}")]
45    Decompression { context: String },
46
47    #[error("UTF-16 decoding error: {context}")]
48    Utf16Decode { context: String },
49
50    #[error("Metadata parse error: {context}")]
51    MetadataParse { context: String },
52}
53
54#[derive(Error, Debug)]
55pub enum InputError {
56    #[error("Missing required dimension '{dimension}'")]
57    MissingDimension { dimension: String },
58
59    #[error("{field} index out of range: got {index}, max {max}")]
60    OutOfRange {
61        field: String,
62        index: usize,
63        max: usize,
64    },
65
66    #[error("Invalid input for {field}: {detail}")]
67    InvalidArgument { field: String, detail: String },
68
69    #[error("Incompatible parameters: expected {expected}, provided {provided}")]
70    IncompatibleParams { expected: String, provided: String },
71}
72
73#[derive(Error, Debug)]
74pub enum InternalError {
75    #[error("Arithmetic overflow during {operation}")]
76    Overflow { operation: String },
77
78    #[error("Internal invariant violation: {detail}")]
79    InvariantViolation { detail: String },
80}
81
82#[derive(Error, Debug)]
83pub enum UnsupportedError {
84    #[error("Unsupported ND2 file version: {major}.{minor}")]
85    Version { major: u32, minor: u32 },
86
87    #[error("Unsupported CLX data type: {type_code}")]
88    ClxType { type_code: u8 },
89}
90
91#[derive(Copy, Clone, Debug, PartialEq, Eq)]
92pub enum ErrorSource {
93    File,
94    Input,
95    Internal,
96    Unsupported,
97}
98
99impl Nd2Error {
100    pub fn source(&self) -> ErrorSource {
101        match self {
102            Self::File { .. } => ErrorSource::File,
103            Self::Input { .. } => ErrorSource::Input,
104            Self::Internal { .. } => ErrorSource::Internal,
105            Self::Unsupported { .. } => ErrorSource::Unsupported,
106        }
107    }
108
109    pub fn is_file(&self) -> bool {
110        matches!(self, Self::File { .. })
111    }
112
113    pub fn is_input(&self) -> bool {
114        matches!(self, Self::Input { .. })
115    }
116
117    pub fn is_internal(&self) -> bool {
118        matches!(self, Self::Internal { .. })
119    }
120
121    pub fn is_unsupported(&self) -> bool {
122        matches!(self, Self::Unsupported { .. })
123    }
124
125    pub fn file_invalid_format(context: impl Into<String>) -> Self {
126        Self::File {
127            source: FileError::InvalidFormat {
128                context: context.into(),
129            },
130        }
131    }
132
133    pub fn file_chunkmap(context: impl Into<String>) -> Self {
134        Self::File {
135            source: FileError::ChunkmapParse {
136                context: context.into(),
137            },
138        }
139    }
140
141    pub fn file_metadata(context: impl Into<String>) -> Self {
142        Self::File {
143            source: FileError::MetadataParse {
144                context: context.into(),
145            },
146        }
147    }
148
149    pub fn file_invalid_magic(expected: u32, actual: u32) -> Self {
150        Self::File {
151            source: FileError::InvalidMagic { expected, actual },
152        }
153    }
154
155    pub fn file_chunk_not_found(name: impl Into<String>) -> Self {
156        Self::File {
157            source: FileError::ChunkNotFound { name: name.into() },
158        }
159    }
160
161    pub fn input_out_of_range(field: impl Into<String>, index: usize, max: usize) -> Self {
162        Self::Input {
163            source: InputError::OutOfRange {
164                field: field.into(),
165                index,
166                max,
167            },
168        }
169    }
170
171    pub fn input_missing_dim(dimension: impl Into<String>) -> Self {
172        Self::Input {
173            source: InputError::MissingDimension {
174                dimension: dimension.into(),
175            },
176        }
177    }
178
179    pub fn input_argument(field: impl Into<String>, detail: impl Into<String>) -> Self {
180        Self::Input {
181            source: InputError::InvalidArgument {
182                field: field.into(),
183                detail: detail.into(),
184            },
185        }
186    }
187
188    pub fn internal_overflow(operation: impl Into<String>) -> Self {
189        Self::Internal {
190            source: InternalError::Overflow {
191                operation: operation.into(),
192            },
193        }
194    }
195
196    pub fn unsupported_version(major: u32, minor: u32) -> Self {
197        Self::Unsupported {
198            source: UnsupportedError::Version { major, minor },
199        }
200    }
201
202    pub fn unsupported_clx_type(type_code: u8) -> Self {
203        Self::Unsupported {
204            source: UnsupportedError::ClxType { type_code },
205        }
206    }
207}
208
209impl From<std::io::Error> for Nd2Error {
210    fn from(value: std::io::Error) -> Self {
211        Self::File {
212            source: FileError::Io(value),
213        }
214    }
215}
216
217pub type Result<T> = std::result::Result<T, Nd2Error>;