tenferro_tensor/error.rs
1//! Runtime error types for tensor execution.
2//!
3//! # Examples
4//!
5//! ```rust
6//! use tenferro_tensor::Error;
7//!
8//! let err = Error::AxisOutOfBounds {
9//! op: "dot_general",
10//! axis: 2,
11//! rank: 1,
12//! };
13//! assert!(err.to_string().contains("dot_general"));
14//! ```
15
16/// Runtime failures produced by tensor execution backends and helpers.
17///
18/// # Examples
19///
20/// ```rust
21/// use tenferro_tensor::Error;
22///
23/// let err = Error::MissingValue { slot: 3 };
24/// ```
25#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
26pub enum Error {
27 #[error("{op}: axis {axis} out of bounds for rank {rank}")]
28 AxisOutOfBounds {
29 op: &'static str,
30 axis: usize,
31 rank: usize,
32 },
33 #[error("{op}: duplicate {role} axis {axis}")]
34 DuplicateAxis {
35 op: &'static str,
36 axis: usize,
37 role: &'static str,
38 },
39 #[error("{op}: axis {axis} appears in both {first_role} and {second_role}")]
40 AxisRoleConflict {
41 op: &'static str,
42 axis: usize,
43 first_role: &'static str,
44 second_role: &'static str,
45 },
46 #[error("{op}: shape mismatch lhs={lhs:?} rhs={rhs:?}")]
47 ShapeMismatch {
48 op: &'static str,
49 lhs: Vec<usize>,
50 rhs: Vec<usize>,
51 },
52 #[error("{op}: rank mismatch expected {expected}, actual {actual}")]
53 RankMismatch {
54 op: &'static str,
55 expected: usize,
56 actual: usize,
57 },
58 #[error("{op}: dtype mismatch lhs={lhs:?} rhs={rhs:?}")]
59 DTypeMismatch {
60 op: &'static str,
61 lhs: crate::DType,
62 rhs: crate::DType,
63 },
64 #[error("{op}: unsupported dtype conversion from {from:?} to {to:?}: {message}")]
65 UnsupportedDTypeConversion {
66 op: &'static str,
67 from: crate::DType,
68 to: crate::DType,
69 message: String,
70 },
71 #[error("{backend} backend does not support {op} for dtype {dtype:?}")]
72 UnsupportedOpDType {
73 op: &'static str,
74 dtype: crate::DType,
75 backend: crate::BackendId,
76 },
77 #[error("{op}: division by zero for dtype {dtype:?}")]
78 DivisionByZero {
79 op: &'static str,
80 dtype: crate::DType,
81 },
82 #[error("{op}: negative integer exponent for dtype {dtype:?}")]
83 NegativeIntegerExponent {
84 op: &'static str,
85 dtype: crate::DType,
86 },
87 #[error("{op}: invalid config: {message}")]
88 InvalidConfig { op: &'static str, message: String },
89 #[error("extension family {family_id:?} has no host reference implementation")]
90 NoHostReference { family_id: &'static str },
91 #[error("{op}: backend failure: {message}")]
92 BackendFailure { op: &'static str, message: String },
93 #[error("missing runtime value for slot {slot}")]
94 MissingValue { slot: usize },
95}
96
97impl Error {
98 /// Construct a backend failure error while preserving the operation name.
99 ///
100 /// # Examples
101 ///
102 /// ```rust
103 /// use tenferro_tensor::Error;
104 ///
105 /// let err = Error::backend_failure("matmul", "backend rejected launch");
106 /// assert!(matches!(
107 /// err,
108 /// Error::BackendFailure {
109 /// op: "matmul",
110 /// ref message,
111 /// } if message == "backend rejected launch"
112 /// ));
113 /// ```
114 pub fn backend_failure(op: &'static str, message: impl std::fmt::Display) -> Self {
115 Self::BackendFailure {
116 op,
117 message: message.to_string(),
118 }
119 }
120
121 /// Construct a structured unsupported operation/dtype error.
122 ///
123 /// # Examples
124 ///
125 /// ```rust
126 /// use tenferro_tensor::{BackendId, DType, Error};
127 ///
128 /// let err = Error::unsupported_op_dtype("add", DType::Bool, BackendId::Cuda);
129 /// assert!(matches!(err, Error::UnsupportedOpDType { backend: BackendId::Cuda, .. }));
130 /// ```
131 pub fn unsupported_op_dtype(
132 op: &'static str,
133 dtype: crate::DType,
134 backend: crate::BackendId,
135 ) -> Self {
136 Self::UnsupportedOpDType { op, dtype, backend }
137 }
138
139 /// Construct a structured division-by-zero domain error.
140 ///
141 /// # Examples
142 ///
143 /// ```rust
144 /// use tenferro_tensor::{DType, Error};
145 ///
146 /// let err = Error::division_by_zero("div", DType::I32);
147 /// assert!(matches!(err, Error::DivisionByZero { op: "div", .. }));
148 /// ```
149 pub fn division_by_zero(op: &'static str, dtype: crate::DType) -> Self {
150 Self::DivisionByZero { op, dtype }
151 }
152
153 /// Construct a structured negative-integer-exponent domain error.
154 ///
155 /// # Examples
156 ///
157 /// ```rust
158 /// use tenferro_tensor::{DType, Error};
159 ///
160 /// let err = Error::negative_integer_exponent("pow", DType::I64);
161 /// assert!(matches!(err, Error::NegativeIntegerExponent { op: "pow", .. }));
162 /// ```
163 pub fn negative_integer_exponent(op: &'static str, dtype: crate::DType) -> Self {
164 Self::NegativeIntegerExponent { op, dtype }
165 }
166}
167
168/// Result type alias for runtime tensor operations.
169///
170/// # Examples
171///
172/// ```rust
173/// use tenferro_tensor::{Error, Result};
174///
175/// let output: Result<()> = Err(Error::MissingValue { slot: 0 });
176/// ```
177pub type Result<T> = std::result::Result<T, Error>;