Skip to main content

henad_core/
grid.rs

1//! The double-buffered [`Grid2D`] that holds a grid model's cells.
2
3use std::mem;
4
5/// A double-buffered 2D grid of cells, stored row-major.
6///
7/// A step reads [`Self::current`] and writes [`Self::next_mut`], then [`Self::swap`] makes the next
8/// side current.
9pub struct Grid2D<T: Copy + Default> {
10    width: u32,
11    height: u32,
12    current: Vec<T>,
13    next: Vec<T>,
14}
15
16/// Prints the grid's size, not its cells.
17impl<T: Copy + Default> std::fmt::Debug for Grid2D<T> {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        f.debug_struct("Grid2D")
20            .field("width", &self.width)
21            .field("height", &self.height)
22            .finish_non_exhaustive()
23    }
24}
25
26impl<T: Copy + Default> Grid2D<T> {
27    /// Creates a `width` by `height` grid with every cell at `T::default()` on both sides.
28    pub fn new(width: u32, height: u32) -> Self {
29        let len = (width as usize) * (height as usize);
30        Self {
31            width,
32            height,
33            current: vec![T::default(); len],
34            next: vec![T::default(); len],
35        }
36    }
37
38    /// Width in cells.
39    pub fn width(&self) -> u32 {
40        self.width
41    }
42
43    /// Height in cells.
44    pub fn height(&self) -> u32 {
45        self.height
46    }
47
48    /// Heap memory held by both sides, in bytes.
49    pub fn heap_bytes(&self) -> usize {
50        (self.current.capacity() + self.next.capacity()) * mem::size_of::<T>()
51    }
52
53    /// Number of cells.
54    pub fn len(&self) -> usize {
55        self.current.len()
56    }
57
58    /// Returns whether the grid has no cells.
59    pub fn is_empty(&self) -> bool {
60        self.current.is_empty()
61    }
62
63    /// Cells of the current side.
64    pub fn current(&self) -> &[T] {
65        &self.current
66    }
67
68    /// Returns the current side mutably, for initialisation.
69    ///
70    /// A step writes through [`Self::next_mut`].
71    pub fn current_mut(&mut self) -> &mut [T] {
72        &mut self.current
73    }
74
75    /// Returns the next side for a step to write.
76    pub fn next_mut(&mut self) -> &mut [T] {
77        &mut self.next
78    }
79
80    /// Returns the current side to read and the next side to write, as one split borrow.
81    pub fn current_and_next_mut(&mut self) -> (&[T], &mut [T]) {
82        (&self.current, &mut self.next)
83    }
84
85    /// Makes the next side current by swapping the two buffers, copying no cells.
86    pub fn swap(&mut self) {
87        mem::swap(&mut self.current, &mut self.next);
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn grid_new_and_size() {
97        let grid: Grid2D<u8> = Grid2D::new(10, 20);
98        assert_eq!(grid.width(), 10);
99        assert_eq!(grid.height(), 20);
100        assert_eq!(grid.len(), 200);
101        assert!(!grid.is_empty());
102        assert!(grid.current().iter().all(|&v| v == 0));
103    }
104
105    #[test]
106    fn grid_swap() {
107        let mut grid: Grid2D<u8> = Grid2D::new(3, 3);
108        grid.next_mut()[0] = 42;
109        assert_eq!(grid.current()[0], 0);
110        grid.swap();
111        assert_eq!(grid.current()[0], 42);
112    }
113
114    #[test]
115    fn current_and_next_mut_split_borrow() {
116        let mut grid: Grid2D<u8> = Grid2D::new(3, 3);
117        grid.current_mut()[4] = 10;
118        let (cur, nxt) = grid.current_and_next_mut();
119        nxt[4] = cur[4] + 1;
120        assert_eq!(grid.next_mut()[4], 11);
121    }
122}