use crate::{Extent2, Order, PhantomData, Position2, TermGrid, TermGridError};
#[rustfmt::skip]
impl<E, S: AsRef<[E]>> TermGrid<E, S> {
pub fn new(storage: S, extent: Extent2<usize>) -> Result<Self, TermGridError> {
let [width, height] = extent.dim;
let len = width.checked_mul(height).ok_or(TermGridError::ExtentOverflow)?;
let available = storage.as_ref().len();
if available < len {
return Err(TermGridError::NotEnoughElements { required: len, available });
}
Ok(Self { storage, extent, len, _element: PhantomData })
}
pub const fn extent(&self) -> Extent2<usize> { self.extent }
#[must_use]
pub const fn width(&self) -> usize { self.extent.dim[0] }
#[must_use]
pub const fn height(&self) -> usize { self.extent.dim[1] }
#[must_use]
pub const fn len(&self) -> usize { self.len }
#[must_use]
pub const fn is_empty(&self) -> bool { self.len == 0 }
#[must_use]
pub const fn storage(&self) -> &S { &self.storage }
#[must_use]
pub fn into_storage(self) -> S { self.storage }
#[must_use]
pub fn storage_slice(&self) -> &[E] { self.storage.as_ref() }
#[must_use]
pub fn as_slice(&self) -> &[E] { &self.storage.as_ref()[..self.len] }
#[must_use]
pub fn spare_len(&self) -> usize { self.storage.as_ref().len() - self.len }
}
#[rustfmt::skip]
impl<E, S: AsRef<[E]>> TermGrid<E, S> {
#[must_use]
pub const fn contains(&self, pos: Position2<usize>) -> bool {
let [x, y] = pos.dim;
x < self.width() && y < self.height()
}
#[must_use]
pub const fn index_of(&self, pos: Position2<usize>) -> Option<usize> {
let [x, y] = pos.dim;
Order::row_major_try_from_2d(x, y, self.width(), self.height())
}
#[must_use]
pub const fn position_of(&self, index: usize) -> Option<Position2<usize>> {
match Order::row_major_try_to_2d(index, self.width(), self.height()) {
Some((x, y)) => Some(Position2::new([x, y])),
None => None,
}
}
#[must_use]
pub fn get(&self, pos: Position2<usize>) -> Option<&E> {
let index = Order::row_major_try_from_2d(
pos.dim[0],
pos.dim[1],
self.width(),
self.height(),
)?;
self.storage.as_ref().get(index)
}
#[must_use]
pub fn get_xy(&self, x: usize, y: usize) -> Option<&E> { self.get(Position2::new([x, y])) }
#[must_use]
pub fn row(&self, y: usize) -> Option<&[E]> {
if y >= self.height() { return None; }
let width = self.width();
let start = y * width;
Some(&self.as_slice()[start..start + width])
}
}
#[rustfmt::skip]
impl<E, S: AsRef<[E]> + AsMut<[E]>> TermGrid<E, S> {
#[must_use]
pub fn as_mut_slice(&mut self) -> &mut [E] {
&mut self.storage.as_mut()[..self.len]
}
#[must_use]
pub fn storage_slice_mut(&mut self) -> &mut [E] {
self.storage.as_mut()
}
#[must_use]
pub fn get_mut(&mut self, pos: Position2<usize>) -> Option<&mut E> {
let index = Order::row_major_try_from_2d(
pos.dim[0],
pos.dim[1],
self.width(),
self.height(),
)?;
self.storage.as_mut().get_mut(index)
}
#[must_use]
pub fn get_xy_mut(&mut self, x: usize, y: usize) -> Option<&mut E> {
self.get_mut(Position2::new([x, y]))
}
#[must_use]
pub fn row_mut(&mut self, y: usize) -> Option<&mut [E]> {
if y >= self.height() { return None; }
let width = self.width();
let start = y * width;
Some(&mut self.as_mut_slice()[start..start + width])
}
pub fn set(&mut self, pos: Position2<usize>, element: impl Into<E>) -> bool {
match self.get_mut(pos) {
Some(dst) => { *dst = element.into(); true }
None => false,
}
}
pub fn set_xy(&mut self, x: usize, y: usize, element: impl Into<E>) -> bool {
self.set(Position2::new([x, y]), element.into())
}
}
impl<E: Copy, S: AsRef<[E]> + AsMut<[E]>> TermGrid<E, S> {
pub fn fill(&mut self, element: E) {
self.as_mut_slice().fill(element);
}
#[must_use]
pub fn get_copy(&self, pos: Position2<usize>) -> Option<E> {
self.get(pos).copied()
}
#[must_use]
pub fn get_xy_copy(&self, x: usize, y: usize) -> Option<E> {
self.get_xy(x, y).copied()
}
}