mermaid 0.1.0

Experimental Linear Algebra
Documentation
pub mod iter;
pub mod ops;

use crate::error::{Error, Result};
use iter::{ColIter, RowIter};
use std::fmt::{self, Display, Formatter};

#[derive(Debug, Clone)]
pub struct Matrix<T, const M: usize, const N: usize>(Vec<T>);

impl<T, const M: usize, const N: usize> Matrix<T, M, N> {
    pub fn new(entries: Vec<T>) -> Result<Self> {
        if entries.len() != M * N {
            return Err(Error::WrongEntriesLength {
                rows: M,
                cols: N,
                len: entries.len(),
            });
        }

        Ok(Self(entries))
    }

    pub const fn is_empty(&self) -> bool {
        M == 0 || N == 0
    }

    pub const fn is_row(&self) -> bool {
        M == 1
    }

    pub const fn is_col(&self) -> bool {
        N == 1
    }

    pub const fn is_square(&self) -> bool {
        M == N
    }

    pub fn get(&self, i: usize, j: usize) -> Option<&T> {
        self.0.get(N * i + j)
    }

    pub fn row_iter(&self, i: usize) -> Option<RowIter<T, M, N>> {
        (i < M).then_some(RowIter::new(self, i))
    }

    pub fn col_iter(&self, j: usize) -> Option<ColIter<T, M, N>> {
        (j < N).then_some(ColIter::new(self, j))
    }
}

impl<T, const M: usize, const N: usize> Display for Matrix<T, M, N>
where
    T: Display,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let entries: Vec<_> = self.0.iter().map(|entry| entry.to_string()).collect();
        let Some(longest) = entries.iter().map(|entry| entry.len()).max() else {
            return write!(f, "||");
        };

        for i in 0..M {
            write!(
                f,
                "|{}|",
                &entries[N * i..N * (i + 1)]
                    .iter()
                    .fold(String::new(), |acc, entry| {
                        acc + &format!("{: ^longest$}", entry, longest = longest + 2)
                    })
            )?;

            if i < M - 1 {
                writeln!(f)?;
            }
        }

        Ok(())
    }
}

impl<T, const M: usize, const N: usize> Eq for Matrix<T, M, N> where T: Eq {}

impl<T, const M: usize, const N: usize> PartialEq for Matrix<T, M, N>
where
    T: PartialEq,
{
    fn eq(&self, other: &Self) -> bool {
        self.0.iter().zip(other.0.iter()).all(|(a, b)| a == b)
    }
}

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

    #[test]
    #[should_panic = "entry array of size `2` does not match matrix of size `2x3`"]
    fn instantiation() {
        if let Err(err) = Matrix::<_, 2, 3>::new(vec![0u32, 2]) {
            panic!("{}", err);
        }
    }
}