md_grid 0.2.1

A simple library for storing and iterating through data in a rectangular grid.
Documentation
#[cfg(feature = "prettytable")]
#[macro_use] extern crate prettytable;
#[cfg(feature = "prettytable")]
use prettytable::{Table, Row, Cell};
use std::fmt::Debug;

#[derive(Copy, Clone, Debug)]
pub struct GridPt {
    pub row: usize,
    pub col: usize
}

impl GridPt {
    pub fn new(row: usize, col: usize) -> Self {
        Self { row, col }
    }

    pub fn component_dist(pt1: GridPt, pt2: GridPt) -> (usize, usize) {
        let rows = if pt1.row > pt2.row { pt1.row - pt2.row }
            else { pt2.row - pt1.row };
        let cols = if pt1.col > pt2.col { pt1.col - pt2.col }
            else { pt2.col - pt1.col };
        (rows, cols)
    }

    pub fn l1_dist(pt1: GridPt, pt2: GridPt) -> usize {
        let (rows, cols) = Self::component_dist(pt1, pt2);
        rows + cols
    }

    pub fn l2_dist(pt1: GridPt, pt2: GridPt) -> usize {
        let (rows, cols) = Self::component_dist(pt1, pt2);
        std::cmp::max(rows, cols)
    }
}

#[derive(Debug)]
pub struct Grid<T> {
    pub rows: usize,
    pub cols: usize,
    pub cells: Vec<Vec<T>>,
}

impl<T> Grid<T>
    where T: Debug+Clone
{
    pub fn new(rows: usize, cols: usize, default: T) -> Self {
        Self {
            rows,
            cols,
            cells: vec![vec![default; cols]; rows],
        }
    }
}

impl<T> Grid<T>
    where T: Debug
{
    pub fn new_from(data: Vec<Vec<T>>) -> Self {
        let rows = data.len();
        let cols = data[0].len();
        Self {
            rows,
            cols,
            cells: data,
        }
    }

    pub fn iter(&self) -> impl Iterator<Item=&T> {
        self.cells.iter().flat_map(|row| row.iter())
    }

    pub fn rows(&self) -> impl Iterator<Item=&Vec<T>> {
        self.cells.iter()
    }

    pub fn cols<'a>(&'a self) -> impl Iterator<Item=impl Iterator<Item=&'a T>> {
        (0..self.cols)
            .map(move |col_idx| self.cells.iter().map(move |row| &row[col_idx]))
    }

    // todo can this be done similar to how vec uses deref<target=[t]>?
    pub fn get(&self, row_index: usize, col_index: usize) -> Option<&T> {
        self.cells.get(row_index).and_then(|r| r.get(col_index))
    }

    pub fn eight_neighbors<'a>(&'a self, row_origin: usize, col_origin: usize)
        -> impl Iterator<Item=&'a T>
    {
        (-1..2 as i32)
            .flat_map(|row| std::iter::repeat(row).zip(-1..2 as i32))
            .filter(|(row, col)| !(*row == 0 && *col == 0))
            .filter_map(move |(row, col)|
                self.cells
                    .get((row_origin as i32 + row) as usize)
                    .and_then(|r| r.get((col_origin as i32 + col) as usize)))
    }

    pub fn l1_dist(&self, pt1: GridPt, pt2: GridPt) -> usize {
        GridPt::l1_dist(pt1, pt2)
    }

    pub fn right_from(&self, row: usize, col: usize) -> impl Iterator<Item=&T> {
        self.cells[row][col+1..].iter()
    }

    pub fn left_from(&self, row: usize, col: usize) -> impl Iterator<Item=&T> {
        self.cells[row][..col].iter().rev()
    }

    pub fn up_from(&self, row: usize, col: usize) -> impl Iterator<Item=&T> {
        self.cells[..row].iter()
            .map(move |row_vec| &row_vec[col])
            .rev()
    }
    pub fn down_from(&self, row: usize, col: usize) -> impl Iterator<Item=&T> {
        self.cells[row+1..].iter()
            .map(move |row_vec| &row_vec[col])
    }
}

#[cfg(feature = "prettytable")]
impl<T> Grid<T>
    where T: Clone+Debug+ToString
{
    pub fn pretty_table(&self) -> Table {
        let mut table = Table::new();
        for row in self.rows() {
            table.add_row(Row::new(
                row.iter().map(|cell| Cell::new(&cell.to_string())).collect()));
        }
        table
    }
}

//pub struct LinearIter<'a, T: 'a> {
//    pub inner: &'a Grid<T>,
//    pub row: usize,
//    pub col: usize,
//}
//
//impl<'a, T> Iterator for LinearIter<'a, T> {
//    type Item = &'a T;
//
//    fn next(&mut self) -> Option<Self::Item> {
//        if self.row < self.inner.rows && self.col < self.inner.cols {
//            let ret = Some(self.inner.cells.get(self.row).unwrap()
//                                           .get(self.col).unwrap());
//            self.col += 1;
//            if self.col == self.inner.cols {
//                self.col = 0;
//                self.row += 1;
//            }
//            return ret
//        }
//        None
//    }
//}

#[cfg(test)]
mod tests {
    #[test]
    fn gridpt_component_dist() {
        let pt1 = super::GridPt::new(4, 5);
        let pt2 = super::GridPt::new(7, 7);
        assert_eq!((3, 2), super::GridPt::component_dist(pt1, pt2));
        assert_eq!((3, 2), super::GridPt::component_dist(pt2, pt1));
    }

