microgemm 0.3.1

General matrix multiplication with custom configuration in Rust. Supports no_std and no_alloc environments.
Documentation
use crate::{MatMut, MatRef, Zero};
use core::ops::Range;

pub(crate) struct ColMajor<V>(pub(crate) V);

impl<T> ColMajor<&[T]>
where
    T: Copy,
{
    pub fn copy_to(&self, mat: &mut MatMut<T>, rows: Range<usize>, cols: Range<usize>) {
        let buf = self.0;
        assert_eq!(buf.len(), rows.len() * cols.len());
        let mut it = buf.iter();

        for col in cols {
            for row in rows.start..rows.end {
                let src = it.next().unwrap();
                if row < mat.nrows() && col < mat.ncols() {
                    let dst = mat.get_mut(row, col);
                    *dst = *src;
                }
            }
        }
    }
}

impl<T> ColMajor<&mut [T]>
where
    T: Copy + Zero,
{
    pub fn init_from(&mut self, mat: MatRef<T>, rows: Range<usize>, cols: Range<usize>) {
        let buf = self.as_mut();
        assert_eq!(buf.len(), rows.len() * cols.len());
        let mut it = buf.iter_mut();

        for col in cols {
            for row in rows.start..rows.end {
                let dst = it.next().unwrap();
                *dst = mat.get_or_zero(row, col);
            }
        }
    }
}

impl<T> AsMut<[T]> for ColMajor<&mut [T]> {
    fn as_mut(&mut self) -> &mut [T] {
        self.0
    }
}

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

    #[rustfmt::skip]
    #[test]
    fn col_major_block_2x2() {
        let v = [
            1, 2,
            3, 4,
        ];
        let b = MatRef::row_major(2, 2, v.as_ref());

        let block = |rows: Range<usize>, cols: Range<usize>| {
            let mut buf = vec![-1; rows.len() * cols.len()];
            ColMajor(buf.as_mut_slice()).init_from(b, rows, cols);
            buf
        };

        assert_eq!(block(0..2, 0..2), [
            1, 3,
            2, 4,
        ]);

        assert_eq!(block(0..1, 0..1), [1]);
        assert_eq!(block(0..1, 1..2), [2]);
        assert_eq!(block(1..2, 0..1), [3]);
        assert_eq!(block(1..2, 1..2), [4]);

        assert_eq!(block(0..1, 0..3), [1, 2, 0]);
        assert_eq!(block(0..1, 0..4), [1, 2, 0, 0]);
        assert_eq!(block(0..1, 0..5), [1, 2, 0, 0, 0]);

        assert_eq!(block(1..2, 0..3), [3, 4, 0]);
        assert_eq!(block(1..2, 0..4), [3, 4, 0, 0]);
        assert_eq!(block(1..2, 0..5), [3, 4, 0, 0, 0]);

        assert_eq!(block(0..2, 0..1), [1, 3]);
        assert_eq!(block(0..3, 0..1), [1, 3, 0]);
        assert_eq!(block(0..4, 0..1), [1, 3, 0, 0]);
        assert_eq!(block(0..5, 0..1), [1, 3, 0, 0, 0]);

        assert_eq!(block(0..2, 1..2), [2, 4]);
        assert_eq!(block(0..3, 1..2), [2, 4, 0]);
        assert_eq!(block(0..4, 1..2), [2, 4, 0, 0]);
        assert_eq!(block(0..5, 1..2), [2, 4, 0, 0, 0]);

        assert_eq!(block(0..3, 0..3), [
            1, 3, 0,
            2, 4, 0,
            0, 0, 0,
        ]);

        assert_eq!(block(0..3, 0..4), [
            1, 3, 0,
            2, 4, 0,
            0, 0, 0,
            0, 0, 0,
        ]);

        assert_eq!(block(0..4, 0..4), [
            1, 3, 0, 0,
            2, 4, 0, 0,
            0, 0, 0, 0,
            0, 0, 0, 0,
        ]);

        assert_eq!(block(1..3, 0..3), [
            3, 0,
            4, 0,
            0, 0,
        ]);

        assert_eq!(block(1..3, 1..3), [
            4, 0,
            0, 0,
        ]);

        assert_eq!(block(0..3, 1..3), [
            2, 4, 0,
            0, 0, 0,
        ]);
    }
}