lat/
lib.rs

1use std::{
2    array,
3    ops::{Index, IndexMut},
4};
5
6pub struct Grid<T> {
7    width: usize,
8    height: usize,
9    buffer: Vec<T>,
10}
11
12impl<T: Default + Clone> Grid<T> {
13    pub fn from_defaults(width: usize, height: usize) -> Self {
14        Self {
15            width,
16            height,
17            buffer: vec![Default::default(); width * height],
18        }
19    }
20}
21
22impl<T> Index<(usize, usize)> for Grid<T> {
23    type Output = T;
24
25    fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
26        assert!(x < self.width);
27        assert!(y < self.height);
28        &self.buffer[y * self.width + x]
29    }
30}
31impl<T> IndexMut<(usize, usize)> for Grid<T> {
32    fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output {
33        assert!(x < self.width);
34        assert!(y < self.height);
35        &mut self.buffer[y * self.width + x]
36    }
37}
38
39impl<T> Grid<T> {
40    pub fn from_fn(width: usize, height: usize, fun: &mut impl FnMut(usize, usize) -> T) -> Self {
41        let mut buffer = Vec::with_capacity(width * height);
42
43        for y in 0..height {
44            for x in 0..width {
45                buffer.push(fun(x, y));
46            }
47        }
48
49        Self {
50            width,
51            height,
52            buffer,
53        }
54    }
55    pub fn width(&self) -> usize {
56        self.width
57    }
58    pub fn height(&self) -> usize {
59        self.height
60    }
61    pub fn map_once<U, F>(self, mapper: F) -> Grid<U>
62    where
63        F: FnMut(T) -> U,
64    {
65        let buffer = self.buffer.into_iter().map(mapper).collect();
66        Grid {
67            width: self.width,
68            height: self.height,
69            buffer,
70        }
71    }
72    pub fn map<U, F>(&self, mapper: F) -> Grid<U>
73    where
74        F: FnMut(&T) -> U,
75    {
76        let buffer = self.buffer.iter().map(mapper).collect();
77        Grid {
78            width: self.width,
79            height: self.height,
80            buffer,
81        }
82    }
83}
84impl<T: Clone> Grid<T> {
85    pub fn map_mut<F>(&mut self, mut mapper: F) -> &mut Grid<T>
86    where
87        F: FnMut(T) -> T,
88    {
89        self.buffer.iter_mut().for_each(|v| {
90            let old = v.clone();
91            let new = mapper(old);
92            *v = new;
93        });
94        self
95    }
96    pub fn map_with_neighbors<U, F>(&self, mut mapper: F, default: T) -> Grid<U>
97    where
98        F: FnMut(&[[T; 3]; 3]) -> U,
99        U: Default,
100    {
101        let (width, height) = (self.width, self.height);
102        let mut buffer = Vec::with_capacity(width * height);
103        let mut neighborhood = array::from_fn(|_| array::from_fn(|_| default.clone()));
104        for y in 0..self.height {
105            for x in 0..self.width {
106                for oy in 0..3 {
107                    for ox in 0..3 {
108                        let x = x as isize + ox as isize - 1;
109                        let y = y as isize + oy as isize - 1;
110                        neighborhood[ox][oy] =
111                            if x > 0 && x < width as _ && y > 0 && y < height as _ {
112                                self[(x as _, y as _)].clone()
113                            } else {
114                                default.clone()
115                            };
116                    }
117                }
118                buffer.push(mapper(&neighborhood));
119            }
120        }
121        Grid {
122            width,
123            height,
124            buffer,
125        }
126    }
127}
128
129// /////////////////////////////////////////////////////////////////////////////
130// Operator Implementation below
131// /////////////////////////////////////////////////////////////////////////////
132
133use core::ops::*;
134macro_rules! impl_binop {
135    ($($Trait:ident => $fun:ident),*) => {$(
136        impl<'a, R: 'static, T: $Trait<&'a R>> $Trait<&'a Grid<R>> for Grid<T> {
137            type Output = Grid<T::Output>;
138            fn $fun(self, rhs: &'a Grid<R>) -> Self::Output {
139                assert_eq!(self.width, rhs.width);
140                assert_eq!(self.height, rhs.height);
141                let buffer = self.buffer.into_iter().zip(rhs.buffer.iter()).map(|(l, r)| l.$fun(r)).collect::<Vec<_>>();
142                Grid {
143                    width: self.width,
144                    height: self.height,
145                    buffer
146                }
147            }
148        }
149    )*};
150}
151macro_rules! impl_assign {
152    ($($Trait:ident => $fun:ident),*) => {$(
153        impl<'a, R, T: $Trait<&'a R>> $Trait<&'a Grid<R>> for Grid<T> {
154            fn $fun(&mut self, rhs: &'a Grid<R>) {
155                assert_eq!(self.width, rhs.width);
156                assert_eq!(self.height, rhs.height);
157                self.buffer.iter_mut().zip(rhs.buffer.iter()).for_each(|(l, r)| l.$fun(r));
158            }
159        }
160    )*};
161}
162macro_rules! impl_unop {
163    ($($Trait:ident => $fun:ident),*) => {$(
164        impl<'a, T: $Trait> $Trait for Grid<T> {
165            type Output = Grid<T::Output>;
166            fn $fun(self) -> Self::Output {
167                let buffer = self.buffer.into_iter().map($Trait::$fun).collect::<Vec<_>>();
168                Grid {
169                    width: self.width,
170                    height: self.height,
171                    buffer
172                }
173            }
174        }
175    )*};
176}
177
178impl_assign!(
179    AddAssign => add_assign,
180    BitAndAssign => bitand_assign,
181    BitOrAssign => bitor_assign,
182    BitXorAssign => bitxor_assign,
183    DivAssign => div_assign,
184    MulAssign => mul_assign,
185    RemAssign => rem_assign,
186    ShlAssign => shl_assign,
187    ShrAssign => shr_assign,
188    SubAssign => sub_assign
189);
190impl_binop!(
191    Add => add,
192    Sub => sub,
193    Mul => mul,
194    Div => div,
195    Rem => rem,
196    Shr => shr,
197    Shl => shl,
198    BitAnd => bitand,
199    BitOr => bitor,
200    BitXor => bitxor
201);
202impl_unop!(
203    Neg => neg,
204    Not => not
205);