1use crate::orientation::Orientation;
2use coord_2d::*;
3use grid_2d::*;
4use std::hash::{Hash, Hasher};
5
6#[derive(Clone)]
7pub struct TiledGridSlice<'a, T: 'a> {
8 grid: &'a Grid<T>,
9 offset: Coord,
10 size: Size,
11 orientation: Orientation,
12}
13
14pub struct TiledGridSliceIter<'a, T: 'a> {
15 grid: &'a TiledGridSlice<'a, T>,
16 coord_iter: CoordIter,
17}
18
19impl<'a, T> Iterator for TiledGridSliceIter<'a, T> {
20 type Item = &'a T;
21 fn next(&mut self) -> Option<Self::Item> {
22 self.coord_iter
23 .next()
24 .map(|coord| self.grid.get_valid(coord))
25 }
26}
27
28impl<'a, T> TiledGridSlice<'a, T> {
29 pub fn new(
30 grid: &'a Grid<T>,
31 offset: Coord,
32 size: Size,
33 orientation: Orientation,
34 ) -> Self {
35 TiledGridSlice {
36 grid,
37 offset,
38 size,
39 orientation,
40 }
41 }
42 pub fn size(&self) -> Size {
43 self.size
44 }
45 fn get_valid(&self, coord: Coord) -> &'a T {
46 let transformed_coord = self.orientation.transform_coord(self.size, coord);
47 self.grid.get_tiled(self.offset + transformed_coord)
48 }
49 pub fn get_checked(&self, coord: Coord) -> &'a T {
50 if coord.is_valid(self.size) {
51 self.get_valid(coord)
52 } else {
53 panic!("coord is out of bounds");
54 }
55 }
56 pub fn offset(&self) -> Coord {
57 self.offset
58 }
59 pub fn iter(&self) -> TiledGridSliceIter<T> {
60 TiledGridSliceIter {
61 grid: self,
62 coord_iter: CoordIter::new(self.size),
63 }
64 }
65}
66
67impl<'a, T: Hash> Hash for TiledGridSlice<'a, T> {
68 fn hash<H: Hasher>(&self, state: &mut H) {
69 for value in self.iter() {
70 value.hash(state);
71 }
72 }
73}
74
75impl<'a, T: PartialEq> PartialEq for TiledGridSlice<'a, T> {
76 fn eq(&self, other: &Self) -> bool {
77 self.size == other.size && self.iter().zip(other.iter()).all(|(s, o)| s.eq(o))
78 }
79}
80impl<'a, T: Eq> Eq for TiledGridSlice<'a, T> {}
81
82#[cfg(test)]
83mod test {
84 use super::*;
85 use crate::orientation::Orientation;
86 use coord_2d::{Coord, Size};
87 use std::collections::HashSet;
88
89 #[test]
90 fn tiling() {
91 let grid = Grid::new_fn(Size::new(4, 4), |coord| coord);
92 let slice = TiledGridSlice::new(
93 &grid,
94 Coord::new(-1, -1),
95 Size::new(2, 2),
96 Orientation::Original,
97 );
98 let value = *slice.get_valid(Coord::new(0, 1));
99 assert_eq!(value, Coord::new(3, 0));
100 }
101 #[test]
102 fn tiled_grid_slice_hash() {
103 let mut grid = Grid::new_fn(Size::new(4, 4), |_| 0);
104 *grid.get_mut(Coord::new(1, 3)).unwrap() = 1;
105 let size = Size::new(2, 2);
106 let a = TiledGridSlice::new(&grid, Coord::new(0, 0), size, Orientation::Original);
107 let b = TiledGridSlice::new(&grid, Coord::new(2, 2), size, Orientation::Original);
108 let c = TiledGridSlice::new(&grid, Coord::new(0, 2), size, Orientation::Original);
109 let d =
110 TiledGridSlice::new(&grid, Coord::new(1, 2), size, Orientation::Clockwise270);
111 let mut set = HashSet::new();
112 set.insert(a);
113 set.insert(b);
114 set.insert(c);
115 set.insert(d);
116 assert_eq!(set.len(), 2);
117 }
118}