1use std::ffi::NulError;
6use std::path::PathBuf;
7use thiserror::Error;
8
9#[derive(Debug, Error)]
11pub enum MnnError {
12 #[error("I/O error: {0}")]
14 Io(#[from] std::io::Error),
15
16 #[error("Invalid model: {0}")]
18 InvalidModel(String),
19
20 #[error("Session error: {0}")]
22 SessionError(String),
23
24 #[error("Tensor error: {0}")]
26 TensorError(String),
27
28 #[error("Backend error: {0}")]
30 BackendError(String),
31
32 #[error("Out of memory: {0}")]
34 OutOfMemory(String),
35
36 #[error("Unsupported operation: {0}")]
38 Unsupported(String),
39
40 #[error("Invalid input: {0}")]
42 InvalidInput(String),
43
44 #[error("Invalid path")]
46 InvalidPath,
47
48 #[error("Internal error: {0}")]
50 Internal(String),
51
52 #[error("Null byte in string: {0}")]
54 NullByte(#[from] NulError),
55
56 #[error("Path error: {path}")]
58 PathError {
59 path: PathBuf,
61 #[source]
63 source: std::io::Error,
64 },
65
66 #[error("Shape mismatch: expected {expected:?}, got {actual:?}")]
68 ShapeMismatch {
69 expected: Vec<i32>,
71 actual: Vec<i32>,
73 },
74
75 #[error("Type mismatch: expected {expected}, got {actual}")]
77 TypeMismatch {
78 expected: String,
80 actual: String,
82 },
83
84 #[error("Invalid dimension: {message}")]
86 InvalidDimension {
87 message: String,
89 },
90
91 #[error("Empty data provided")]
93 EmptyData,
94
95 #[error("Index {index} out of bounds for dimension {dim} with size {size}")]
97 IndexOutOfBounds {
98 dim: usize,
100 index: i32,
102 size: i32,
104 },
105
106 #[error("Backend {backend:?} is not available on this platform")]
108 BackendNotAvailable {
109 backend: String,
111 },
112
113 #[error("Model file not found: {0}")]
115 ModelNotFound(PathBuf),
116
117 #[error("Session not initialized")]
119 SessionNotInitialized,
120
121 #[error("Interpreter not initialized")]
123 InterpreterNotInitialized,
124
125 #[error("Feature '{feature}' is not enabled. Add it to Cargo.toml features.")]
127 FeatureNotEnabled {
128 feature: &'static str,
130 },
131
132 #[cfg(feature = "async")]
134 #[error("Async error: {0}")]
135 AsyncError(String),
136}
137
138pub type MnnResult<T> = Result<T, MnnError>;
140
141impl MnnError {
142 pub fn invalid_model<S: Into<String>>(msg: S) -> Self {
144 MnnError::InvalidModel(msg.into())
145 }
146
147 pub fn session_error<S: Into<String>>(msg: S) -> Self {
149 MnnError::SessionError(msg.into())
150 }
151
152 pub fn tensor_error<S: Into<String>>(msg: S) -> Self {
154 MnnError::TensorError(msg.into())
155 }
156
157 pub fn backend_error<S: Into<String>>(msg: S) -> Self {
159 MnnError::BackendError(msg.into())
160 }
161
162 pub fn unsupported<S: Into<String>>(msg: S) -> Self {
164 MnnError::Unsupported(msg.into())
165 }
166
167 pub fn invalid_input<S: Into<String>>(msg: S) -> Self {
169 MnnError::InvalidInput(msg.into())
170 }
171
172 pub fn internal<S: Into<String>>(msg: S) -> Self {
174 MnnError::Internal(msg.into())
175 }
176
177 pub fn shape_mismatch(expected: &[i32], actual: &[i32]) -> Self {
179 MnnError::ShapeMismatch {
180 expected: expected.to_vec(),
181 actual: actual.to_vec(),
182 }
183 }
184
185 pub fn out_of_memory<S: Into<String>>(msg: S) -> Self {
187 MnnError::OutOfMemory(msg.into())
188 }
189
190 pub fn index_out_of_bounds(dim: usize, index: i32, size: i32) -> Self {
192 MnnError::IndexOutOfBounds { dim, index, size }
193 }
194
195 pub fn backend_not_available<S: Into<String>>(backend: S) -> Self {
197 MnnError::BackendNotAvailable {
198 backend: backend.into(),
199 }
200 }
201
202 pub fn is_oom(&self) -> bool {
204 matches!(self, MnnError::OutOfMemory(_))
205 }
206
207 pub fn is_model_error(&self) -> bool {
209 matches!(
210 self,
211 MnnError::InvalidModel(_) | MnnError::ModelNotFound(_)
212 )
213 }
214
215 pub fn is_backend_error(&self) -> bool {
217 matches!(
218 self,
219 MnnError::BackendError(_) | MnnError::BackendNotAvailable { .. }
220 )
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 #[test]
229 fn test_error_creation() {
230 let err = MnnError::invalid_model("test error");
231 assert!(err.to_string().contains("test error"));
232 }
233
234 #[test]
235 fn test_shape_mismatch() {
236 let err = MnnError::shape_mismatch(&[1, 2, 3], &[1, 2, 4]);
237 assert!(err.to_string().contains("expected"));
238 assert!(err.to_string().contains("got"));
239 }
240
241 #[test]
242 fn test_error_checks() {
243 let err = MnnError::out_of_memory("test");
244 assert!(err.is_oom());
245
246 let err = MnnError::invalid_model("test");
247 assert!(err.is_model_error());
248
249 let err = MnnError::backend_error("test");
250 assert!(err.is_backend_error());
251 }
252}