    #[test]
    fn gridpt_l1_dist() {
        let pt1 = super::GridPt::new(4, 5);
        let pt2 = super::GridPt::new(7, 7);
        assert_eq!(5, super::GridPt::l1_dist(pt1, pt2));
        assert_eq!(5, super::GridPt::l1_dist(pt2, pt1));
    }

    #[test]
    fn grid_new() {
        let rows = 8;
        let cols = 10;
        let grid = super::Grid::<Option<usize>>::new(rows, cols, None);
        assert_eq!(grid.rows, rows);
        assert_eq!(grid.cols, cols);
        assert_eq!(grid.cells.len(), rows);
        assert_eq!(grid.cells[0].len(), cols);
    }

    #[test]
    fn grid_new_from() {
        let data = vec![
            vec![1, 2, 3, 4],
            vec![5, 6, 7, 8],
            vec![9, 10, 11, 12],
        ];
        let grid = super::Grid::<usize>::new_from(data);
        assert_eq!(grid.rows, 3);
        assert_eq!(grid.cols, 4);
        assert_eq!(grid.cells.len(), 3);
        assert_eq!(grid.cells[0].len(), 4);
    }

    #[test]
    fn grid_iter() {
        let rows = 4;
        let cols = 5;
        let grid = super::Grid::<usize>::new(rows, cols, 1);
        assert_eq!(grid.iter().sum::<usize>(), rows*cols);
    }

    #[test]
    fn grid_rows() {
        let data = vec![
            vec![1, 2, 3, 4],
            vec![5, 6, 7, 8],
            vec![9, 10, 11, 12],
        ];
        let grid = super::Grid::<usize>::new_from(data);
        let mut iter = grid.rows();
        assert_eq!(Some(&vec![1,2,3,4]), iter.next());
        assert_eq!(Some(&vec![5,6,7,8]), iter.next());
        assert_eq!(Some(&vec![9,10,11,12]), iter.next());
        assert_eq!(None, iter.next());
    }

    #[test]
    fn grid_cols() {
        let data = vec![
            vec![1, 2, 3, 4],
            vec![5, 6, 7, 8],
            vec![9, 10, 11, 12],
        ];
        let grid = super::Grid::<usize>::new_from(data);
        let mut iter = grid.cols();
        assert_eq!(vec![&1, &5, &9], iter.next().unwrap().collect::<Vec<&usize>>());
        assert_eq!(vec![&2, &6, &10], iter.next().unwrap().collect::<Vec<&usize>>());
        assert_eq!(vec![&3, &7, &11], iter.next().unwrap().collect::<Vec<&usize>>());
        assert_eq!(vec![&4, &8, &12], iter.next().unwrap().collect::<Vec<&usize>>());
        assert!(iter.next().is_none());
    }

    #[test]
    fn grid_eight_neighbors() {
        let rows = 4;
        let cols = 5;
        let grid = super::Grid::<usize>::new(rows, cols, 1);
        assert_eq!(grid.eight_neighbors(0, 0).sum::<usize>(), 3);
        assert_eq!(grid.eight_neighbors(1, 1).sum::<usize>(), 8);
        assert_eq!(grid.eight_neighbors(3, 4).sum::<usize>(), 3);
        assert_eq!(grid.eight_neighbors(10, 10).sum::<usize>(), 0);
        assert_eq!(grid.eight_neighbors(0, 1).sum::<usize>(), 5);
    }

    #[test]
    fn grid_right_from() {
        let data = vec![
            vec![1, 2, 3, 4],
            vec![5, 6, 7, 8],
            vec![9, 10, 11, 12],
        ];
        let grid = super::Grid::<usize>::new_from(data);
        let mut iter = grid.right_from(2, 1);
        assert_eq!(Some(&11), iter.next());
        assert_eq!(Some(&12), iter.next());
        assert!(iter.next().is_none());
    }

    #[test]
    fn grid_left_from() {
        let data = vec![
            vec![1, 2, 3, 4],
            vec![5, 6, 7, 8],
            vec![9, 10, 11, 12],
        ];
        let grid = super::Grid::<usize>::new_from(data);
        let mut iter = grid.left_from(1, 2);
        assert_eq!(Some(&6), iter.next());
        assert_eq!(Some(&5), iter.next());
        assert!(iter.next().is_none());
    }

    #[test]
    fn grid_up_from() {
        let data = vec![
            vec![1, 2, 3, 4],
            vec![5, 6, 7, 8],
            vec![9, 10, 11, 12],
        ];
        let grid = super::Grid::<usize>::new_from(data);
        let mut iter = grid.up_from(2, 1);
        assert_eq!(Some(&6), iter.next());
        assert_eq!(Some(&2), iter.next());
        assert!(iter.next().is_none());
    }

    #[test]
    fn grid_down_from() {
        let data = vec![
            vec![1, 2, 3, 4],
            vec![5, 6, 7, 8],
            vec![9, 10, 11, 12],
        ];
        let grid = super::Grid::<usize>::new_from(data);
        let mut iter = grid.down_from(0, 2);
        assert_eq!(Some(&7), iter.next());
        assert_eq!(Some(&11), iter.next());
        assert!(iter.next().is_none());
    }
}