#[derive(Clone, Default)]
pub struct Field<T> {
data: Vec<T>,
width: usize,
height: usize,
}
impl<T> Field<T> {
pub fn with_vec(width: usize, height: usize, data: Vec<T>) -> Option<Self> {
if data.len() == width * height {
Some(Self {
data,
width,
height,
})
} else {
None
}
}
pub fn width(&self) -> usize {
self.width
}
pub fn height(&self) -> usize {
self.height
}
pub fn peek(&self, index: usize) -> Option<&T> {
self.data.get(index)
}
pub fn peek_mut(&mut self, index: usize) -> Option<&mut T> {
self.data.get_mut(index)
}
pub fn replace(&mut self, index: usize, value: T) -> Option<T> {
self.data
.get_mut(index)
.map(|elem| std::mem::replace(elem, value))
}
pub fn locate(&self, index: usize) -> (usize, usize) {
(index % self.width, index / self.width)
}
pub fn index_at(&self, x: usize, y: usize) -> usize {
self.width * y + x
}
pub fn iter(&self) -> impl Iterator + '_ {
self.data.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator + '_ {
self.data.iter_mut()
}
}
impl<T> Field<T>
where
T: Default,
{
pub fn with_default(width: usize, height: usize) -> Self {
let size = width * height;
let mut data = Vec::with_capacity(size);
data.resize_with(size, T::default);
Self {
data,
width,
height,
}
}
}
impl<T> Field<T>
where
T: Clone,
{
pub fn with_initial(width: usize, height: usize, value: T) -> Self {
Self {
data: vec![value; width * height],
width,
height,
}
}
pub fn get(&self, index: usize) -> Option<T> {
self.peek(index).cloned()
}
pub fn set(&mut self, index: usize, value: &T) {
if let Some(elem) = self.data.get_mut(index) {
*elem = value.clone();
}
}
}
impl<T> IntoIterator for Field<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.data.into_iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty() {
let mut field = Field::<i32>::default();
assert_eq!(field.width(), 0);
assert_eq!(field.height(), 0);
assert_eq!(field.peek(0), None);
assert_eq!(field.peek_mut(0), None);
}
#[test]
fn two_by_three() {
let mut field = Field::with_initial(3, 2, 1);
for i in 0..6 {
assert_eq!(field.replace(i, i), Some(1));
}
for i in 0..6 {
assert_eq!(field.peek(i), Some(&i));
}
}
}