use crate::SetValueSeriesError;
pub trait Grid<T> {
#[must_use]
fn get(&self, x: usize, y: usize) -> T {
#[allow(clippy::panic, reason = "This is the version that panics - _optional does not")]
self.get_optional(x, y)
.unwrap_or_else(|| panic!("Cannot access index ({x}, {y}) because it is out of bounds for a grid of dimension {}x{}", self.width(), self.height()))
}
#[must_use]
fn get_optional(&self, x: usize, y: usize) -> Option<T>;
#[must_use]
fn width(&self) -> usize;
#[must_use]
fn height(&self) -> usize;
#[must_use]
fn is_in_bounds(&self, x: usize, y: usize) -> bool {
x < self.width() && y < self.height()
}
fn assert_in_bounds(&self, x: usize, y: usize) {
let width = self.width();
assert!(x < width, "cannot access index [{x}, {y}] because x is outside of bounds [0..{width})");
let height = self.height();
assert!(y < height, "cannot access index [{x}, {y}] because y is outside of bounds [0..{height})");
}
#[must_use]
fn get_row(&self, y: usize) -> Option<Vec<T>> {
if y >= self.height() {
return None;
}
let width = self.width();
let mut row = Vec::with_capacity(width);
for x in 0..width {
row.push(self.get(x, y));
}
Some(row)
}
#[must_use]
fn get_col(&self, x: usize) -> Option<Vec<T>> {
if x >= self.width() {
return None;
}
let height = self.height();
let mut col = Vec::with_capacity(height);
for y in 0..height {
col.push(self.get(x, y));
}
Some(col)
}
}
pub trait GridMut<T: Clone>: Grid<T> {
fn set(&mut self, x: usize, y: usize, value: T) {
#[allow(
clippy::expect_used,
reason = "This is the version that panics - _optional does not"
)]
let worked = self.set_optional(x, y, value);
assert!(worked, "Cannot access index ({x}, {y}) because it is out of bounds for a grid of dimension {}x{}", self.width(), self.height());
}
#[must_use]
fn set_optional(&mut self, x: usize, y: usize, value: T) -> bool;
fn fill(&mut self, value: T);
fn deref_assign<O: Grid<T>>(&mut self, other: &O) {
let width = self.width();
let height = self.height();
assert_eq!(
width,
other.width(),
"Cannot assign grid of width {} to a window of width {}",
other.width(),
self.width()
);
assert_eq!(
height,
other.height(),
"Cannot assign grid of height {} to a height of width {}",
other.height(),
self.height()
);
for y in 0..height {
for x in 0..width {
self.set(x, y, other.get(x, y));
}
}
}
fn set_col(
&mut self,
x: usize,
col: &[T],
) -> Result<(), SetValueSeriesError> {
let height = self.height();
if col.len() != height {
return Err(SetValueSeriesError::InvalidLength {
expected: height,
actual: col.len(),
});
}
if x >= self.width() {
return Err(SetValueSeriesError::OutOfBounds {
size: self.width(),
index: x,
});
}
for (y, item) in col.iter().enumerate().take(height) {
self.set(x, y, item.clone());
}
Ok(())
}
fn set_row(
&mut self,
y: usize,
row: &[T],
) -> Result<(), SetValueSeriesError> {
let width = self.width();
if row.len() != width {
return Err(SetValueSeriesError::InvalidLength {
expected: width,
actual: row.len(),
});
}
if y >= self.height() {
return Err(SetValueSeriesError::OutOfBounds {
size: self.height(),
index: y,
});
}
for (x, item) in row.iter().enumerate().take(width) {
self.set(x, y, item.clone());
}
Ok(())
}
}
#[cfg(test)]
mod test {
use crate::{DataRef, Grid, GridMut, SetValueSeriesError, ValueGrid};
#[test]
fn optional() {
let mut grid = ValueGrid::load(2, 2, &[0, 1, 2, 3]).unwrap();
assert!(grid.set_optional(0, 0, 5));
assert!(!grid.set_optional(0, 8, 42));
assert_eq!(grid.data_ref(), [5, 1, 2, 3]);
assert_eq!(grid.get_optional(0, 0), Some(5));
assert_eq!(grid.get_optional(0, 8), None);
}
#[test]
fn col() {
let mut grid = ValueGrid::load(2, 3, &[0, 1, 2, 3, 4, 5]).unwrap();
assert_eq!(grid.get_col(0), Some(vec![0, 2, 4]));
assert_eq!(grid.get_col(1), Some(vec![1, 3, 5]));
assert_eq!(grid.get_col(2), None);
assert_eq!(grid.set_col(0, &[5, 7, 9]), Ok(()));
assert_eq!(
grid.set_col(2, &[5, 7, 9]),
Err(SetValueSeriesError::OutOfBounds { size: 2, index: 2 })
);
assert_eq!(
grid.set_col(0, &[5, 7]),
Err(SetValueSeriesError::InvalidLength {
expected: 3,
actual: 2
})
);
assert_eq!(grid.get_col(0), Some(vec![5, 7, 9]));
}
#[test]
fn row() {
let mut grid = ValueGrid::load(2, 3, &[0, 1, 2, 3, 4, 5]).unwrap();
assert_eq!(grid.get_row(0), Some(vec![0, 1]));
assert_eq!(grid.get_row(2), Some(vec![4, 5]));
assert_eq!(grid.get_row(3), None);
assert_eq!(grid.set_row(0, &[5, 7]), Ok(()));
assert_eq!(grid.get_row(0), Some(vec![5, 7]));
assert_eq!(
grid.set_row(3, &[5, 7]),
Err(SetValueSeriesError::OutOfBounds { size: 3, index: 3 })
);
assert_eq!(
grid.set_row(2, &[5, 7, 3]),
Err(SetValueSeriesError::InvalidLength {
expected: 2,
actual: 3
})
);
}
}