use crate::{
core::{HasSize as _, Layout, Pos, Rect},
ops::{GridRead, unchecked::TrustedSizeGrid},
};
pub trait GridReadUnchecked {
type Element<'a>: 'a
where
Self: 'a;
type Layout: Layout;
unsafe fn get_unchecked(&self, pos: Pos) -> Self::Element<'_>;
unsafe fn iter_rect_unchecked(&self, bounds: Rect) -> impl Iterator<Item = Self::Element<'_>> {
Self::Layout::iter_pos(bounds).map(move |pos| unsafe { self.get_unchecked(pos) })
}
}
impl<T: GridReadUnchecked + TrustedSizeGrid> GridRead for T {
type Element<'a>
= T::Element<'a>
where
Self: 'a;
type Layout = T::Layout;
fn get(&self, pos: Pos) -> Option<Self::Element<'_>> {
if self.contains(pos) {
Some(unsafe { self.get_unchecked(pos) })
} else {
None
}
}
fn iter_rect(&self, bounds: Rect) -> impl Iterator<Item = Self::Element<'_>> {
let size = self.size().to_rect();
let rect = bounds.intersect(size);
unsafe { self.iter_rect_unchecked(rect) }
}
}
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
use crate::{core::RowMajor, ops::unchecked::TrustedSizeGrid};
use alloc::vec::Vec;
struct UncheckedTestGrid {
grid: [[u8; 3]; 3],
}
unsafe impl TrustedSizeGrid for UncheckedTestGrid {
fn width(&self) -> usize {
3
}
fn height(&self) -> usize {
3
}
}
impl GridReadUnchecked for UncheckedTestGrid {
type Element<'a> = u8;
type Layout = RowMajor;
unsafe fn get_unchecked(&self, pos: Pos) -> Self::Element<'_> {
self.grid[pos.y][pos.x]
}
}
#[test]
fn test_get_ok() {
let grid = UncheckedTestGrid {
grid: [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
};
assert_eq!(grid.get(Pos::new(1, 1)), Some(5));
}
#[test]
fn test_get_out_of_bounds_x() {
let grid = UncheckedTestGrid {
grid: [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
};
assert_eq!(grid.get(Pos::new(3, 1)), None);
}
#[test]
fn test_get_out_of_bounds_y() {
let grid = UncheckedTestGrid {
grid: [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
};
assert_eq!(grid.get(Pos::new(1, 3)), None);
}
#[test]
fn test_get_unchecked_ok() {
let grid = UncheckedTestGrid {
grid: [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
};
let val = unsafe { grid.get_unchecked(Pos::new(2, 2)) };
assert_eq!(val, 9);
}
#[test]
fn rect_iter_completely_in_bounds_unchecked_impl() {
let grid = UncheckedTestGrid {
grid: [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
};
let cells = grid
.iter_rect(Rect::from_ltwh(1, 1, 2, 2))
.collect::<Vec<_>>();
#[rustfmt::skip]
assert_eq!(cells, &[
5, 6,
8, 9,
]);
}
#[test]
fn rect_iter_partially_out_of_bounds_unchecked_impl() {
let grid = UncheckedTestGrid {
grid: [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
};
let cells = grid
.iter_rect(Rect::from_ltwh(0, 0, 4, 4))
.collect::<Vec<_>>();
#[rustfmt::skip]
assert_eq!(cells, &[
1, 2, 3,
4, 5, 6,
7, 8, 9,
]);
}
#[test]
fn rect_iter_completely_out_of_bounds_unchecked_impl() {
let grid = UncheckedTestGrid {
grid: [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
};
let cells = grid
.iter_rect(Rect::from_ltwh(3, 3, 2, 2))
.collect::<Vec<_>>();
assert!(cells.is_empty());
}
}