use std::{
fmt,
ops::{Deref, DerefMut, Index, IndexMut},
};
use crate::pos::{Size, X, Y};
pub struct Grid<T: Default + Copy> {
size: Size,
cells: Vec<T>,
}
impl<T: Default + Copy> Grid<T> {
pub fn new_with(size: Size, mut cell: impl FnMut(X, Y) -> T) -> Self {
let cells = (0..size.height.0)
.flat_map(|y| (0..size.width.0).map(move |x| (X(x), Y(y))))
.map(|(x, y)| cell(x, y))
.collect();
Self { size, cells }
}
pub fn new(size: Size) -> Self {
Self { size, cells: vec![T::default(); size.area()] }
}
#[inline]
pub fn size(&self) -> Size {
self.size
}
#[inline]
pub fn width(&self) -> X {
self.size.width
}
#[inline]
pub fn height(&self) -> Y {
self.size.height
}
#[inline]
pub fn is_empty(&self) -> bool {
self.size.is_empty()
}
pub fn resize(&mut self, new: Size) {
let minheight = self.height().min(new.height).0;
if new.width < self.width() {
for row in 0..minheight {
let os = row * self.width().0;
let oe = os + new.width.0;
let ns = row * new.width.0;
self.cells.copy_within(os..oe, ns);
}
}
self.cells.resize(new.width.0 * new.height.0, T::default());
if new.width > self.width() {
for row in 0..minheight {
let row = minheight - 1 - row;
let os = row * self.width().0;
let oe = os + self.width().0;
let ns = row * new.width.0;
let bs = ns + self.width().0;
let be = ns + new.width.0;
self.cells.copy_within(os..oe, ns);
self.cells[bs..be].fill(T::default());
}
} else if self.height() < new.height {
let bs = new.width.0 * self.height().0;
self.cells[bs..].fill(T::default());
}
self.size = new;
}
pub fn all_cells(&mut self) -> &mut [T] {
&mut self.cells
}
}
impl<T: Default + Copy + Into<char>> fmt::Debug for Grid<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut rvs = Vec::with_capacity(self.height().0);
for row in self.rows() {
let rv: String = row.iter().copied().map(|c| c.into()).collect();
rvs.push(rv);
}
f.debug_struct("Grid")
.field("size", &Size::new(self.width(), self.height()))
.field("rows", &rvs)
.finish()
}
}
macro_rules! stripe {
(
$fn:ident($pos:ident: $ptype:ident) -> $type:ident:
$xtype:ident, $dim:ident, |$self:ident, $index:ident| $get:expr
) => {
paste::paste! {
impl<T: Default + Copy> Grid<T> {
#[doc = concat!("get the nth ", stringify!($fn), " in the grid")]
pub fn $fn<'g>(&'g self, $pos: $ptype) -> Option<$type<'g, T>> {
if $pos >= self.$dim() {
return None;
}
Some($type {
grid: self,
$pos: $pos,
})
}
#[doc = concat!("get the nth ", stringify!($fn), " in the grid for writing")]
pub fn [<$fn _mut>]<'g>(&'g mut self, $pos: $ptype) -> Option<[<$type Mut>]<'g, T>> {
if $pos >= self.$dim() {
return None;
}
Some([<$type Mut>] {
grid: self,
$pos: $pos,
})
}
#[doc = concat!("iterate over all ", stringify!($fn), "s in the grid")]
pub fn [<$fn s>]<'g>(&'g self) -> impl Iterator<Item = $type<'g, T>> {
[<$type sIter>] {
grid: self,
$pos: $ptype(0),
}
}
}
#[doc = concat!("the nth ", stringify!($fn), " in the grid")]
pub struct $type<'g, T: Default + Copy> {
grid: &'g Grid<T>,
$pos: $ptype,
}
impl<'g, T: Default + Copy> Index<$xtype> for $type<'g, T> {
type Output = T;
fn index(&self, index: $xtype) -> &Self::Output {
let $self = self;
let $index = index;
&self.grid.cells[$get]
}
}
#[doc = concat!("the nth ", stringify!($fn), " in the grid, mutably referenced")]
pub struct [<$type Mut>]<'g, T: Default + Copy> {
grid: &'g mut Grid<T>,
$pos: $ptype,
}
impl<'g, T: Default + Copy> Index<$xtype> for [<$type Mut>]<'g, T> {
type Output = T;
fn index(&self, index: $xtype) -> &Self::Output {
let $self = self;
let $index = index;
&self.grid.cells[$get]
}
}
impl<'g, T: Default + Copy> IndexMut<$xtype> for [<$type Mut>]<'g, T> {
fn index_mut(&mut self, index: $xtype) -> &mut Self::Output {
let $self = &mut *self;
let $index = index;
&mut $self.grid.cells[$get]
}
}
struct [<$type sIter>]<'g, T: Default + Copy> {
grid: &'g Grid<T>,
$pos: $ptype,
}
impl<'g, T: Default + Copy> Iterator for [<$type sIter>]<'g, T> {
type Item = $type<'g, T>;
fn next(&mut self) -> Option<Self::Item> {
let stripe = self.grid.$fn(self.$pos)?;
self.$pos += $ptype(1);
Some(stripe)
}
}
}
};
}
stripe!(row(y: Y) -> Row: X, height, |s, i| s.y.0 * s.grid.size.width.0 + i.0);
stripe!(col(x: X) -> Col: Y, width, |s, i| i.0 * s.grid.size.width.0 + s.x.0);
impl<'g, T: Default + Copy> Deref for Row<'g, T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
let start = self.y.0 * self.grid.width().0;
let end = start + self.grid.width().0;
&self.grid.cells[start..end]
}
}
impl<'g, T: Default + Copy> Deref for RowMut<'g, T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
let start = self.y.0 * self.grid.width().0;
let end = start + self.grid.width().0;
&self.grid.cells[start..end]
}
}
impl<'g, T: Default + Copy> DerefMut for RowMut<'g, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
let start = self.y.0 * self.grid.width().0;
let end = start + self.grid.width().0;
&mut self.grid.cells[start..end]
}
}