etensor-core 0.0.1

The pure Rust tensor math and autograd engine
Documentation
//! Unified error handling and boundary enforcement for ETensor.

/// The standard result type utilized across the entire ETensor engine.
///
/// By wrapping all backend and autograd operations in this Result, we guarantee
/// zero implicit panics, allowing graceful error handoffs to Python bindings.
pub type EtensorResult<T> = Result<T, EtensorError>;

/// Represents all possible failure states within the ETensor execution pipeline.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EtensorError {
    /// Raised when an operation receives tensors with fundamentally incompatible dimensional geometry.
    ShapeMismatch {
        expected: Vec<usize>,
        got: Vec<usize>,
    },

    /// Raised when mathematical operations are attempted across isolated memory spaces.
    /// (e.g., Attempting to add a CPU buffer directly to a CudaNative buffer).
    DeviceMismatch { expected: String, got: String },

    /// Raised when a kernel does not support the provided precision type.
    DTypeMismatch { expected: String, got: String },

    /// Raised when a failure occurs during Tape recording, topological sorting, or gradient accumulation.
    AutogradError(String),

    /// Raised when a hardware backend (CUDA driver, Torch C++, Rayon) fails an internal execution.
    BackendError(String),

    /// Raised during serialization or deserialization of model weights (e.g., Safetensors).
    IoError(String),

    /// A generic fallback for unclassified engine structural violations.
    InternalError(String),
}

impl std::fmt::Display for EtensorError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            EtensorError::ShapeMismatch { expected, got } => {
                write!(
                    f,
                    "ShapeMismatch: Operation expected shape {:?}, but got {:?}",
                    expected, got
                )
            }
            EtensorError::DeviceMismatch { expected, got } => {
                write!(
                    f,
                    "DeviceMismatch: Operation expected tensors on '{}', but found tensor on '{}'",
                    expected, got
                )
            }
            EtensorError::DTypeMismatch { expected, got } => {
                write!(
                    f,
                    "DTypeMismatch: Operation expected dtype '{}', but found '{}'",
                    expected, got
                )
            }
            EtensorError::AutogradError(msg) => write!(f, "AutogradError: {}", msg),
            EtensorError::BackendError(msg) => write!(f, "BackendError: {}", msg),
            EtensorError::IoError(msg) => write!(f, "IoError: {}", msg),
            EtensorError::InternalError(msg) => write!(f, "InternalError: {}", msg),
        }
    }
}

// Implements the standard Rust Error trait, allowing seamless integration with
// standard library traits (like `?` propagation and `Box<dyn Error>`).
impl std::error::Error for EtensorError {}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_shape_mismatch_formatting() {
        let err = EtensorError::ShapeMismatch {
            expected: vec![2, 3],
            got: vec![3, 2],
        };
        assert_eq!(
            err.to_string(),
            "ShapeMismatch: Operation expected shape [2, 3], but got [3, 2]"
        );
    }

    #[test]
    fn test_device_mismatch_formatting() {
        let err = EtensorError::DeviceMismatch {
            expected: "cuda:0".to_string(),
            got: "cpu".to_string(),
        };
        assert_eq!(
            err.to_string(),
            "DeviceMismatch: Operation expected tensors on 'cuda:0', but found tensor on 'cpu'"
        );
    }

    #[test]
    fn test_result_propagation() {
        // A simple dummy function to test the EtensorResult alias
        fn mock_add(a_is_cpu: bool, b_is_cpu: bool) -> EtensorResult<f32> {
            if a_is_cpu != b_is_cpu {
                return Err(EtensorError::DeviceMismatch {
                    expected: "cpu".to_string(),
                    got: "cuda".to_string(),
                });
            }
            Ok(42.0)
        }

        assert!(mock_add(true, true).is_ok());

        let err = mock_add(true, false).unwrap_err();
        assert!(matches!(err, EtensorError::DeviceMismatch { .. }));
    }
}