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}