leto 0.41.0

N-dimensional strided arrays, zero-copy views, and storage backends
Documentation
use leto::{Layout, LetoError};

#[test]
fn test_c_contiguous_layout() {
    let layout = Layout::c_contiguous([2, 3, 4]).unwrap();
    assert_eq!(layout.shape, [2, 3, 4]);
    assert_eq!(layout.strides, [12, 4, 1]);
    assert_eq!(layout.offset, 0);
    assert_eq!(layout.size(), 24);
    assert!(layout.is_c_contiguous());
    assert!(!layout.is_f_contiguous());

    let (min_off, max_off) = layout.min_max_offsets();
    assert_eq!(min_off, 0);
    assert_eq!(max_off, 23);
}

#[test]
fn test_f_contiguous_layout() {
    let layout = Layout::f_contiguous([2, 3, 4]).unwrap();
    assert_eq!(layout.shape, [2, 3, 4]);
    assert_eq!(layout.strides, [1, 2, 6]);
    assert_eq!(layout.offset, 0);
    assert_eq!(layout.size(), 24);
    assert!(!layout.is_c_contiguous());
    assert!(layout.is_f_contiguous());

    let (min_off, max_off) = layout.min_max_offsets();
    assert_eq!(min_off, 0);
    assert_eq!(max_off, 23);
}

#[test]
fn test_offset_calculation() {
    let layout = Layout::c_contiguous([2, 3]).unwrap();
    assert_eq!(layout.offset_of([0, 0]).unwrap(), 0);
    assert_eq!(layout.offset_of([0, 1]).unwrap(), 1);
    assert_eq!(layout.offset_of([1, 0]).unwrap(), 3);
    assert_eq!(layout.offset_of([1, 2]).unwrap(), 5);

    assert!(matches!(
        layout.offset_of([2, 0]),
        Err(LetoError::OutOfBounds { .. })
    ));
}

#[test]
fn test_negative_stride_offsets_are_checked_before_unsigned_conversion() {
    let layout = Layout::new([3], [-1], 2);

    assert_eq!(layout.checked_min_max_offsets().unwrap(), (0, 2));
    assert_eq!(layout.offset_of([0]).unwrap(), 2);
    assert_eq!(layout.offset_of([2]).unwrap(), 0);

    let invalid = Layout::new([3], [-1], 0);
    assert!(matches!(
        invalid.checked_min_max_offsets(),
        Err(LetoError::StorageError { .. })
    ));
    assert!(matches!(
        invalid.offset_of([1]),
        Err(LetoError::StorageError { .. })
    ));
}

#[test]
fn test_array_rejects_layout_that_reaches_one_past_storage() {
    use leto::{Array, VecStorage};
    let layout = Layout::new([2], [1], 1);
    let storage = VecStorage::new(vec![10, 20]);

    assert!(matches!(
        Array::new(layout, storage),
        Err(LetoError::StorageError { .. })
    ));
}