Skip to main content

axonml_core/
error.rs

1//! Error Types - Axonml Core Error Handling
2//!
3//! # File
4//! `crates/axonml-core/src/error.rs`
5//!
6//! # Author
7//! Andrew Jewell Sr - AutomataNexus
8//!
9//! # Updated
10//! March 8, 2026
11//!
12//! # Disclaimer
13//! Use at own risk. This software is provided "as is", without warranty of any
14//! kind, express or implied. The author and AutomataNexus shall not be held
15//! liable for any damages arising from the use of this software.
16
17use thiserror::Error;
18
19use crate::device::Device;
20use crate::dtype::DType;
21
22// =============================================================================
23// Error Types
24// =============================================================================
25
26/// The main error type for Axonml operations.
27#[derive(Error, Debug, Clone, PartialEq)]
28pub enum Error {
29    /// Shape mismatch between tensors.
30    #[error("Shape mismatch: expected {expected:?}, got {actual:?}")]
31    ShapeMismatch {
32        /// The expected shape.
33        expected: Vec<usize>,
34        /// The actual shape.
35        actual: Vec<usize>,
36    },
37
38    /// Data type mismatch between tensors.
39    #[error("DType mismatch: expected {expected:?}, got {actual:?}")]
40    DTypeMismatch {
41        /// The expected data type.
42        expected: DType,
43        /// The actual data type.
44        actual: DType,
45    },
46
47    /// Device mismatch between tensors.
48    #[error("Device mismatch: expected {expected:?}, got {actual:?}")]
49    DeviceMismatch {
50        /// The expected device.
51        expected: Device,
52        /// The actual device.
53        actual: Device,
54    },
55
56    /// Invalid dimension index.
57    #[error("Invalid dimension: index {index} for tensor with {ndim} dimensions")]
58    InvalidDimension {
59        /// The invalid dimension index.
60        index: i64,
61        /// Number of dimensions in the tensor.
62        ndim: usize,
63    },
64
65    /// Index out of bounds.
66    #[error("Index out of bounds: index {index} for dimension of size {size}")]
67    IndexOutOfBounds {
68        /// The invalid index.
69        index: usize,
70        /// The size of the dimension.
71        size: usize,
72    },
73
74    /// Memory allocation failed.
75    #[error("Memory allocation failed: requested {size} bytes on {device:?}")]
76    AllocationFailed {
77        /// The requested size in bytes.
78        size: usize,
79        /// The device on which allocation failed.
80        device: Device,
81    },
82
83    /// Device not available.
84    #[error("Device not available: {device:?}")]
85    DeviceNotAvailable {
86        /// The unavailable device.
87        device: Device,
88    },
89
90    /// Invalid operation for the given tensor.
91    #[error("Invalid operation: {message}")]
92    InvalidOperation {
93        /// Description of why the operation is invalid.
94        message: String,
95    },
96
97    /// Broadcasting failed between shapes.
98    #[error("Cannot broadcast shapes {shape1:?} and {shape2:?}")]
99    BroadcastError {
100        /// The first shape.
101        shape1: Vec<usize>,
102        /// The second shape.
103        shape2: Vec<usize>,
104    },
105
106    /// Empty tensor error.
107    #[error("Operation not supported on empty tensor")]
108    EmptyTensor,
109
110    /// Contiguous tensor required.
111    #[error("Operation requires contiguous tensor")]
112    NotContiguous,
113
114    /// Gradient computation error.
115    #[error("Gradient error: {message}")]
116    GradientError {
117        /// Description of the gradient error.
118        message: String,
119    },
120
121    /// Serialization/deserialization error.
122    #[error("Serialization error: {message}")]
123    SerializationError {
124        /// Description of the serialization error.
125        message: String,
126    },
127
128    /// Internal error (should not happen).
129    #[error("Internal error: {message}")]
130    InternalError {
131        /// Description of the internal error.
132        message: String,
133    },
134}
135
136// =============================================================================
137// Result Type
138// =============================================================================
139
140/// A specialized Result type for Axonml operations.
141pub type Result<T> = core::result::Result<T, Error>;
142
143// =============================================================================
144// Helper Functions
145// =============================================================================
146
147impl Error {
148    /// Creates a new shape mismatch error.
149    #[must_use]
150    pub fn shape_mismatch(expected: &[usize], actual: &[usize]) -> Self {
151        Self::ShapeMismatch {
152            expected: expected.to_vec(),
153            actual: actual.to_vec(),
154        }
155    }
156
157    /// Creates a new invalid operation error.
158    #[must_use]
159    pub fn invalid_operation(message: impl Into<String>) -> Self {
160        Self::InvalidOperation {
161            message: message.into(),
162        }
163    }
164
165    /// Creates a new internal error.
166    #[must_use]
167    pub fn internal(message: impl Into<String>) -> Self {
168        Self::InternalError {
169            message: message.into(),
170        }
171    }
172}
173
174// =============================================================================
175// Tests
176// =============================================================================
177
178#[cfg(test)]
179mod tests {
180    use super::*;
181
182    #[test]
183    fn test_error_display() {
184        let err = Error::shape_mismatch(&[2, 3], &[2, 4]);
185        assert!(err.to_string().contains("Shape mismatch"));
186    }
187
188    #[test]
189    fn test_error_equality() {
190        let err1 = Error::EmptyTensor;
191        let err2 = Error::EmptyTensor;
192        assert_eq!(err1, err2);
193    }
194}