1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
//! A simple fixed-size 2d grid container suitable for `no_std` game development
//!
//! See [`Grid::new`] [`Grid::new_with`] and [`Grid::from_row_major_iter`] for examples on
//! how to create a grid.
//!
//! ## Features
//!
//! `std`: *(enabled by default)* enable use of the standard library. Must be disabled for `no_std` crates.
//! `aline-v01`: add conversions between [`Coord`] and [aline 0.1](https://docs.rs/aline/0.1) vectors
extern crate alloc;
mod coord;
mod rect;
use alloc::vec::Vec;
pub use coord::Coord;
pub use rect::Rect;
/// A 2d fixed-size grid containers for cells of type `T`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Grid<T> {
cells: Vec<T>,
width: usize,
}
impl<T: Default> Grid<T> {
/// Create a grid using the default value of `T` for each cell
///
/// # Example
///
/// ```
/// # use cell_grid::{Grid, Coord};
/// let grid: Grid<i32> = Grid::new(2, 2);
/// assert_eq!(grid.get([0, 0]), Some(&0));
/// assert_eq!(grid.get([1, 0]), Some(&0));
/// assert_eq!(grid.get([0, 1]), Some(&0));
/// assert_eq!(grid.get([1, 1]), Some(&0));
/// ```
#[must_use]
pub fn new(width: usize, height: usize) -> Self {
Self::new_with(width, height, |_| T::default())
}
}
impl<T> Grid<T> {
/// Create a grid using `init_cell` function for each cell
///
/// # Example
///
/// ```
/// # use cell_grid::{Grid, Coord};
/// let grid = Grid::new_with(2, 2, |coord| coord);
/// assert_eq!(grid.get([0, 0]), Some(&Coord { x: 0, y: 0 }));
/// assert_eq!(grid.get([1, 0]), Some(&Coord { x: 1, y: 0 }));
/// assert_eq!(grid.get([0, 1]), Some(&Coord { x: 0, y: 1 }));
/// assert_eq!(grid.get([1, 1]), Some(&Coord { x: 1, y: 1 }));
/// ```
#[must_use]
pub fn new_with(width: usize, height: usize, init_cell: impl FnMut(Coord) -> T) -> Self {
Self::from_row_major_iter(
width,
(0..(width * height))
.map(|i| Coord::from_index(width, i))
.map(init_cell),
)
}
/// Create a grid using the row-major `iter`
///
/// # Example
///
/// ```
/// # use cell_grid::Grid;
/// let grid = Grid::from_row_major_iter(2, [1, 2, 3, 4]);
/// assert_eq!(grid.get([0, 0]), Some(&1));
/// assert_eq!(grid.get([1, 0]), Some(&2));
/// assert_eq!(grid.get([0, 1]), Some(&3));
/// assert_eq!(grid.get([1, 1]), Some(&4));
/// ```
#[must_use]
pub fn from_row_major_iter(width: usize, iter: impl IntoIterator<Item = T>) -> Self {
let cells = iter.into_iter().collect();
Self { cells, width }
}
/// Access the cell at `coord`
///
/// Returns `None` if the `coord` is out of bounds
#[must_use]
pub fn get(&self, coord: impl Into<Coord>) -> Option<&T> {
let index = coord.into().into_index(self.width)?;
self.cells.get(index)
}
/// Iterator over cells in `rect`
pub fn cells_in_rect(&self, rect: impl Into<Rect>) -> impl Iterator<Item = &T> {
rect.into().coords().filter_map(|c| self.get(c))
}
}