tenferro_tensor_core/
error.rs1use crate::{DType, ShapeVec};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
17#[non_exhaustive]
18pub enum ValidationKind {
19 ShapeMismatch,
20 RankMismatch,
21 AxisOutOfBounds,
22 DTypeMismatch,
23 InvalidArgument,
24}
25
26#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
39#[non_exhaustive]
40pub enum ErrorKind {
41 Validation(ValidationKind),
42 Unsupported,
43 NumericalFailure,
44 BackendFailure,
45 Io,
46 RuntimeState,
47 Internal,
48}
49
50#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
64#[non_exhaustive]
65pub enum ShapeMismatch {
66 #[error("incompatible shapes: lhs={lhs:?}, rhs={rhs:?}")]
67 IncompatibleShapes { lhs: ShapeVec, rhs: ShapeVec },
68 #[error("shape mismatch: expected={expected:?}, actual={actual:?}")]
69 ExpectedActual {
70 expected: ShapeVec,
71 actual: ShapeVec,
72 },
73 #[error("reshape element-count mismatch: from {from} to {to}")]
74 ReshapeElementCount { from: usize, to: usize },
75 #[error(
76 "contracted dimensions differ: lhs axis {lhs_axis} ({lhs_size}) vs rhs axis {rhs_axis} ({rhs_size})"
77 )]
78 ContractedDimensions {
79 lhs_axis: usize,
80 lhs_size: usize,
81 rhs_axis: usize,
82 rhs_size: usize,
83 },
84}
85
86#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
101#[non_exhaustive]
102pub enum ValidationError {
103 #[error("{0}")]
104 ShapeMismatch(#[source] Box<ShapeMismatch>),
105 #[error("shape product {expected} does not match data length {actual}")]
106 ShapeDataLengthMismatch { expected: usize, actual: usize },
107 #[error("rank mismatch: expected {expected}, actual {actual}")]
108 RankMismatch { expected: usize, actual: usize },
109 #[error("axis {axis} out of bounds for rank {rank}")]
110 AxisOutOfBounds { axis: usize, rank: usize },
111 #[error("duplicate {role} axis {axis}")]
112 DuplicateAxis { axis: usize, role: &'static str },
113 #[error("axis {axis} appears in both {first_role} and {second_role}")]
114 AxisRoleConflict {
115 axis: usize,
116 first_role: &'static str,
117 second_role: &'static str,
118 },
119 #[error("invalid permutation length: expected {expected}, actual {actual}")]
120 InvalidPermutationLength { expected: usize, actual: usize },
121 #[error("invalid slice step {step}; zero is invalid")]
122 InvalidSliceStep { step: isize },
123 #[error("invalid slice bounds: start={start}, end={end}, axis_len={axis_len}")]
124 InvalidSliceBounds {
125 start: isize,
126 end: isize,
127 axis_len: usize,
128 },
129 #[error("dtype mismatch: expected {expected:?}, actual {actual:?}")]
130 DTypeMismatch { expected: DType, actual: DType },
131 #[error("invalid argument {argument}: {message}")]
132 InvalidArgument {
133 argument: &'static str,
134 message: String,
135 },
136 #[error("view is not slice-contiguous")]
137 NonContiguousViewAsSlice,
138 #[error("view metadata is out of borrowed-slice bounds")]
139 ViewOutOfBounds,
140 #[error("mutable tensor layout may overlap physical elements")]
141 OverlappingMutableLayout,
142 #[error("integer overflow while validating tensor metadata")]
143 IntegerOverflow,
144}
145
146impl From<ShapeMismatch> for ValidationError {
147 fn from(error: ShapeMismatch) -> Self {
148 Self::ShapeMismatch(Box::new(error))
149 }
150}
151
152impl ValidationError {
153 pub fn kind(&self) -> ValidationKind {
164 match self {
165 Self::ShapeMismatch(_) | Self::ShapeDataLengthMismatch { .. } => {
166 ValidationKind::ShapeMismatch
167 }
168 Self::RankMismatch { .. } | Self::InvalidPermutationLength { .. } => {
169 ValidationKind::RankMismatch
170 }
171 Self::AxisOutOfBounds { .. } => ValidationKind::AxisOutOfBounds,
172 Self::DTypeMismatch { .. } => ValidationKind::DTypeMismatch,
173 _ => ValidationKind::InvalidArgument,
174 }
175 }
176}