#![deny(missing_docs)]
use std::fmt::{Display, Formatter};
use std::ops::{Index, IndexMut};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Array2D<T> {
array: Vec<T>,
num_rows: usize,
num_columns: usize,
}
#[derive(Debug, Eq, PartialEq)]
pub enum Error {
IndicesOutOfBounds(usize, usize),
IndexOutOfBounds(usize),
DimensionMismatch,
NotEnoughElements,
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Error::IndicesOutOfBounds(row, column) => write!(f, "indices ({row}, {column}) out of bounds"),
Error::IndexOutOfBounds(index) => write!(f, "index {index} out of bounds"),
Error::DimensionMismatch => write!(f, "dimension mismatch"),
Error::NotEnoughElements => write!(f, "not enough elements"),
}
}
}
impl std::error::Error for Error {}
impl<T> Array2D<T> {
pub fn from_rows(elements: &[Vec<T>]) -> Result<Self, Error>
where
T: Clone,
{
let row_len = elements.get(0).map(Vec::len).unwrap_or(0);
if !elements.iter().all(|row| row.len() == row_len) {
return Err(Error::DimensionMismatch);
}
Ok(Array2D {
array: flatten(elements),
num_rows: elements.len(),
num_columns: row_len,
})
}
pub fn from_columns(elements: &[Vec<T>]) -> Result<Self, Error>
where
T: Clone,
{
let column_len = elements.get(0).map(Vec::len).unwrap_or(0);
if !elements.iter().all(|column| column.len() == column_len) {
return Err(Error::DimensionMismatch);
}
let num_rows = column_len;
let num_columns = elements.len();
let array = indices_row_major(num_rows, num_columns)
.map(|(row, column)| elements[column][row].clone())
.collect();
Ok(Array2D {
array,
num_rows,
num_columns,
})
}
pub fn from_row_major(
elements: &[T],
num_rows: usize,
num_columns: usize,
) -> Result<Self, Error>
where
T: Clone,
{
let total_len = num_rows * num_columns;
if total_len != elements.len() {
return Err(Error::DimensionMismatch);
}
Ok(Array2D {
array: elements.to_vec(),
num_rows,
num_columns,
})
}
pub fn from_column_major(
elements: &[T],
num_rows: usize,
num_columns: usize,
) -> Result<Self, Error>
where
T: Clone,
{
let total_len = num_rows * num_columns;
if total_len != elements.len() {
return Err(Error::DimensionMismatch);
}
let indices_row_major =
(0..num_rows).flat_map(move |row| (0..num_columns).map(move |column| (row, column)));
let array = indices_row_major
.map(|(row, column)| {
let index = column * num_rows + row;
elements[index].clone()
})
.collect();
Ok(Array2D {
array,
num_rows,
num_columns,
})
}
pub fn filled_with(element: T, num_rows: usize, num_columns: usize) -> Self
where
T: Clone,
{
let total_len = num_rows * num_columns;
let array = vec![element; total_len];
Array2D {
array,
num_rows,
num_columns,
}
}
#[deprecated(since = "0.2.0", note = "Renamed to filled_with")]
pub fn fill_with(element: T, num_rows: usize, num_columns: usize) -> Self
where
T: Clone,
{
Array2D::filled_with(element, num_rows, num_columns)
}
pub fn filled_by_row_major<F>(mut generator: F, num_rows: usize, num_columns: usize) -> Self
where
F: FnMut() -> T,
{
let total_len = num_rows * num_columns;
let array = (0..total_len).map(|_| generator()).collect();
Array2D {
array,
num_rows,
num_columns,
}
}
pub fn filled_by_column_major<F>(mut generator: F, num_rows: usize, num_columns: usize) -> Self
where
F: FnMut() -> T,
T: Clone,
{
let total_len = num_rows * num_columns;
let array_column_major = (0..total_len).map(|_| generator()).collect::<Vec<_>>();
Array2D::from_column_major(&array_column_major, num_rows, num_columns)
.expect("Filled by should never fail")
}
pub fn from_iter_row_major<I>(
iterator: I,
num_rows: usize,
num_columns: usize,
) -> Result<Self, Error>
where
I: Iterator<Item = T>,
{
let total_len = num_rows * num_columns;
let array = iterator.take(total_len).collect::<Vec<_>>();
if array.len() != total_len {
return Err(Error::NotEnoughElements);
}
Ok(Array2D {
array,
num_rows,
num_columns,
})
}
pub fn from_iter_column_major<I>(
iterator: I,
num_rows: usize,
num_columns: usize,
) -> Result<Self, Error>
where
I: Iterator<Item = T>,
T: Clone,
{
let total_len = num_rows * num_columns;
let array_column_major = iterator.take(total_len).collect::<Vec<_>>();
Array2D::from_column_major(&array_column_major, num_rows, num_columns)
.map_err(|_| Error::NotEnoughElements)
}
pub fn num_rows(&self) -> usize {
self.num_rows
}
pub fn num_columns(&self) -> usize {
self.num_columns
}
pub fn num_elements(&self) -> usize {
self.num_rows * self.num_columns
}
pub fn row_len(&self) -> usize {
self.num_columns
}
pub fn column_len(&self) -> usize {
self.num_rows
}
pub fn get(&self, row: usize, column: usize) -> Option<&T> {
self.get_index(row, column).map(|index| &self.array[index])
}
pub fn get_row_major(&self, index: usize) -> Option<&T> {
self.array.get(index)
}
pub fn get_column_major(&self, index: usize) -> Option<&T> {
let column = dbg!(dbg!(index) / self.num_rows);
let row = dbg!(index % self.num_rows);
self.get(row, column)
}
pub fn get_mut(&mut self, row: usize, column: usize) -> Option<&mut T> {
self.get_index(row, column)
.map(move |index| &mut self.array[index])
}
pub fn get_mut_row_major(&mut self, index: usize) -> Option<&mut T> {
self.array.get_mut(index)
}
pub fn get_mut_column_major(&mut self, index: usize) -> Option<&mut T> {
let column = index / self.num_rows;
let row = index % self.num_rows;
self.get_mut(row, column)
}
pub fn set(&mut self, row: usize, column: usize, element: T) -> Result<(), Error> {
self.get_mut(row, column)
.map(|location| {
*location = element;
})
.ok_or(Error::IndicesOutOfBounds(row, column))
}
pub fn set_row_major(&mut self, index: usize, element: T) -> Result<(), Error> {
self.get_mut_row_major(index)
.map(|location| {
*location = element;
})
.ok_or(Error::IndexOutOfBounds(index))
}
pub fn set_column_major(&mut self, index: usize, element: T) -> Result<(), Error> {
self.get_mut_column_major(index)
.map(|location| {
*location = element;
})
.ok_or(Error::IndexOutOfBounds(index))
}
pub fn elements_row_major_iter(&self) -> impl DoubleEndedIterator<Item = &T> + Clone {
self.array.iter()
}
pub fn elements_column_major_iter(&self) -> impl DoubleEndedIterator<Item = &T> + Clone {
self.indices_column_major().map(move |i| &self[i])
}
pub fn row_iter(&self, row_index: usize) -> Result<impl DoubleEndedIterator<Item = &T> + Clone, Error> {
let start = self
.get_index(row_index, 0)
.ok_or(Error::IndicesOutOfBounds(row_index, 0))?;
let end = start + self.row_len();
Ok(self.array[start..end].iter())
}
pub fn column_iter(
&self,
column_index: usize,
) -> Result<impl DoubleEndedIterator<Item = &T> + Clone, Error> {
if column_index >= self.num_columns {
return Err(Error::IndicesOutOfBounds(0, column_index));
}
Ok((0..self.column_len()).map(move |row_index| &self[(row_index, column_index)]))
}
pub fn rows_iter(
&self,
) -> impl DoubleEndedIterator<Item = impl DoubleEndedIterator<Item = &T> + Clone> + Clone {
(0..self.num_rows()).map(move |row_index| {
self.row_iter(row_index)
.expect("rows_iter should never fail")
})
}
pub fn columns_iter(
&self,
) -> impl DoubleEndedIterator<Item = impl DoubleEndedIterator<Item = &T> + Clone> + Clone {
(0..self.num_columns).map(move |column_index| {
self.column_iter(column_index)
.expect("columns_iter should never fail")
})
}
pub fn as_rows(&self) -> Vec<Vec<T>>
where
T: Clone,
{
self.rows_iter()
.map(|row_iter| row_iter.cloned().collect())
.collect()
}
pub fn as_columns(&self) -> Vec<Vec<T>>
where
T: Clone,
{
self.columns_iter()
.map(|column_iter| column_iter.cloned().collect())
.collect()
}
pub fn as_row_major(&self) -> Vec<T>
where
T: Clone,
{
self.elements_row_major_iter().cloned().collect()
}
pub fn as_column_major(&self) -> Vec<T>
where
T: Clone,
{
self.elements_column_major_iter().cloned().collect()
}
pub fn indices_row_major(&self) -> impl DoubleEndedIterator<Item = (usize, usize)> + Clone {
indices_row_major(self.num_rows, self.num_columns)
}
pub fn indices_column_major(&self) -> impl DoubleEndedIterator<Item = (usize, usize)> + Clone {
indices_column_major(self.num_rows, self.num_columns)
}
pub fn enumerate_row_major(
&self,
) -> impl DoubleEndedIterator<Item = ((usize, usize), &T)> + Clone {
self.indices_row_major().map(move |i| (i, &self[i]))
}
pub fn enumerate_column_major(
&self,
) -> impl DoubleEndedIterator<Item = ((usize, usize), &T)> + Clone {
self.indices_column_major().map(move |i| (i, &self[i]))
}
fn get_index(&self, row: usize, column: usize) -> Option<usize> {
if row < self.num_rows && column < self.num_columns {
Some(row * self.row_len() + column)
} else {
None
}
}
}
impl<T> Index<(usize, usize)> for Array2D<T> {
type Output = T;
fn index(&self, (row, column): (usize, usize)) -> &Self::Output {
self.get(row, column)
.unwrap_or_else(|| panic!("Index indices {}, {} out of bounds", row, column))
}
}
impl<T> IndexMut<(usize, usize)> for Array2D<T> {
fn index_mut(&mut self, (row, column): (usize, usize)) -> &mut Self::Output {
self.get_mut(row, column)
.unwrap_or_else(|| panic!("Index mut indices {}, {} out of bounds", row, column))
}
}
fn flatten<T: Clone>(nested: &[Vec<T>]) -> Vec<T> {
nested.iter().flat_map(|row| row.clone()).collect()
}
fn indices_row_major(
num_rows: usize,
num_columns: usize,
) -> impl DoubleEndedIterator<Item = (usize, usize)> + Clone {
(0..num_rows).flat_map(move |row| (0..num_columns).map(move |column| (row, column)))
}
fn indices_column_major(
num_rows: usize,
num_columns: usize,
) -> impl DoubleEndedIterator<Item = (usize, usize)> + Clone {
(0..num_columns).flat_map(move |column| (0..num_rows).map(move |row| (row, column)))
}