tenferro-tensor 0.3.0

Dense runtime tensors, views, backend traits, and backend-independent contracts for tenferro.
Documentation
use num_complex::Complex64;

use crate::{BackendId, DType, Error, Tensor, TensorRead, TensorScalar, TypedTensor};

fn dtype_of_typed<T: crate::TensorScalar>(_: &TypedTensor<T>) -> DType {
    T::dtype()
}

fn dtype_of_view<T: crate::TensorScalar>(_: &crate::TypedTensorView<'_, T>) -> DType {
    T::dtype()
}

#[test]
fn with_scalar_dispatches_allowed_float_complex_tensors() {
    let tensor = Tensor::from_vec_col_major(
        vec![2],
        vec![Complex64::new(1.0, 2.0), Complex64::new(3.0, 4.0)],
    )
    .unwrap();

    let dtype = crate::with_scalar!(
        &tensor,
        float_complex,
        backend = BackendId::Cpu,
        op = "dtype_probe",
        |typed| -> crate::Result<DType> { Ok(dtype_of_typed(typed)) }
    )
    .unwrap();

    assert_eq!(dtype, DType::C64);
}

#[test]
fn with_scalar_rejects_dtype_outside_guard_with_structured_error() {
    let tensor = Tensor::from_vec_col_major(vec![1], vec![7_i32]).unwrap();
    let err = crate::with_scalar!(
        &tensor,
        float_only,
        backend = BackendId::Cuda,
        op = "dtype_probe",
        |typed| -> crate::Result<DType> { Ok(dtype_of_typed(typed)) }
    )
    .unwrap_err();

    assert!(matches!(
        err,
        Error::UnsupportedDType {
            op: "dtype_probe",
            dtype: DType::I32,
            ..
        }
    ));
}

#[test]
fn with_scalar_read_dispatches_tensor_reads_and_views() {
    let tensor = Tensor::from_vec_col_major(vec![2], vec![1.0_f32, 2.0]).unwrap();
    let read = TensorRead::from_tensor(&tensor);
    let dtype = crate::with_scalar_read!(
        read,
        float_only,
        backend = BackendId::Cpu,
        op = "read_probe",
        |view| -> crate::Result<DType> { Ok(dtype_of_view(&view)) }
    )
    .unwrap();

    assert_eq!(dtype, DType::F32);

    let typed = TypedTensor::<f32>::from_vec_col_major(vec![2], vec![1.0, 2.0]).unwrap();
    let read = TensorRead::from_view(f32::tensor_view(typed.as_view()));
    let dtype = crate::with_scalar_read!(
        read,
        float_only,
        backend = BackendId::Cpu,
        op = "read_probe",
        |view| -> crate::Result<DType> { Ok(dtype_of_view(&view)) }
    )
    .unwrap();

    assert_eq!(dtype, DType::F32);
}