1use std::marker::PhantomData;
2
3pub mod bounds2d;
4pub mod bounds3d;
5pub(crate) mod fixedarray;
6pub mod grid2d;
7pub mod grid3d;
8pub mod math;
9pub mod rollgrid2d;
10pub mod rollgrid3d;
11
12mod error_messages {
13 macro_rules! error_messages {
14 ($($name:ident = $message:literal;)*) => {
15 $(
16 pub const $name: panicmsg::PanicMsg = panicmsg::PanicMsg::new($message);
17 )*
18 };
19 }
20 error_messages!(
21 UNALLOCATED_BUFFER = "Buffer was not allocated.";
22 X_MAX_EXCEEDS_MAXIMUM = "X max bound exceeds maximum.";
23 Y_MAX_EXCEEDS_MAXIMUM = "Y max bound exceeds maximum.";
24 Z_MAX_EXCEEDS_MAXIMUM = "Z max bound exceeds maximum.";
25 NOT_ALLOCATED = "Not allocated.";
26 SIZE_TOO_LARGE = "Size is too large.";
27 OUT_OF_BOUNDS = "Out of bounds.";
28 INDEX_OUT_OF_BOUNDS = "Index is out of bounds.";
29 AREA_IS_ZERO = "Width/Height cannot be 0.";
30 VOLUME_IS_ZERO = "Width/Height/Depth cannot be 0.";
31 INFLATE_OVERFLOW = "Inflate operation results in integer overflow.";
32 DEFLATE_OVERFLOW = "Deflate operation results in integer overflow.";
33 RESIZE_OVERFLOW = "Resize operation results in overflow.";
34 );
35}
36
37pub trait CellManage<C, T> {
41 fn load(&mut self, position: C) -> T;
42 fn unload(&mut self, position: C, old_value: T);
43 fn reload(&mut self, old_position: C, new_position: C, value: &mut T);
44}
45
46pub trait TryCellManage<C, T, E> {
48 fn try_load(&mut self, position: C) -> Result<T, E>;
49 fn try_unload(&mut self, position: C, old_value: T) -> Result<(), E>;
50 fn try_reload(&mut self, old_position: C, new_position: C, value: &mut T) -> Result<(), E>;
51}
52
53pub struct CellManager<C, T, FL, FU, FR, Marker = ()> {
55 load: FL,
56 unload: FU,
57 reload: FR,
58 phantom: std::marker::PhantomData<(C, T, Marker)>,
59}
60
61impl<C, T, FL, FU, FR> CellManage<C, T> for CellManager<C, T, FL, FU, FR>
62where
63 T: Sized,
64 FL: FnMut(C) -> T,
65 FU: FnMut(C, T),
66 FR: FnMut(C, C, &mut T),
67{
68 fn load(&mut self, position: C) -> T {
70 (self.load)(position)
71 }
72
73 fn unload(&mut self, position: C, value: T) {
75 (self.unload)(position, value);
76 }
77
78 fn reload(&mut self, old_position: C, new_position: C, value: &mut T) {
80 (self.reload)(old_position, new_position, value);
81 }
82}
83
84impl<C, T, E, FL, FU, FR> TryCellManage<C, T, E> for CellManager<C, T, FL, FU, FR, (E,)>
85where
86 T: Sized,
87 FL: FnMut(C) -> Result<T, E>,
88 FU: FnMut(C, T) -> Result<(), E>,
89 FR: FnMut(C, C, &mut T) -> Result<(), E>,
90{
91 fn try_load(&mut self, position: C) -> Result<T, E> {
93 (self.load)(position)
94 }
95
96 fn try_unload(&mut self, position: C, old_value: T) -> Result<(), E> {
98 (self.unload)(position, old_value)
99 }
100
101 fn try_reload(&mut self, old_position: C, new_position: C, value: &mut T) -> Result<(), E> {
103 (self.reload)(old_position, new_position, value)
104 }
105}
106
107pub fn cell_manager<C, T, FL, FU, FR>(
109 load: FL,
110 unload: FU,
111 reload: FR,
112) -> CellManager<C, T, FL, FU, FR>
113where
114 CellManager<C, T, FL, FU, FR>: CellManage<C, T>,
115{
116 CellManager {
117 load,
118 unload,
119 reload,
120 phantom: PhantomData,
121 }
122}
123
124pub fn try_cell_manager<C, T, E, FL, FU, FR>(
126 load: FL,
127 unload: FU,
128 reload: FR,
129) -> CellManager<C, T, FL, FU, FR, (E,)>
130where
131 CellManager<C, T, FL, FU, FR, (E,)>: TryCellManage<C, T, E>,
132{
133 CellManager {
134 load,
135 unload,
136 reload,
137 phantom: PhantomData,
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 #![allow(unused)]
144 use crate::bounds2d::Bounds2D;
145 use crate::rollgrid2d::RollGrid2D;
146
147 use super::*;
148
149 #[test]
150 pub fn roll_test() {
151 const HEX_CHARS: [char; 16] = [
152 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
153 ];
154 let mut hex = HEX_CHARS.into_iter();
155 let mut grid = RollGrid2D::new((4, 4), (0, 0), |pos: (i32, i32)| hex.next().unwrap());
156 fn print_grid(grid: &RollGrid2D<char>) {
157 for y in grid.y_min()..grid.y_max() {
158 for x in grid.x_min()..grid.x_max() {
159 if let Some(c) = grid.get((x, y)) {
160 print!("{}", *c);
161 }
162 }
163 println!();
164 }
165 }
166 print_grid(&grid);
167 grid.translate((1, 1), |old_pos, new_pos, old_value| {});
168 print_grid(&grid);
169 }
170
171 #[test]
172 pub fn bounds_test() {
173 macro_rules! intersect {
178 (($a_min:expr, $a_max:expr) -=> ($b_min:expr, $b_max:expr)) => {
179 assert!(Bounds2D::from_bounds($a_min, $a_max)
180 .intersects(Bounds2D::from_bounds($b_min, $b_max)));
181 };
182 (($a_min:expr, $a_max:expr) -!> ($b_min:expr, $b_max:expr)) => {
183 assert!(!Bounds2D::from_bounds($a_min, $a_max)
184 .intersects(Bounds2D::from_bounds($b_min, $b_max)));
185 };
186 }
187 intersect!(((0, 0), (3, 3)) -!> ((3, 0), (6, 3)));
188 intersect!(((0, 0), (1, 1)) -=> ((0, 0), (1, 1)));
189 intersect!(((-1, -1), (0, 0)) -=> ((-1, -1), (0, 0)));
190 intersect!(((0, 0), (3, 3)) -=> ((1, 1), (2, 2)));
191 intersect!(((1, 1), (2, 2)) -=> ((0, 0), (3, 3)));
192 intersect!(((0, 0), (1, 1)) -!> ((1, 0), (2, 1)));
193 intersect!(((1, 0), (2, 1)) -!> ((0, 0), (1, 1)));
194 intersect!(((0, 0), (1, 1)) -!> ((0, 1), (1, 2)));
195 intersect!(((0, 1), (1, 2)) -!> ((0, 0), (1, 1)));
196 }
197
198 #[test]
199 pub fn rollgrid2d_test() {
200 let mut grid = RollGrid2D::new((2, 2), (0, 0), |coord: (i32, i32)| coord);
201 fn print_grid(grid: &RollGrid2D<(i32, i32)>) {
202 println!("***");
203 for y in grid.y_min()..grid.y_max() {
204 for x in grid.x_min()..grid.x_max() {
205 if let Some(&(cx, cy)) = grid.get((x, y)) {
206 print!("({cx:3},{cy:3})");
207 }
208 }
209 println!();
210 }
211 }
212 print_grid(&grid);
213 grid.translate((1, 1), |old, new, old_value| {
214 *old_value = old;
215 });
216 print_grid(&grid);
217 return;
218 grid.inflate_size(
219 (1, 1),
220 cell_manager(
221 |pos: (i32, i32)| {
222 println!("Load: ({}, {})", pos.0, pos.1);
223 pos
224 },
225 |pos, value| {},
226 |old_pos, new_pos, value| {},
227 ),
228 );
229 println!("***");
230 print_grid(&grid);
231 if let Some(&(x, y)) = grid.get((-5, -16)) {
232 println!("({x}, {y})");
233 } else {
234 println!("None");
235 }
236 }
237}