Skip to main content

mnn_rs/
error.rs

1//! Error types for MNN operations.
2//!
3//! This module provides a comprehensive error type for all MNN operations.
4
5use std::ffi::NulError;
6use std::path::PathBuf;
7use thiserror::Error;
8
9/// Main error type for MNN operations.
10#[derive(Debug, Error)]
11pub enum MnnError {
12    /// I/O error (file not found, permission denied, etc.)
13    #[error("I/O error: {0}")]
14    Io(#[from] std::io::Error),
15
16    /// Invalid model file or corrupted model
17    #[error("Invalid model: {0}")]
18    InvalidModel(String),
19
20    /// Failed to create or use session
21    #[error("Session error: {0}")]
22    SessionError(String),
23
24    /// Tensor operation failed
25    #[error("Tensor error: {0}")]
26    TensorError(String),
27
28    /// Backend not available or misconfigured
29    #[error("Backend error: {0}")]
30    BackendError(String),
31
32    /// Out of memory
33    #[error("Out of memory: {0}")]
34    OutOfMemory(String),
35
36    /// Operation not supported
37    #[error("Unsupported operation: {0}")]
38    Unsupported(String),
39
40    /// Invalid input provided
41    #[error("Invalid input: {0}")]
42    InvalidInput(String),
43
44    /// Invalid path (non-UTF8 or invalid format)
45    #[error("Invalid path")]
46    InvalidPath,
47
48    /// Internal MNN error
49    #[error("Internal error: {0}")]
50    Internal(String),
51
52    /// Null byte in string
53    #[error("Null byte in string: {0}")]
54    NullByte(#[from] NulError),
55
56    /// Path-related error
57    #[error("Path error: {path}")]
58    PathError {
59        /// The problematic path
60        path: PathBuf,
61        /// The source error
62        #[source]
63        source: std::io::Error,
64    },
65
66    /// Shape mismatch
67    #[error("Shape mismatch: expected {expected:?}, got {actual:?}")]
68    ShapeMismatch {
69        /// Expected shape
70        expected: Vec<i32>,
71        /// Actual shape
72        actual: Vec<i32>,
73    },
74
75    /// Type mismatch
76    #[error("Type mismatch: expected {expected}, got {actual}")]
77    TypeMismatch {
78        /// Expected type
79        expected: String,
80        /// Actual type
81        actual: String,
82    },
83
84    /// Invalid dimension
85    #[error("Invalid dimension: {message}")]
86    InvalidDimension {
87        /// Error message
88        message: String,
89    },
90
91    /// Empty data
92    #[error("Empty data provided")]
93    EmptyData,
94
95    /// Index out of bounds
96    #[error("Index {index} out of bounds for dimension {dim} with size {size}")]
97    IndexOutOfBounds {
98        /// The dimension
99        dim: usize,
100        /// The index
101        index: i32,
102        /// The size
103        size: i32,
104    },
105
106    /// Backend not available
107    #[error("Backend {backend:?} is not available on this platform")]
108    BackendNotAvailable {
109        /// The requested backend
110        backend: String,
111    },
112
113    /// Model file not found
114    #[error("Model file not found: {0}")]
115    ModelNotFound(PathBuf),
116
117    /// Session not initialized
118    #[error("Session not initialized")]
119    SessionNotInitialized,
120
121    /// Interpreter not initialized
122    #[error("Interpreter not initialized")]
123    InterpreterNotInitialized,
124
125    /// Feature not enabled
126    #[error("Feature '{feature}' is not enabled. Add it to Cargo.toml features.")]
127    FeatureNotEnabled {
128        /// The feature name
129        feature: &'static str,
130    },
131
132    /// Async runtime error
133    #[cfg(feature = "async")]
134    #[error("Async error: {0}")]
135    AsyncError(String),
136}
137
138/// Result type alias for MNN operations.
139pub type MnnResult<T> = Result<T, MnnError>;
140
141impl MnnError {
142    /// Create an invalid model error with context
143    pub fn invalid_model<S: Into<String>>(msg: S) -> Self {
144        MnnError::InvalidModel(msg.into())
145    }
146
147    /// Create a session error with context
148    pub fn session_error<S: Into<String>>(msg: S) -> Self {
149        MnnError::SessionError(msg.into())
150    }
151
152    /// Create a tensor error with context
153    pub fn tensor_error<S: Into<String>>(msg: S) -> Self {
154        MnnError::TensorError(msg.into())
155    }
156
157    /// Create a backend error with context
158    pub fn backend_error<S: Into<String>>(msg: S) -> Self {
159        MnnError::BackendError(msg.into())
160    }
161
162    /// Create an unsupported error
163    pub fn unsupported<S: Into<String>>(msg: S) -> Self {
164        MnnError::Unsupported(msg.into())
165    }
166
167    /// Create an invalid input error
168    pub fn invalid_input<S: Into<String>>(msg: S) -> Self {
169        MnnError::InvalidInput(msg.into())
170    }
171
172    /// Create an internal error
173    pub fn internal<S: Into<String>>(msg: S) -> Self {
174        MnnError::Internal(msg.into())
175    }
176
177    /// Create a shape mismatch error
178    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    /// Create an out of memory error
186    pub fn out_of_memory<S: Into<String>>(msg: S) -> Self {
187        MnnError::OutOfMemory(msg.into())
188    }
189
190    /// Create an index out of bounds error
191    pub fn index_out_of_bounds(dim: usize, index: i32, size: i32) -> Self {
192        MnnError::IndexOutOfBounds { dim, index, size }
193    }
194
195    /// Create a backend not available error
196    pub fn backend_not_available<S: Into<String>>(backend: S) -> Self {
197        MnnError::BackendNotAvailable {
198            backend: backend.into(),
199        }
200    }
201
202    /// Check if this is an out of memory error
203    pub fn is_oom(&self) -> bool {
204        matches!(self, MnnError::OutOfMemory(_))
205    }
206
207    /// Check if this is a model error
208    pub fn is_model_error(&self) -> bool {
209        matches!(
210            self,
211            MnnError::InvalidModel(_) | MnnError::ModelNotFound(_)
212        )
213    }
214
215    /// Check if this is a backend error
216    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}