use crate::{DType, ShapeVec};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ValidationKind {
ShapeMismatch,
RankMismatch,
AxisOutOfBounds,
DTypeMismatch,
InvalidArgument,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ErrorKind {
Validation(ValidationKind),
Unsupported,
NumericalFailure,
BackendFailure,
Io,
RuntimeState,
Internal,
}
#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum ShapeMismatch {
#[error("incompatible shapes: lhs={lhs:?}, rhs={rhs:?}")]
IncompatibleShapes { lhs: ShapeVec, rhs: ShapeVec },
#[error("shape mismatch: expected={expected:?}, actual={actual:?}")]
ExpectedActual {
expected: ShapeVec,
actual: ShapeVec,
},
#[error("reshape element-count mismatch: from {from} to {to}")]
ReshapeElementCount { from: usize, to: usize },
#[error(
"contracted dimensions differ: lhs axis {lhs_axis} ({lhs_size}) vs rhs axis {rhs_axis} ({rhs_size})"
)]
ContractedDimensions {
lhs_axis: usize,
lhs_size: usize,
rhs_axis: usize,
rhs_size: usize,
},
}
#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum ValidationError {
#[error("{0}")]
ShapeMismatch(#[source] Box<ShapeMismatch>),
#[error("shape product {expected} does not match data length {actual}")]
ShapeDataLengthMismatch { expected: usize, actual: usize },
#[error("rank mismatch: expected {expected}, actual {actual}")]
RankMismatch { expected: usize, actual: usize },
#[error("axis {axis} out of bounds for rank {rank}")]
AxisOutOfBounds { axis: usize, rank: usize },
#[error("duplicate {role} axis {axis}")]
DuplicateAxis { axis: usize, role: &'static str },
#[error("axis {axis} appears in both {first_role} and {second_role}")]
AxisRoleConflict {
axis: usize,
first_role: &'static str,
second_role: &'static str,
},
#[error("invalid permutation length: expected {expected}, actual {actual}")]
InvalidPermutationLength { expected: usize, actual: usize },
#[error("invalid slice step {step}; zero is invalid")]
InvalidSliceStep { step: isize },
#[error("invalid slice bounds: start={start}, end={end}, axis_len={axis_len}")]
InvalidSliceBounds {
start: isize,
end: isize,
axis_len: usize,
},
#[error("dtype mismatch: expected {expected:?}, actual {actual:?}")]
DTypeMismatch { expected: DType, actual: DType },
#[error("invalid argument {argument}: {message}")]
InvalidArgument {
argument: &'static str,
message: String,
},
#[error("view is not slice-contiguous; materialize with to_contiguous before requesting a borrowed slice")]
NonContiguousViewAsSlice,
#[error("view metadata is out of borrowed-slice bounds")]
ViewOutOfBounds,
#[error("mutable tensor layout may overlap physical elements; materialize a contiguous owner before requesting mutable access")]
OverlappingMutableLayout,
#[error("integer overflow while validating tensor metadata")]
IntegerOverflow,
}
impl From<ShapeMismatch> for ValidationError {
fn from(error: ShapeMismatch) -> Self {
Self::ShapeMismatch(Box::new(error))
}
}
impl ValidationError {
pub fn kind(&self) -> ValidationKind {
match self {
Self::ShapeMismatch(_) | Self::ShapeDataLengthMismatch { .. } => {
ValidationKind::ShapeMismatch
}
Self::RankMismatch { .. } | Self::InvalidPermutationLength { .. } => {
ValidationKind::RankMismatch
}
Self::AxisOutOfBounds { .. } => ValidationKind::AxisOutOfBounds,
Self::DTypeMismatch { .. } => ValidationKind::DTypeMismatch,
_ => ValidationKind::InvalidArgument,
}
}
}