merosity 0.1.0

(wip) competitive stacker game
// merosity, online stacker game
//
// Copyright (c) 2023 rini
// SPDX-License-Identifier: Apache-2.0

pub struct Board<T> {
    stride: usize,
    buffer: Box<[T]>,
}

impl<T> Board<T> {
    pub fn filled(shape: (usize, usize), value: T) -> Self
    where
        T: Clone,
    {
        let (width, height) = shape;
        Self {
            stride: width,
            buffer: vec![value; width * height].into_boxed_slice(),
        }
    }

    pub fn flat(&self) -> &[T] {
        &self.buffer
    }
}

impl<T> std::ops::Index<usize> for Board<T> {
    type Output = [T];

    fn index(&self, index: usize) -> &Self::Output {
        &self.buffer[index * self.stride..(index + 1) * self.stride]
    }
}

impl<T> std::ops::IndexMut<usize> for Board<T> {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        &mut self.buffer[index * self.stride..(index + 1) * self.stride]
    }
}

pub struct Iter<'a, T> {
    board: &'a Board<T>,
    i: usize,
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a [T];

    fn next(&mut self) -> Option<Self::Item> {
        if self.i < self.board.buffer.len() {
            let i = self.i;
            self.i = i + self.board.stride;
            Some(&self.board.buffer[i..self.i])
        } else {
            None
        }
    }
}

impl<'a, T> IntoIterator for &'a Board<T> {
    type Item = &'a [T];
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        Iter {
            board: self,
            i: 0,
        }
    }
}