Skip to main content

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>;