use std::error::Error as StdError;
use tenferro_tensor_core::{ErrorKind, ValidationError};
pub type BoxError = Box<dyn StdError + Send + Sync + 'static>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("{op}: {source}")]
Validation {
op: &'static str,
#[source]
source: ValidationError,
},
#[error("{op}: unsupported dtype conversion from {from:?} to {to:?}: {message}")]
UnsupportedDTypeConversion {
op: &'static str,
from: crate::DType,
to: crate::DType,
message: String,
},
#[error("{op}: unsupported dtype {dtype:?}: {message}")]
UnsupportedDType {
op: &'static str,
dtype: crate::DType,
message: String,
},
#[error("{op}: unsupported operation: {message}")]
Unsupported { op: &'static str, message: String },
#[error("{op}: backend failure: {message}")]
BackendFailure { op: &'static str, message: String },
#[error("{op}: backend failure: {source}")]
BackendSource {
op: &'static str,
#[source]
source: BoxError,
},
#[error("{op}: I/O failure: {source}")]
IoSource {
op: &'static str,
#[source]
source: BoxError,
},
#[error("{op}: runtime state failure: {message}")]
RuntimeState { op: &'static str, message: String },
#[error("{op}: runtime state failure: {source}")]
RuntimeStateSource {
op: &'static str,
#[source]
source: BoxError,
},
#[error("{op}: host access failed: {source}")]
HostAccess {
op: &'static str,
#[source]
source: crate::HostAccessError,
},
#[error("{op}: extension {family} failed: {source}")]
Extension {
op: &'static str,
family: &'static str,
kind: ErrorKind,
#[source]
source: BoxError,
},
#[error("missing runtime value for slot {slot}")]
MissingValue { slot: usize },
#[error("internal tensor error: {0}")]
Internal(String),
}
#[derive(Debug)]
pub struct ReinterpretError<T> {
owner: Box<T>,
error: Error,
}
impl<T> ReinterpretError<T> {
pub(crate) fn new(owner: T, error: Error) -> Self {
Self {
owner: Box::new(owner),
error,
}
}
pub fn into_owner(self) -> T {
*self.owner
}
pub fn error(&self) -> &Error {
&self.error
}
pub(crate) fn into_parts(self) -> (T, Error) {
(*self.owner, self.error)
}
}
impl<T: std::fmt::Debug> std::fmt::Display for ReinterpretError<T> {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(formatter, "tensor reinterpretation failed: {}", self.error)
}
}
impl<T: std::fmt::Debug + 'static> std::error::Error for ReinterpretError<T> {}
impl Error {
pub fn shape_mismatch(
op: &'static str,
lhs: impl Into<Vec<usize>>,
rhs: impl Into<Vec<usize>>,
) -> Self {
Self::validation(
op,
tenferro_tensor_core::ShapeMismatch::IncompatibleShapes {
lhs: tenferro_tensor_core::ShapeVec::from_vec(lhs.into()),
rhs: tenferro_tensor_core::ShapeVec::from_vec(rhs.into()),
}
.into(),
)
}
pub fn rank_mismatch(op: &'static str, expected: usize, actual: usize) -> Self {
Self::validation(op, ValidationError::RankMismatch { expected, actual })
}
pub fn axis_out_of_bounds(op: &'static str, axis: usize, rank: usize) -> Self {
Self::validation(op, ValidationError::AxisOutOfBounds { axis, rank })
}
pub fn duplicate_axis(op: &'static str, axis: usize, role: &'static str) -> Self {
Self::validation(op, ValidationError::DuplicateAxis { axis, role })
}
pub fn dtype_mismatch(op: &'static str, expected: crate::DType, actual: crate::DType) -> Self {
Self::validation(
op,
ValidationError::DTypeMismatch {
expected: crate::core_dtype(expected),
actual: crate::core_dtype(actual),
},
)
}
pub fn validation(op: &'static str, source: ValidationError) -> Self {
Self::Validation { op, source }
}
pub fn invalid_argument(
op: &'static str,
argument: &'static str,
message: impl Into<String>,
) -> Self {
Self::validation(
op,
ValidationError::InvalidArgument {
argument,
message: message.into(),
},
)
}
pub fn unsupported_dtype_conversion(
op: &'static str,
from: crate::DType,
to: crate::DType,
message: impl Into<String>,
) -> Self {
Self::UnsupportedDTypeConversion {
op,
from,
to,
message: message.into(),
}
}
pub fn unsupported_dtype(
op: &'static str,
dtype: crate::DType,
message: impl Into<String>,
) -> Self {
Self::UnsupportedDType {
op,
dtype,
message: message.into(),
}
}
pub fn unsupported(op: &'static str, message: impl Into<String>) -> Self {
Self::Unsupported {
op,
message: message.into(),
}
}
pub fn backend_failure(op: &'static str, message: impl Into<String>) -> Self {
Self::BackendFailure {
op,
message: message.into(),
}
}
pub fn backend_source<E>(op: &'static str, source: E) -> Self
where
E: StdError + Send + Sync + 'static,
{
Self::BackendSource {
op,
source: Box::new(source),
}
}
pub fn io_source<E>(op: &'static str, source: E) -> Self
where
E: StdError + Send + Sync + 'static,
{
Self::IoSource {
op,
source: Box::new(source),
}
}
pub fn runtime_state(op: &'static str, message: impl Into<String>) -> Self {
Self::RuntimeState {
op,
message: message.into(),
}
}
pub fn runtime_state_source<E>(op: &'static str, source: E) -> Self
where
E: StdError + Send + Sync + 'static,
{
Self::RuntimeStateSource {
op,
source: Box::new(source),
}
}
pub fn extension<E>(op: &'static str, family: &'static str, kind: ErrorKind, source: E) -> Self
where
E: StdError + Send + Sync + 'static,
{
Self::Extension {
op,
family,
kind,
source: Box::new(source),
}
}
pub fn host_access(op: &'static str, source: crate::HostAccessError) -> Self {
Self::HostAccess { op, source }
}
pub fn kind(&self) -> ErrorKind {
match self {
Self::Validation { source, .. } => ErrorKind::Validation(source.kind()),
Self::UnsupportedDTypeConversion { .. }
| Self::UnsupportedDType { .. }
| Self::Unsupported { .. } => ErrorKind::Unsupported,
Self::BackendFailure { .. } | Self::BackendSource { .. } => ErrorKind::BackendFailure,
Self::IoSource { .. } => ErrorKind::Io,
Self::RuntimeState { .. }
| Self::RuntimeStateSource { .. }
| Self::HostAccess { .. } => ErrorKind::RuntimeState,
Self::Extension { kind, .. } => *kind,
Self::MissingValue { .. } => ErrorKind::RuntimeState,
Self::Internal(_) => ErrorKind::Internal,
}
}
}
pub type Result<T> = std::result::Result<T, Error>;