griddy 0.1.2

A simple implementation of a general-purpose grid/matrix
Documentation
use std::{
    iter::StepBy,
    slice::{Iter, IterMut},
};

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Grid<T> {
    width: usize,
    height: usize,
    data: Vec<T>,
}

impl<T> Grid<T> {
    pub fn new(width: usize, height: usize) -> Self
    where
        T: Default,
    {
        let mut data = Vec::with_capacity(width * height);
        data.resize_with(width * height, T::default);

        Self {
            width,
            height,
            data,
        }
    }

    pub fn init(width: usize, height: usize, value: T) -> Self
    where
        T: Clone,
    {
        Self {
            width,
            height,
            data: vec![value; width * height],
        }
    }

    pub fn from_vec(vec: Vec<T>, width: usize) -> Self {
        assert_eq!(vec.len() % width, 0);

        Self {
            width,
            height: vec.len() / width,
            data: vec,
        }
    }

    pub unsafe fn get_unchecked(&self, x: usize, y: usize) -> &T {
        self.data.get_unchecked(x + y * self.width)
    }

    pub unsafe fn get_unchecked_mut(&mut self, x: usize, y: usize) -> &mut T {
        self.data.get_unchecked_mut(x + y * self.width)
    }

    pub fn get(&self, x: usize, y: usize) -> Option<&T> {
        self.data.get(x + y * self.width)
    }

    pub fn get_mut(&mut self, x: usize, y: usize) -> Option<&mut T> {
        self.data.get_mut(x + y * self.width)
    }

    pub fn size(&self) -> (usize, usize) {
        (self.width, self.height)
    }

    pub fn width(&self) -> usize {
        self.width
    }

    pub fn height(&self) -> usize {
        self.height
    }

    pub fn rows(&self) -> usize {
        self.height
    }

    pub fn cols(&self) -> usize {
        self.width
    }

    pub fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    pub fn clear(&mut self) {
        self.width = 0;
        self.height = 0;
        self.data.clear();
    }

    pub fn iter(&self) -> Iter<T> {
        self.data.iter()
    }

    pub fn iter_mut(&mut self) -> IterMut<T> {
        self.data.iter_mut()
    }

    pub fn iter_col(&self, col: usize) -> StepBy<Iter<T>> {
        self.data[col..].iter().step_by(self.width)
    }

    pub fn iter_col_mut(&mut self, col: usize) -> StepBy<IterMut<T>> {
        self.data[col..].iter_mut().step_by(self.width)
    }

    pub fn iter_row(&self, row: usize) -> Iter<T> {
        let start = row * self.width;
        self.data[start..(start + self.width)].iter()
    }

    pub fn iter_row_mut(&mut self, row: usize) -> IterMut<T> {
        let start = row * self.width;
        self.data[start..(start + self.width)].iter_mut()
    }

    pub fn flatten(&self) -> &Vec<T> {
        &self.data
    }

    pub fn into_vec(self) -> Vec<T> {
        self.data
    }

    pub fn fill(&mut self, value: T)
    where
        T: Clone,
    {
        self.data.fill(value);
    }

    pub fn fill_with(&mut self, func: impl FnMut() -> T) {
        self.data.fill_with(func);
    }

    pub fn map<U>(self, func: impl FnMut(T) -> U) -> Grid<U> {
        Grid {
            width: self.width,
            height: self.height,
            data: self.data.into_iter().map(func).collect(),
        }
    }
}

impl<T> Grid<Option<T>> {
    pub fn or(self, other: Self) -> Self {
        assert_eq!(self.width, other.width);
        assert_eq!(self.height, other.height);

        Self {
            width: self.width,
            height: self.height,
            data: self
                .into_vec()
                .into_iter()
                .zip(other.into_vec().into_iter())
                .map(|(a, b)| a.or(b))
                .collect(),
        }
    }

    pub fn and_then<U>(self, f: impl FnOnce(T) -> Option<U> + Clone) -> Grid<Option<U>> {
        Grid {
            width: self.width,
            height: self.height,
            data: self
                .into_vec()
                .into_iter()
                .map(|a| a.and_then(f.clone()))
                .collect(),
        }
    }

    pub fn option_map<U>(self, f: impl FnOnce(T) -> U + Clone) -> Grid<Option<U>> {
        Grid {
            width: self.width,
            height: self.height,
            data: self
                .into_vec()
                .into_iter()
                .map(|a| a.map(f.clone()))
                .collect(),
        }
    }
}

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

    #[test]
    fn and_then_works() {
        let g = Grid::from_vec(vec![None, Some(2), Some(3), Some(4)], 2);
        let r = g.and_then(|x| Some(x * x));

        assert_eq!(r, Grid::from_vec(vec![None, Some(4), Some(9), Some(16)], 2));
    }
}