#![warn(clippy::all, clippy::pedantic, clippy::nursery)] | |
/*! | |
# Two Dimensional Grid | |
Continuous growable 2D data structure. | |
The purpose of this crate is to provide an universal data structure that is faster, | |
uses less memory, and is easier to use than a naive `Vec<Vec<T>>` solution. | |
This crate will always provide a 2D data structure. If you need three or more dimensions take a look at the | |
[ndarray](https://docs.rs/ndarray/0.13.0/ndarray/) library. The `grid` crate is a container for all kind of data. | |
If you need to perform matrix operations, you are better off with a linear algebra lib, such as | |
[cgmath](https://docs.rs/cgmath/0.17.0/cgmath/) or [nalgebra](https://docs.rs/nalgebra/0.21.0/nalgebra/). | |
No other dependencies except for the std lib are used. | |
Most of the functions `std::Vec<T>` offer are also implemented in `grid` and slightly modified for a 2D data object. | |
# Memory layout | |
Similar to *C-like* arrays, `grid` uses a flat 1D `Vec<T>` data structure to have a continuous | |
memory data layout. See also [this](https://stackoverflow.com/questions/17259877/1d-or-2d-array-whats-faster) | |
explanation of why you should probably use a one-dimensional array approach. | |
Note that this crate uses a [*row-major*](https://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays) memory layout by default. | |
If you need a specific memory layout, please seek the `*_with_order` constructors. You should also take note that some transformation methods | |
change the internal memory layout, like [`transpose`](Grid::transpose). | |
This choice is important, because operations on rows are faster with a row-major memory layout. | |
Likewise, operations on columns are faster with column-major memory layout. | |
# Examples | |
``` | |
use grid::*; | |
let mut grid = grid![[1,2,3] | |
[4,5,6]]; | |
assert_eq!(grid, Grid::from_vec(vec![1,2,3,4,5,6],3)); | |
assert_eq!(grid.get(0, 2), Some(&3)); | |
assert_eq!(grid[(1, 1)], 5); | |
assert_eq!(grid.size(), (2, 3)); | |
grid.push_row(vec![7,8,9]); | |
assert_eq!(grid, grid![[1,2,3][4,5,6][7,8,9]]) | |
``` | |
*/ | |
#![cfg_attr(not(feature = "std"), no_std)] | |
#[cfg(not(feature = "std"))] | |
extern crate alloc; | |
#[cfg(not(feature = "std"))] | |
use alloc::{format, vec, vec::Vec}; | |
#[cfg(feature = "serde")] | |
use serde::{ | |
de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor}, | |
ser::{Serialize, SerializeStruct, Serializer}, | |
}; | |
use core::cmp::Eq; | |
use core::fmt; | |
use core::hash; | |
use core::iter::StepBy; | |
use core::ops::Index; | |
use core::ops::IndexMut; | |
use core::slice::Iter; | |
use core::slice::IterMut; | |
use core::{cmp, convert::TryInto}; | |
#[doc(hidden)] | |
#[macro_export] | |
macro_rules! count { | |
() => (0usize); | |
( $x:tt $($xs:tt)* ) => (1usize + $crate::count!($($xs)*)); | |
} | |
/// Init a grid with values. | |
/// | |
/// Each array within `[]` represents a row starting from top to button. | |
/// | |
/// # Examples | |
/// | |
/// In this example a grid of numbers from 1 to 9 is created: | |
/// | |
/// | |
/// ``` | |
/// use grid::grid; | |
/// let grid = grid![[1, 2, 3] | |
/// [4, 5, 6] | |
/// [7, 8, 9]]; | |
/// assert_eq!(grid.size(), (3, 3)) | |
/// ``` | |
/// | |
/// Note that each row must be of the same length. The following example will not compile: | |
/// | |
/// ``` ignore | |
/// use grid::grid; | |
/// let grid = grid![[1, 2, 3] | |
/// [4, 5] // This does not work! | |
/// [7, 8, 9]]; | |
/// ``` | |
#[macro_export] | |
macro_rules! grid { | |
() => { | |
$crate::Grid::from_vec(vec![], 0) | |
}; | |
( [$( $x:expr ),* ]) => { { | |
let vec = vec![$($x),*]; | |
let len = vec.len(); | |
$crate::Grid::from_vec(vec, len) | |
} }; | |
( [$( $x0:expr ),*] $([$( $x:expr ),*])* ) => { | |
{ | |
let mut _assert_width0 = [(); $crate::count!($($x0)*)]; | |
let cols = $crate::count!($($x0)*); | |
let rows = 1usize; | |
$( | |
let _assert_width = [(); $crate::count!($($x)*)]; | |
_assert_width0 = _assert_width; | |
let rows = rows + 1usize; | |
)* | |
let mut vec = Vec::with_capacity(rows.checked_mul(cols).unwrap()); | |
$( vec.push($x0); )* | |
$( $( vec.push($x); )* )* | |
$crate::Grid::from_vec(vec, cols) | |
} | |
}; | |
} | |
/// Init a column-major grid with values. | |
/// | |
/// Each array within `[]` represents a row starting from top to button. | |
/// | |
/// # Examples | |
/// | |
/// In this example a grid of numbers from 1 to 9 is created: | |
/// | |
/// ``` | |
/// use grid::grid_cm; | |
/// let grid = grid_cm![[1, 2, 3] | |
/// [4, 5, 6] | |
/// [7, 8, 9]]; | |
/// assert_eq!(grid.size(), (3, 3)); | |
/// assert_eq!(grid[(1, 1)], 5); | |
/// ``` | |
/// | |
/// Note that each row must be of the same length. The following example will not compile: | |
/// | |
/// ``` ignore | |
/// use grid::grid_cm; | |
/// let grid = grid_cm![[1, 2, 3] | |
/// [4, 5] // This does not work! | |
/// [7, 8, 9]]; | |
/// ``` | |
#[macro_export] | |
macro_rules! grid_cm { | |
() => { | |
$crate::Grid::from_vec_with_order(vec![], 0, $crate::Order::ColumnMajor) | |
}; | |
( [$( $x:expr ),* ]) => { { | |
let vec = vec![$($x),*]; | |
let len = vec.len(); | |
$crate::Grid::from_vec_with_order(vec, len, $crate::Order::ColumnMajor) | |
} }; | |
( [$( $x0:expr ),*] $([$( $x:expr ),*])* ) => { | |
{ | |
let mut _assert_width0 = [(); $crate::count!($($x0)*)]; | |
let cols = $crate::count!($($x0)*); | |
let rows = 1usize; | |
$( | |
let _assert_width = [(); $crate::count!($($x)*)]; | |
_assert_width0 = _assert_width; | |
let rows = rows + 1usize; | |
)* | |
let vec = Vec::with_capacity(rows.checked_mul(cols).unwrap()); | |
let mut grid = $crate::Grid::from_vec_with_order(vec, cols, $crate::Order::ColumnMajor); | |
grid.push_row(vec![$($x0),*]); | |
$( grid.push_row(vec![$($x),*]); )* | |
grid | |
} | |
}; | |
} | |
/// Define the internal memory layout of the grid. | |
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] | |
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] | |
pub enum Order { | |
/// The data is ordered row by row. | |
#[default] | |
RowMajor, | |
/// The data is ordered column by column. | |
ColumnMajor, | |
} | |
impl Order { | |
const fn counterpart(self) -> Self { | |
match self { | |
Self::RowMajor => Self::ColumnMajor, | |
Self::ColumnMajor => Self::RowMajor, | |
} | |
} | |
} | |
/// Stores elements of a certain type in a 2D grid structure. | |
/// | |
/// Uses a rust `Vec<T>` type to reference the grid data on the heap. | |
/// Also the internal memory layout as well as the number of | |
/// rows and columns are stored in the grid data structure. | |
/// | |
/// The size limit of a grid is `rows * cols < usize`. | |
pub struct Grid<T> { | |
data: Vec<T>, | |
cols: usize, | |
rows: usize, | |
order: Order, | |
} | |
#[cfg(feature = "serde")] | |
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Grid<T> { | |
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | |
where | |
D: Deserializer<'de>, | |
{ | |
use std::marker::PhantomData; | |
#[derive(serde::Deserialize)] | |
#[serde(field_identifier, rename_all = "lowercase")] | |
enum Field { | |
Data, | |
Cols, | |
Order, | |
} | |
struct GridVisitor<T> { | |
_p: PhantomData<T>, | |
} | |
impl<'de, T: Deserialize<'de>> Visitor<'de> for GridVisitor<T> { | |
type Value = Grid<T>; | |
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | |
formatter.write_str("struct Grid") | |
} | |
fn visit_seq<V>(self, mut seq: V) -> Result<Grid<T>, V::Error> | |
where | |
V: SeqAccess<'de>, | |
{ | |
let cols = seq | |
.next_element()? | |
.ok_or_else(|| de::Error::invalid_length(0, &self))?; | |
let data = seq | |
.next_element()? | |
.ok_or_else(|| de::Error::invalid_length(1, &self))?; | |
let order = seq.next_element()?.unwrap_or_default(); | |
Ok(Grid::from_vec_with_order(data, cols, order)) | |
} | |
fn visit_map<V>(self, mut map: V) -> Result<Grid<T>, V::Error> | |
where | |
V: MapAccess<'de>, | |
{ | |
let mut cols = None; | |
let mut data = None; | |
let mut order = None; | |
while let Some(key) = map.next_key()? { | |
match key { | |
Field::Data => { | |
if data.is_some() { | |
return Err(de::Error::duplicate_field("data")); | |
} | |
data = Some(map.next_value()?); | |
} | |
Field::Cols => { | |
if cols.is_some() { | |
return Err(de::Error::duplicate_field("cols")); | |
} | |
cols = Some(map.next_value()?); | |
} | |
Field::Order => { | |
if order.is_some() { | |
return Err(de::Error::duplicate_field("order")); | |
} | |
order = Some(map.next_value()?); | |
} | |
} | |
} | |
let cols = cols.ok_or_else(|| de::Error::missing_field("cols"))?; | |
let data = data.ok_or_else(|| de::Error::missing_field("data"))?; | |
let order = order.unwrap_or_default(); | |
Ok(Grid::from_vec_with_order(data, cols, order)) | |
} | |
} | |
const FIELDS: &[&str] = &["cols", "data", "order"]; | |
deserializer.deserialize_struct("Grid", FIELDS, GridVisitor { _p: PhantomData }) | |
} | |
} | |
#[cfg(feature = "serde")] | |
impl<T: Serialize> Serialize for Grid<T> { | |
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | |
where | |
S: Serializer, | |
{ | |
// 3 is the number of fields in the struct. | |
let mut state = serializer.serialize_struct("Grid", 3)?; | |
state.serialize_field("cols", &self.cols)?; | |
state.serialize_field("data", &self.data)?; | |
state.serialize_field("order", &self.order)?; | |
state.end() | |
} | |
} | |
impl<T> Grid<T> { | |
/// Init a grid of size rows x columns with default values of the given type. | |
/// For example this will generate a 2x3 grid of zeros: | |
/// | |
/// ``` | |
/// use grid::Grid; | |
/// let grid : Grid<u8> = Grid::new(2,3); | |
/// assert_eq!(grid[(0, 0)], 0); | |
/// ``` | |
/// | |
/// If `rows == 0` or `cols == 0` the grid will be empty with no cols and rows. | |
/// | |
/// This create a grid with a row-major memory layout. | |
/// If you need a column-major one, see [`new_with_order`](Grid::new_with_order). | |
/// | |
/// # Panics | |
/// | |
/// Panics if `rows * cols > usize::MAX`. | |
#[must_use] | |
#[inline] | |
pub fn new(rows: usize, cols: usize) -> Self | |
where | |
T: Default, | |
{ | |
Self::new_with_order(rows, cols, Order::default()) | |
} | |
/// Same as [`new`](Self::new) but with a specific [`Order`]. | |
/// | |
/// # Panics | |
/// | |
/// Panics if `rows * cols > usize::MAX`. | |
pub fn new_with_order(rows: usize, cols: usize, order: Order) -> Self | |
where | |
T: Default, | |
{ | |
if rows == 0 || cols == 0 { | |
return Self { | |
data: Vec::new(), | |
rows: 0, | |
cols: 0, | |
order, | |
}; | |
} | |
let mut data = Vec::new(); | |
data.resize_with(rows.checked_mul(cols).unwrap(), T::default); | |
Self { | |
data, | |
cols, | |
rows, | |
order, | |
} | |
} | |
/// Init a grid of size rows x columns with the given data element. | |
/// | |
/// If `rows == 0` or `cols == 0` the grid will be empty with no cols and rows. | |
/// | |
/// This create a grid with a row-major memory layout. | |
/// If you need a column-major one, see [`init_with_order`](Grid::init_with_order). | |
/// | |
/// # Panics | |
/// | |
/// Panics if `rows * cols > usize::MAX`. | |
#[inline] | |
pub fn init(rows: usize, cols: usize, data: T) -> Self | |
where | |
T: Clone, | |
{ | |
Self::init_with_order(rows, cols, Order::default(), data) | |
} | |
/// Same as [`init`](Self::init) but with a specific [`Order`]. | |
/// | |
/// # Panics | |
/// | |
/// Panics if `rows * cols > usize::MAX`. | |
pub fn init_with_order(rows: usize, cols: usize, order: Order, data: T) -> Self | |
where | |
T: Clone, | |
{ | |
if rows == 0 || cols == 0 { | |
return Self { | |
data: Vec::new(), | |
rows: 0, | |
cols: 0, | |
order, | |
}; | |
} | |
Self { | |
data: vec![data; rows.checked_mul(cols).unwrap()], | |
cols, | |
rows, | |
order, | |
} | |
} | |
/// Initialises an empty Grid with the capacity to store `cols * rows` elements. | |
/// Similar to `Vec::with_capacity`. | |
/// | |
/// # Panics | |
/// | |
/// Panics if `rows * cols > usize::MAX` or if `rows * cols * size_of::<T>() > isize::MAX` | |
#[must_use] | |
pub fn with_capacity(rows: usize, cols: usize) -> Self { | |
Self::with_capacity_and_order(rows, cols, Order::default()) | |
} | |
/// Same as [`with_capacity`](Self::with_capacity) but with a specified [`Order`] | |
/// | |
/// # Panics | |
/// | |
/// Panics if `rows * cols > usize::MAX` or if `rows * cols * size_of::<T>() > isize::MAX` | |
#[must_use] | |
pub fn with_capacity_and_order(rows: usize, cols: usize, order: Order) -> Self { | |
Self { | |
data: Vec::with_capacity(rows.checked_mul(cols).unwrap()), | |
cols: 0, | |
rows: 0, | |
order, | |
} | |
} | |
/// Returns a grid from a vector with a given column length. | |
/// The length of `vec` must be a multiple of `cols`. | |
/// | |
/// This create a grid with a row-major memory layout. | |
/// If you need a column-major one, see [`from_vec_with_order`](Grid::from_vec_with_order). | |
/// | |
/// For example: | |
/// | |
/// ``` | |
/// use grid::Grid; | |
/// let grid = Grid::from_vec(vec![1,2,3,4,5,6], 3); | |
/// assert_eq!(grid.size(), (2, 3)); | |
/// ``` | |
/// | |
/// will create a grid with the following layout: | |
/// \[1,2,3\] | |
/// \[4,5,6\] | |
/// | |
/// This example will fail, because `vec.len()` is not a multiple of `cols`: | |
/// | |
/// ``` should_panic | |
/// use grid::Grid; | |
/// Grid::from_vec(vec![1,2,3,4,5], 3); | |
/// ``` | |
/// | |
/// # Panics | |
/// | |
/// This panics if the vector length isn't a multiple of the number of columns. | |
#[must_use] | |
#[inline] | |
pub fn from_vec(vec: Vec<T>, cols: usize) -> Self { | |
Self::from_vec_with_order(vec, cols, Order::default()) | |
} | |
/// Same as [`from_vec`](Self::from_vec) but with a specific [`Order`]. | |
/// | |
/// # Panics | |
/// | |
/// This panics if the vector length isn't a multiple of the number of columns. | |
#[must_use] | |
pub fn from_vec_with_order(vec: Vec<T>, cols: usize, order: Order) -> Self { | |
let rows = vec.len().checked_div(cols).unwrap_or(0); | |
assert_eq!( | |
rows * cols, | |
vec.len(), | |
"Vector length {:?} should be a multiple of cols = {:?}", | |
vec.len(), | |
cols | |
); | |
if rows == 0 || cols == 0 { | |
Self { | |
data: vec, | |
rows: 0, | |
cols: 0, | |
order, | |
} | |
} else { | |
Self { | |
data: vec, | |
rows, | |
cols, | |
order, | |
} | |
} | |
} | |
/// Returns the index of the coordinates in the internal vector. | |
#[inline] | |
#[must_use] | |
const fn get_index(&self, row: usize, col: usize) -> usize { | |
match self.order { | |
Order::RowMajor => row * self.cols + col, | |
Order::ColumnMajor => col * self.rows + row, | |
} | |
} | |
/// Returns a reference to an element, without performing bound checks. | |
/// Generally not recommended, use with caution! | |
/// | |
/// # Safety | |
/// | |
/// Calling this method with an out-of-bounds index is undefined behavior even if the resulting reference is not used. | |
#[inline] | |
#[must_use] | |
pub unsafe fn get_unchecked(&self, row: impl Into<usize>, col: impl Into<usize>) -> &T { | |
let index = self.get_index(row.into(), col.into()); | |
self.data.get_unchecked(index) | |
} | |
/// Returns a mutable reference to an element, without performing bound checks. | |
/// Generally not recommended, use with caution! | |
/// | |
/// # Safety | |
/// | |
/// Calling this method with an out-of-bounds index is undefined behavior even if the resulting reference is not used. | |
#[inline] | |
#[must_use] | |
pub unsafe fn get_unchecked_mut( | |
&mut self, | |
row: impl Into<usize>, | |
col: impl Into<usize>, | |
) -> &mut T { | |
let index = self.get_index(row.into(), col.into()); | |
self.data.get_unchecked_mut(index) | |
} | |
/// Access a certain element in the grid. | |
/// Returns `None` if an element beyond the grid bounds is tried to be accessed. | |
#[must_use] | |
pub fn get(&self, row: impl TryInto<usize>, col: impl TryInto<usize>) -> Option<&T> { | |
let row_usize = row.try_into().ok()?; | |
let col_usize = col.try_into().ok()?; | |
if row_usize < self.rows && col_usize < self.cols { | |
unsafe { Some(self.get_unchecked(row_usize, col_usize)) } | |
} else { | |
None | |
} | |
} | |
/// Mutable access to a certain element in the grid. | |
/// Returns `None` if an element beyond the grid bounds is tried to be accessed. | |
#[must_use] | |
pub fn get_mut( | |
&mut self, | |
row: impl TryInto<usize>, | |
col: impl TryInto<usize>, | |
) -> Option<&mut T> { | |
let row_usize = row.try_into().ok()?; | |
let col_usize = col.try_into().ok()?; | |
if row_usize < self.rows && col_usize < self.cols { | |
unsafe { Some(self.get_unchecked_mut(row_usize, col_usize)) } | |
} else { | |
None | |
} | |
} | |
/// Returns the size of the grid as a two element tuple. | |
/// First element are the number of rows and the second the columns. | |
#[must_use] | |
pub const fn size(&self) -> (usize, usize) { | |
(self.rows, self.cols) | |
} | |
/// Returns the number of rows of the grid. | |
#[must_use] | |
pub const fn rows(&self) -> usize { | |
self.rows | |
} | |
/// Returns the number of columns of the grid. | |
#[must_use] | |
pub const fn cols(&self) -> usize { | |
self.cols | |
} | |
/// Returns the internal memory layout of the grid. | |
#[must_use] | |
pub const fn order(&self) -> Order { | |
self.order | |
} | |
/// Returns `true` if the grid contains no elements. | |
/// For example: | |
/// ``` | |
/// use grid::*; | |
/// let grid : Grid<u8> = grid![]; | |
/// assert!(grid.is_empty()); | |
/// ``` | |
#[must_use] | |
pub fn is_empty(&self) -> bool { | |
self.data.is_empty() | |
} | |
/// Clears the grid. | |
/// | |
/// This doesn't change the grid order. | |
pub fn clear(&mut self) { | |
self.rows = 0; | |
self.cols = 0; | |
self.data.clear(); | |
} | |
/// Returns an iterator over the whole grid, starting from the first row and column. | |
/// | |
/// The iteration order is dependant on the internal memory layout. | |
/// If you need a specific order, see [`iter_rows`](Grid::iter_rows) or | |
/// [`iter_cols`](Grid::iter_cols). | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let grid: Grid<u8> = grid![[1,2][3,4]]; | |
/// let mut iter = grid.iter(); | |
/// assert_eq!(iter.next(), Some(&1)); | |
/// assert_eq!(iter.next(), Some(&2)); | |
/// assert_eq!(iter.next(), Some(&3)); | |
/// assert_eq!(iter.next(), Some(&4)); | |
/// assert_eq!(iter.next(), None); | |
/// ``` | |
pub fn iter(&self) -> Iter<T> { | |
self.data.iter() | |
} | |
/// Returns an mutable iterator over the whole grid that allows modifying each value. | |
/// | |
/// The iteration order is dependant on the internal memory layout. | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid: Grid<u8> = grid![[1,2][3,4]]; | |
/// let mut iter = grid.iter_mut(); | |
/// let next = iter.next(); | |
/// assert_eq!(next, Some(&mut 1)); | |
/// *next.unwrap() = 10; | |
/// ``` | |
pub fn iter_mut(&mut self) -> IterMut<T> { | |
self.data.iter_mut() | |
} | |
/// Returns an iterator over a column. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let grid: Grid<u8> = grid![[1, 2, 3][3, 4, 5]]; | |
/// let mut col_iter = grid.iter_col(1); | |
/// assert_eq!(col_iter.next(), Some(&2)); | |
/// assert_eq!(col_iter.next(), Some(&4)); | |
/// assert_eq!(col_iter.next(), None); | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a row-major memory layout, | |
/// which is the default. | |
/// | |
/// # Panics | |
/// | |
/// Panics if the col index is out of bounds. | |
pub fn iter_col(&self, col: usize) -> StepBy<Iter<T>> { | |
assert!( | |
col < self.cols, | |
"out of bounds. Column must be less than {:?}, but is {:?}", | |
self.cols, | |
col | |
); | |
match self.order { | |
Order::RowMajor => self.data[col..].iter().step_by(self.cols), | |
Order::ColumnMajor => { | |
let start = col * self.rows; | |
self.data[start..(start + self.rows)].iter().step_by(1) | |
} | |
} | |
} | |
/// Returns a mutable iterator over a column. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid: Grid<u8> = grid![[1, 2, 3][3, 4, 5]]; | |
/// let mut col_iter = grid.iter_col_mut(1); | |
/// let next = col_iter.next(); | |
/// assert_eq!(next, Some(&mut 2)); | |
/// *next.unwrap() = 10; | |
/// assert_eq!(grid[(0, 1)], 10); | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a row-major memory layout, | |
/// which is the default. | |
/// | |
/// # Panics | |
/// | |
/// Panics if the col index is out of bounds. | |
pub fn iter_col_mut(&mut self, col: usize) -> StepBy<IterMut<T>> { | |
assert!( | |
col < self.cols, | |
"out of bounds. Column must be less than {:?}, but is {:?}", | |
self.cols, | |
col | |
); | |
match self.order { | |
Order::RowMajor => self.data[col..].iter_mut().step_by(self.cols), | |
Order::ColumnMajor => { | |
let start = col * self.rows; | |
self.data[start..(start + self.rows)].iter_mut().step_by(1) | |
} | |
} | |
} | |
/// Returns an iterator over a row. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let grid: Grid<u8> = grid![[1, 2, 3][3, 4, 5]]; | |
/// let mut col_iter = grid.iter_row(1); | |
/// assert_eq!(col_iter.next(), Some(&3)); | |
/// assert_eq!(col_iter.next(), Some(&4)); | |
/// assert_eq!(col_iter.next(), Some(&5)); | |
/// assert_eq!(col_iter.next(), None); | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a column-major memory layout. | |
/// | |
/// # Panics | |
/// | |
/// Panics if the row index is out of bounds. | |
pub fn iter_row(&self, row: usize) -> StepBy<Iter<T>> { | |
assert!( | |
row < self.rows, | |
"out of bounds. Row must be less than {:?}, but is {:?}", | |
self.rows, | |
row | |
); | |
match self.order { | |
Order::RowMajor => { | |
let start = row * self.cols; | |
self.data[start..(start + self.cols)].iter().step_by(1) | |
} | |
Order::ColumnMajor => self.data[row..].iter().step_by(self.rows), | |
} | |
} | |
/// Returns a mutable iterator over a row. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid: Grid<u8> = grid![[1, 2, 3][3, 4, 5]]; | |
/// let mut col_iter = grid.iter_row_mut(1); | |
/// let next = col_iter.next(); | |
/// *next.unwrap() = 10; | |
/// assert_eq!(grid[(1, 0)], 10); | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a column-major memory layout. | |
/// | |
/// # Panics | |
/// | |
/// Panics if the row index is out of bounds. | |
pub fn iter_row_mut(&mut self, row: usize) -> StepBy<IterMut<T>> { | |
assert!( | |
row < self.rows, | |
"out of bounds. Row must be less than {:?}, but is {:?}", | |
self.rows, | |
row | |
); | |
match self.order { | |
Order::RowMajor => { | |
let start = row * self.cols; | |
self.data[start..(start + self.cols)].iter_mut().step_by(1) | |
} | |
Order::ColumnMajor => self.data[row..].iter_mut().step_by(self.rows), | |
} | |
} | |
/// Traverse the grid with row and column indexes. | |
/// | |
/// The iteration order is dependent on the internal memory layout, | |
/// but the indexes will be accurate either way. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let grid: Grid<u8> = grid![[1,2][3,4]]; | |
/// let mut iter = grid.indexed_iter(); | |
/// assert_eq!(iter.next(), Some(((0, 0), &1))); | |
/// ``` | |
/// | |
/// Or simply unpack in a `for` loop: | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let grid: Grid<u8> = grid![[1,2][3,4]]; | |
/// for ((row, col), i) in grid.indexed_iter() { | |
/// println!("value at row {row} and column {col} is: {i}"); | |
/// } | |
/// ``` | |
pub fn indexed_iter(&self) -> impl Iterator<Item = ((usize, usize), &T)> { | |
self.data.iter().enumerate().map(move |(idx, i)| { | |
let position = match self.order { | |
Order::RowMajor => (idx / self.cols, idx % self.cols), | |
Order::ColumnMajor => (idx % self.rows, idx / self.rows), | |
}; | |
(position, i) | |
}) | |
} | |
/// Traverse the grid with row and column indexes, | |
/// and mutable access to each element. | |
/// | |
/// The iteration order is dependent on the internal memory layout, | |
/// but the indexes will be accurate either way. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid: Grid<u8> = grid![[1,2][3,4]]; | |
/// let mut iter = grid.indexed_iter_mut(); | |
/// assert_eq!(iter.next(), Some(((0, 0), &mut 1))); | |
/// ``` | |
/// | |
/// Or simply unpack in a `for` loop: | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid: Grid<u8> = grid![[1,2][3,4]]; | |
/// for ((row, col), i) in grid.indexed_iter_mut() { | |
/// *i += 1; | |
/// println!("value at row {row} and column {col} is: {i}"); | |
/// } | |
/// | |
/// assert_eq!(grid[(0, 0)], 2); | |
/// assert_eq!(grid[(0, 1)], 3); | |
/// assert_eq!(grid[(1, 0)], 4); | |
/// assert_eq!(grid[(1, 1)], 5); | |
/// ``` | |
pub fn indexed_iter_mut(&mut self) -> impl Iterator<Item = ((usize, usize), &mut T)> { | |
let order = self.order; | |
let cols = self.cols; | |
let rows = self.rows; | |
self.data.iter_mut().enumerate().map(move |(idx, i)| { | |
let position = match order { | |
Order::RowMajor => (idx / cols, idx % cols), | |
Order::ColumnMajor => (idx % rows, idx / rows), | |
}; | |
(position, i) | |
}) | |
} | |
/// Add a new row to the grid. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid: Grid<u8> = grid![[1, 2, 3][3, 4, 5]]; | |
/// let row = vec![6,7,8]; | |
/// grid.push_row(row); | |
/// assert_eq!(grid.rows(), 3); | |
/// assert_eq!(grid[(2, 0)], 6); | |
/// assert_eq!(grid[(2, 1)], 7); | |
/// assert_eq!(grid[(2, 2)], 8); | |
/// ``` | |
/// | |
/// Can also be used to init an empty grid: | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid: Grid<u8> = grid![]; | |
/// let row = vec![1,2,3]; | |
/// grid.push_row(row); | |
/// assert_eq!(grid.size(), (1, 3)); | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a column-major memory layout. | |
/// | |
/// # Panics | |
/// | |
/// Panics if: | |
/// - the grid is not empty and `row.len() != grid.cols()` | |
/// - `row.len() == 0` | |
pub fn push_row(&mut self, row: Vec<T>) { | |
assert_ne!(row.len(), 0); | |
assert!( | |
!(self.rows > 0 && row.len() != self.cols), | |
"pushed row does not match. Length must be {:?}, but was {:?}.", | |
self.cols, | |
row.len() | |
); | |
self.data.extend(row); | |
if self.order == Order::ColumnMajor { | |
for i in (1..self.cols).rev() { | |
let col_idx = i * self.rows; | |
self.data[col_idx..col_idx + self.rows + i].rotate_right(i); | |
} | |
} | |
self.rows += 1; | |
if self.cols == 0 { | |
self.cols = self.data.len(); | |
} | |
} | |
/// Add a new column to the grid. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid: Grid<u8> = grid![[1, 2, 3][3, 4, 5]]; | |
/// let col = vec![4,6]; | |
/// grid.push_col(col); | |
/// assert_eq!(grid.cols(), 4); | |
/// assert_eq!(grid[(0, 3)], 4); | |
/// assert_eq!(grid[(1, 3)], 6); | |
/// ``` | |
/// | |
/// Can also be used to init an empty grid: | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid: Grid<u8> = grid![]; | |
/// let col = vec![1,2,3]; | |
/// grid.push_col(col); | |
/// assert_eq!(grid.size(), (3, 1)); | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a row-major memory layout, | |
/// which is the default. | |
/// | |
/// # Panics | |
/// | |
/// Panics if: | |
/// - the grid is not empty and `col.len() != grid.rows()` | |
/// - `col.len() == 0` | |
pub fn push_col(&mut self, col: Vec<T>) { | |
assert_ne!(col.len(), 0); | |
assert!( | |
!(self.cols > 0 && col.len() != self.rows), | |
"pushed column does not match. Length must be {:?}, but was {:?}.", | |
self.rows, | |
col.len() | |
); | |
self.data.extend(col); | |
if self.order == Order::RowMajor { | |
for i in (1..self.rows).rev() { | |
let row_idx = i * self.cols; | |
self.data[row_idx..row_idx + self.cols + i].rotate_right(i); | |
} | |
} | |
self.cols += 1; | |
if self.rows == 0 { | |
self.rows = self.data.len(); | |
} | |
} | |
/// Removes the last row from a grid and returns it, or None if it is empty. | |
/// | |
/// # Examples | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2,3][4,5,6]]; | |
/// assert_eq![grid.pop_row(), Some(vec![4,5,6])]; | |
/// assert_eq![grid.pop_row(), Some(vec![1,2,3])]; | |
/// assert_eq![grid.pop_row(), None]; | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a column-major memory layout. | |
pub fn pop_row(&mut self) -> Option<Vec<T>> { | |
if self.rows == 0 { | |
return None; | |
} | |
if self.order == Order::ColumnMajor { | |
for i in 1..self.cols { | |
let col_idx = i * (self.rows - 1); | |
self.data[col_idx..col_idx + self.rows + i - 1].rotate_left(i); | |
} | |
} | |
let row = self.data.split_off(self.data.len() - self.cols); | |
self.rows -= 1; | |
if self.rows == 0 { | |
self.cols = 0; | |
} | |
Some(row) | |
} | |
/// Remove a Row at the index and return a vector of it. | |
/// | |
/// # Examples | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2][3,4][5,6]]; | |
/// assert_eq![grid.remove_row(1), Some(vec![3,4])]; | |
/// assert_eq![grid.remove_row(0), Some(vec![1,2])]; | |
/// assert_eq![grid.remove_row(0), Some(vec![5,6])]; | |
/// assert_eq![grid.remove_row(0), None]; | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a column-major memory layout. | |
pub fn remove_row(&mut self, row_index: usize) -> Option<Vec<T>> { | |
if self.cols == 0 || self.rows == 0 || row_index >= self.rows { | |
return None; | |
} | |
let row = match self.order { | |
Order::RowMajor => self | |
.data | |
.drain((row_index * self.cols)..((row_index + 1) * self.cols)) | |
.collect(), | |
Order::ColumnMajor => { | |
for i in 0..self.cols { | |
let col_idx = row_index + i * (self.rows - 1); | |
let end = cmp::min(col_idx + self.rows + i, self.data.len()); | |
self.data[col_idx..end].rotate_left(i + 1); | |
} | |
self.data.split_off(self.data.len() - self.cols) | |
} | |
}; | |
self.rows -= 1; | |
if self.rows == 0 { | |
self.cols = 0; | |
} | |
Some(row) | |
} | |
/// Removes the last column from a grid and returns it, or None if it is empty. | |
/// | |
/// Note that this operation is much slower than the `pop_row()` because the memory layout | |
/// of `Grid` is row-major and removing a column requires a lot of move operations. | |
/// | |
/// # Examples | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2,3][4,5,6]]; | |
/// assert_eq![grid.pop_col(), Some(vec![3,6])]; | |
/// assert_eq![grid.pop_col(), Some(vec![2,5])]; | |
/// assert_eq![grid.pop_col(), Some(vec![1,4])]; | |
/// assert_eq![grid.pop_col(), None]; | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a row-major memory layout, | |
/// which is the default. | |
pub fn pop_col(&mut self) -> Option<Vec<T>> { | |
if self.cols == 0 { | |
return None; | |
} | |
if self.order == Order::RowMajor { | |
for i in 1..self.rows { | |
let row_idx = i * (self.cols - 1); | |
self.data[row_idx..row_idx + self.cols + i - 1].rotate_left(i); | |
} | |
} | |
let col = self.data.split_off(self.data.len() - self.rows); | |
self.cols -= 1; | |
if self.cols == 0 { | |
self.rows = 0; | |
} | |
Some(col) | |
} | |
/// Remove a column at the index and return a vector of it. | |
/// | |
/// # Examples | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2,3,4][5,6,7,8][9,10,11,12][13,14,15,16]]; | |
/// assert_eq![grid.remove_col(3), Some(vec![4,8,12,16])]; | |
/// assert_eq![grid.remove_col(0), Some(vec![1,5,9,13])]; | |
/// assert_eq![grid.remove_col(1), Some(vec![3,7,11,15])]; | |
/// assert_eq![grid.remove_col(0), Some(vec![2,6,10,14])]; | |
/// assert_eq![grid.remove_col(0), None]; | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a row-major memory layout, | |
/// which is the default. | |
pub fn remove_col(&mut self, col_index: usize) -> Option<Vec<T>> { | |
if self.cols == 0 || self.rows == 0 || col_index >= self.cols { | |
return None; | |
} | |
let col = match self.order { | |
Order::RowMajor => { | |
for i in 0..self.rows { | |
let row_idx = col_index + i * (self.cols - 1); | |
let end = cmp::min(row_idx + self.cols + i, self.data.len()); | |
self.data[row_idx..end].rotate_left(i + 1); | |
} | |
self.data.split_off(self.data.len() - self.rows) | |
} | |
Order::ColumnMajor => self | |
.data | |
.drain((col_index * self.rows)..((col_index + 1) * self.rows)) | |
.collect(), | |
}; | |
self.cols -= 1; | |
if self.cols == 0 { | |
self.rows = 0; | |
} | |
Some(col) | |
} | |
/// Insert a new row at the index and shifts all rows after down. | |
/// | |
/// # Examples | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2,3][4,5,6]]; | |
/// grid.insert_row(1, vec![7,8,9]); | |
/// assert_eq!(grid, grid![[1,2,3][7,8,9][4,5,6]]); | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a column-major memory layout. | |
/// | |
/// # Panics | |
/// | |
/// Panics if: | |
/// - the grid is not empty and `row.len() != grid.cols()`. | |
/// - the index is greater than the number of rows | |
pub fn insert_row(&mut self, index: usize, row: Vec<T>) { | |
let input_len = row.len(); | |
assert!( | |
!(self.cols > 0 && input_len != self.cols), | |
"Inserted row must be of length {}, but was {}.", | |
self.cols, | |
row.len() | |
); | |
assert!( | |
index <= self.rows, | |
"Out of range. Index was {}, but must be less or equal to {}.", | |
index, | |
self.rows | |
); | |
match self.order { | |
Order::RowMajor => { | |
let data_idx = index * input_len; | |
self.data.splice(data_idx..data_idx, row); | |
} | |
Order::ColumnMajor => { | |
for (col_iter, row_val) in row.into_iter().enumerate() { | |
let data_idx = col_iter * self.rows + index + col_iter; | |
self.data.insert(data_idx, row_val); | |
} | |
} | |
} | |
self.cols = input_len; | |
self.rows += 1; | |
} | |
/// Insert a new column at the index. | |
/// | |
/// Important! Insertion of columns is a lot slower than the lines insertion. | |
/// This is because of the memory layout of the grid data structure. | |
/// | |
/// # Examples | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2,3][4,5,6]]; | |
/// grid.insert_col(1, vec![9,9]); | |
/// assert_eq!(grid, grid![[1,9,2,3][4,9,5,6]]) | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a row-major memory layout, | |
/// which is the default. | |
/// | |
/// # Panics | |
/// | |
/// Panics if: | |
/// - the grid is not empty and `col.len() != grid.rows()`. | |
/// - the index is greater than the number of columns | |
pub fn insert_col(&mut self, index: usize, col: Vec<T>) { | |
let input_len = col.len(); | |
assert!( | |
!(self.rows > 0 && input_len != self.rows), | |
"Inserted col must be of length {}, but was {}.", | |
self.rows, | |
col.len() | |
); | |
assert!( | |
index <= self.cols, | |
"Out of range. Index was {}, but must be less or equal to {}.", | |
index, | |
self.cols | |
); | |
match self.order { | |
Order::RowMajor => { | |
for (row_iter, col_val) in col.into_iter().enumerate() { | |
let data_idx = row_iter * self.cols + index + row_iter; | |
self.data.insert(data_idx, col_val); | |
} | |
} | |
Order::ColumnMajor => { | |
let data_idx = index * input_len; | |
self.data.splice(data_idx..data_idx, col); | |
} | |
} | |
self.rows = input_len; | |
self.cols += 1; | |
} | |
/// Returns a reference to the internal data structure of the grid. | |
/// | |
/// The order of the elements depends on the internal memory layout, which is | |
/// row-major by default. | |
/// | |
/// # Examples | |
/// ``` | |
/// use grid::*; | |
/// let grid = grid![[1,2,3][4,5,6]]; | |
/// let flat = grid.flatten(); | |
/// assert_eq!(flat, &vec![1,2,3,4,5,6]); | |
/// ``` | |
#[must_use] | |
pub const fn flatten(&self) -> &Vec<T> { | |
&self.data | |
} | |
/// Converts self into a vector without clones or allocation. | |
/// | |
/// The order of the elements depends on the internal memory layout, which is | |
/// row-major by default. | |
#[must_use] | |
pub fn into_vec(self) -> Vec<T> { | |
self.data | |
} | |
/// Transpose the grid so that columns become rows in new grid. | |
/// | |
/// This method changes the internal memory layout. | |
pub fn transpose(&mut self) { | |
self.order = self.order.counterpart(); | |
core::mem::swap(&mut self.rows, &mut self.cols); | |
} | |
/// Flip (or mirrors) the columns. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2,3][4,5,6]]; | |
/// grid.flip_cols(); | |
/// assert_eq!(grid, grid![[3,2,1][6,5,4]]) | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a column-major memory layout. | |
pub fn flip_cols(&mut self) { | |
match self.order { | |
Order::RowMajor => { | |
for row in 0..self.rows { | |
let idx = row * self.cols; | |
self.data[idx..idx + self.cols].reverse(); | |
} | |
} | |
Order::ColumnMajor => { | |
for col in 0..self.cols / 2 { | |
for row in 0..self.rows { | |
let cell1 = self.get_index(row, col); | |
let cell2 = self.get_index(row, self.cols - col - 1); | |
self.data.swap(cell1, cell2); | |
} | |
} | |
} | |
} | |
} | |
/// Flip (or mirrors) the rows. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2,3][4,5,6]]; | |
/// grid.flip_rows(); | |
/// assert_eq!(grid, grid![[4,5,6][1,2,3]]) | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid uses a row-major memory layout, | |
/// which is the default. | |
pub fn flip_rows(&mut self) { | |
match self.order { | |
Order::RowMajor => { | |
for row in 0..self.rows / 2 { | |
for col in 0..self.cols { | |
let cell1 = self.get_index(row, col); | |
let cell2 = self.get_index(self.rows - row - 1, col); | |
self.data.swap(cell1, cell2); | |
} | |
} | |
} | |
Order::ColumnMajor => { | |
for col in 0..self.cols { | |
let idx = col * self.rows; | |
self.data[idx..idx + self.rows].reverse(); | |
} | |
} | |
} | |
} | |
/// Rotate the grid 90° counter-clockwise. | |
/// | |
/// This method changes the internal memory layout. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2][3,4]]; | |
/// grid.rotate_left(); | |
/// assert_eq!(grid, grid![[2,4][1,3]]); | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid initialy uses a column-major memory layout, | |
/// which is the default. | |
pub fn rotate_left(&mut self) { | |
self.transpose(); | |
self.flip_rows(); | |
} | |
/// Rotate the grid 90° clockwise. | |
/// | |
/// This method changes the internal memory layout. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2][3,4]]; | |
/// grid.rotate_right(); | |
/// assert_eq!(grid, grid![[3,1][4,2]]); | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// This method will be significantly slower if the grid initialy uses a row-major memory layout, | |
/// which is the default. | |
pub fn rotate_right(&mut self) { | |
self.transpose(); | |
self.flip_cols(); | |
} | |
/// Rotate the grid 180°. | |
/// | |
/// This method **doesn't** change the internal memory layout. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2,3][4,5,6]]; | |
/// grid.rotate_half(); | |
/// assert_eq!(grid, grid![[6,5,4][3,2,1]]); | |
/// ``` | |
/// | |
/// # Performance | |
/// | |
/// The performances of this method is not affected by the internal memory layout. | |
pub fn rotate_half(&mut self) { | |
self.data.reverse(); | |
} | |
/// Fills the grid with elements by cloning `value`. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2,3][4,5,6]]; | |
/// grid.fill(7); | |
/// assert_eq!(grid, grid![[7,7,7][7,7,7]]); | |
/// ``` | |
pub fn fill(&mut self, value: T) | |
where | |
T: Clone, | |
{ | |
self.data.fill(value); | |
} | |
/// Fills the grid with elements returned by calling a closure repeatedly. | |
/// | |
/// This method uses a closure to create new values. If you'd rather | |
/// [`Clone`] a given value, use [`fill`]. If you want to use the [`Default`] | |
/// trait to generate values, you can pass [`Default::default`] as the | |
/// argument. | |
/// | |
/// [`fill`]: Grid::fill | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2,3][4,5,6]]; | |
/// grid.fill_with(Default::default); | |
/// assert_eq!(grid, grid![[0,0,0][0,0,0]]); | |
/// ``` | |
pub fn fill_with<F>(&mut self, f: F) | |
where | |
F: FnMut() -> T, | |
{ | |
self.data.fill_with(f); | |
} | |
/// Returns a new grid with the same dimensions, but with each element transformed by the closure. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let grid = grid![[1,2][3,4]]; | |
/// let new_grid = grid.map(|x| x * 2); | |
/// assert_eq!(new_grid, grid![[2,4][6,8]]); | |
/// | |
/// let grid = grid![[1,2][3,4]]; | |
/// let new_grid = grid.map(|x| x > 2); | |
/// assert_eq!(new_grid, grid![[false,false][true,true]]); | |
/// ``` | |
pub fn map<U, F>(self, f: F) -> Grid<U> | |
where | |
F: FnMut(T) -> U, | |
{ | |
Grid { | |
data: self.data.into_iter().map(f).collect(), | |
cols: self.cols, | |
rows: self.rows, | |
order: self.order, | |
} | |
} | |
/// Returns a new grid with the same dimensions, but with each element | |
/// transformed by the closure. Does not consume the grid. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let grid = grid![[1,2][3,4]]; | |
/// let new_grid = grid.map(|x| x * 2); | |
/// assert_eq!(new_grid, grid![[2,4][6,8]]); | |
/// | |
/// let grid = grid![[1,2][3,4]]; | |
/// let new_grid = grid.map(|x| x > 2); | |
/// assert_eq!(new_grid, grid![[false,false][true,true]]); | |
/// ``` | |
#[must_use] | |
pub fn map_ref<U, F>(&self, f: F) -> Grid<U> | |
where | |
F: Fn(&T) -> U, | |
{ | |
Grid { | |
data: self.data.iter().map(f).collect(), | |
cols: self.cols, | |
rows: self.rows, | |
order: self.order, | |
} | |
} | |
/// Iterate over the rows of the grid. Each time an iterator over a single | |
/// row is returned. | |
/// | |
/// An item in this iterator is equal to a call to `Grid.iter_row(row_index)` | |
/// of the corresponding row. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2,3][4,5,6]]; | |
/// let sum_by_row: Vec<u8> = grid.iter_rows().map(|row| row.sum()).collect(); | |
/// assert_eq!(sum_by_row, vec![1+2+3, 4+5+6]) | |
/// ``` | |
#[must_use] | |
pub const fn iter_rows(&self) -> GridRowIter<'_, T> { | |
GridRowIter { | |
grid: self, | |
row_start_index: 0, | |
row_end_index: self.rows, | |
} | |
} | |
/// Iterate over the columns of the grid. Each time an iterator over a single | |
/// column is returned. | |
/// | |
/// An item in this iterator is equal to a call to `Grid.iter_col(col_index)` | |
/// of the corresponding column. | |
/// | |
/// # Examples | |
/// | |
/// ``` | |
/// use grid::*; | |
/// let mut grid = grid![[1,2,3][4,5,6]]; | |
/// let sum_by_col: Vec<u8> = grid.iter_cols().map(|col| col.sum()).collect(); | |
/// assert_eq!(sum_by_col, vec![1+4, 2+5, 3+6]) | |
/// ``` | |
#[must_use] | |
pub const fn iter_cols(&self) -> GridColIter<'_, T> { | |
GridColIter { | |
grid: self, | |
col_start_index: 0, | |
col_end_index: self.cols, | |
} | |
} | |
/// Swaps two elements in the Grid. | |
/// Similar to `Vec::swap()`. | |
/// | |
/// # Panics | |
/// | |
/// Panics if either index is out of bounds. | |
pub fn swap(&mut self, (row_a, col_a): (usize, usize), (row_b, col_b): (usize, usize)) { | |
assert!( | |
!(row_a >= self.rows || col_a >= self.cols), | |
"grid index out of bounds: ({row_a},{col_a}) out of ({},{})", | |
self.rows, | |
self.cols | |
); | |
assert!( | |
!(row_b >= self.rows || col_b >= self.cols), | |
"grid index out of bounds: ({row_b},{col_b}) out of ({},{})", | |
self.rows, | |
self.cols | |
); | |
let a_idx = self.get_index(row_a, col_a); | |
let b_idx = self.get_index(row_b, col_b); | |
self.data.swap(a_idx, b_idx); | |
} | |
} | |
impl<T> Default for Grid<T> { | |
fn default() -> Self { | |
Self { | |
data: Vec::default(), | |
cols: 0, | |
rows: 0, | |
order: Order::default(), | |
} | |
} | |
} | |
impl<T: Clone> Clone for Grid<T> { | |
fn clone(&self) -> Self { | |
Self { | |
rows: self.rows, | |
cols: self.cols, | |
data: self.data.clone(), | |
order: self.order, | |
} | |
} | |
} | |
impl<T: hash::Hash> hash::Hash for Grid<T> { | |
#[inline] | |
fn hash<H: hash::Hasher>(&self, state: &mut H) { | |
self.rows.hash(state); | |
self.cols.hash(state); | |
self.order.hash(state); | |
self.data.hash(state); | |
} | |
} | |
impl<T> Index<(usize, usize)> for Grid<T> { | |
type Output = T; | |
#[inline] | |
fn index(&self, (row, col): (usize, usize)) -> &T { | |
assert!( | |
!(row >= self.rows || col >= self.cols), | |
"grid index out of bounds: ({row},{col}) out of ({},{})", | |
self.rows, | |
self.cols | |
); | |
let index = self.get_index(row, col); | |
&self.data[index] | |
} | |
} | |
impl<T> IndexMut<(usize, usize)> for Grid<T> { | |
#[inline] | |
fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut T { | |
assert!( | |
!(row >= self.rows || col >= self.cols), | |
"grid index out of bounds: ({row},{col}) out of ({},{})", | |
self.rows, | |
self.cols | |
); | |
let index = self.get_index(row, col); | |
&mut self.data[index] | |
} | |
} | |
impl<'a, T> IntoIterator for &'a Grid<T> { | |
type IntoIter = core::slice::Iter<'a, T>; | |
type Item = &'a T; | |
fn into_iter(self) -> Self::IntoIter { | |
self.iter() | |
} | |
} | |
impl<'a, T> IntoIterator for &'a mut Grid<T> { | |
type IntoIter = core::slice::IterMut<'a, T>; | |
type Item = &'a mut T; | |
fn into_iter(self) -> Self::IntoIter { | |
self.iter_mut() | |
} | |
} | |
impl<T: fmt::Debug> fmt::Debug for Grid<T> { | |
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
write!(f, "[")?; | |
if self.cols > 0 { | |
if f.alternate() { | |
writeln!(f)?; | |
/* | |
WARNING | |
Compound types becoming enormous as the entire `fmt::Debug` width is applied to each item individually. | |
For tuples and structs define padding and precision arguments manually to improve readability. | |
*/ | |
let width = f.width().unwrap_or_else(|| { | |
// Conditionally calculate the longest item by default. | |
self.data | |
.iter() | |
.map(|i| format!("{i:?}").len()) | |
.max() | |
.unwrap() | |
}); | |
let precision = f.precision().unwrap_or(2); | |
for mut row in self.iter_rows().map(Iterator::peekable) { | |
write!(f, " [")?; | |
while let Some(item) = row.next() { | |
write!(f, " {item:width$.precision$?}")?; | |
if row.peek().is_some() { | |
write!(f, ",")?; | |
} | |
} | |
writeln!(f, "]")?; | |
} | |
} else { | |
for row in self.iter_rows() { | |
f.debug_list().entries(row).finish()?; | |
} | |
} | |
} | |
write!(f, "]") | |
} | |
} | |
impl<T: PartialEq> PartialEq for Grid<T> { | |
fn eq(&self, other: &Self) -> bool { | |
if self.rows != other.rows || self.cols != other.cols { | |
return false; | |
} | |
if self.order == other.order { | |
return self.data == other.data; | |
} | |
for (self_row, other_row) in core::iter::zip(self.iter_rows(), other.iter_rows()) { | |
if self_row.ne(other_row) { | |
return false; | |
} | |
} | |
true | |
} | |
} | |
impl<T: Eq> Eq for Grid<T> {} | |
impl<T> From<Vec<Vec<T>>> for Grid<T> { | |
#[allow(clippy::redundant_closure_for_method_calls)] | |
fn from(vec: Vec<Vec<T>>) -> Self { | |
let cols = vec.first().map_or(0, |row| row.len()); | |
Self::from_vec_with_order(vec.into_iter().flatten().collect(), cols, Order::default()) | |
} | |
} | |
impl<T: Clone> From<&Vec<Vec<T>>> for Grid<T> { | |
#[allow(clippy::redundant_closure_for_method_calls)] | |
fn from(vec: &Vec<Vec<T>>) -> Self { | |
let cols = vec.first().map_or(0, |row| row.len()); | |
Self::from_vec_with_order( | |
vec.clone().into_iter().flatten().collect(), | |
cols, | |
Order::default(), | |
) | |
} | |
} | |
impl<T: Clone> From<&Vec<&Vec<T>>> for Grid<T> { | |
#[allow(clippy::redundant_closure_for_method_calls)] | |
fn from(vec: &Vec<&Vec<T>>) -> Self { | |
let cols = vec.first().map_or(0, |row| row.len()); | |
Self::from_vec_with_order( | |
vec.clone() | |
.into_iter() | |
.flat_map(|inner| inner.clone()) | |
.collect(), | |
cols, | |
Order::default(), | |
) | |
} | |
} | |
impl<T> From<(Vec<T>, usize)> for Grid<T> { | |
fn from(value: (Vec<T>, usize)) -> Self { | |
Self::from_vec_with_order(value.0, value.1, Order::default()) | |
} | |
} | |
impl<T: Clone> From<(&Vec<T>, usize)> for Grid<T> { | |
fn from(value: (&Vec<T>, usize)) -> Self { | |
Self::from_vec_with_order(value.0.clone(), value.1, Order::default()) | |
} | |
} | |
impl<T: Clone> From<(&Vec<T>, &usize)> for Grid<T> { | |
fn from(value: (&Vec<T>, &usize)) -> Self { | |
Self::from_vec_with_order(value.0.clone(), *value.1, Order::default()) | |
} | |
} | |
#[derive(Clone)] | |
pub struct GridRowIter<'a, T> { | |
grid: &'a Grid<T>, | |
row_start_index: usize, | |
row_end_index: usize, | |
} | |
#[derive(Clone)] | |
pub struct GridColIter<'a, T> { | |
grid: &'a Grid<T>, | |
col_start_index: usize, | |
col_end_index: usize, | |
} | |
impl<'a, T> Iterator for GridRowIter<'a, T> { | |
type Item = StepBy<Iter<'a, T>>; | |
fn next(&mut self) -> Option<Self::Item> { | |
if self.row_start_index >= self.row_end_index { | |
return None; | |
} | |
let row_iter = self.grid.iter_row(self.row_start_index); | |
self.row_start_index += 1; | |
Some(row_iter) | |
} | |
fn size_hint(&self) -> (usize, Option<usize>) { | |
let size = self.row_end_index - self.row_start_index; | |
(size, Some(size)) | |
} | |
} | |
impl<T> ExactSizeIterator for GridRowIter<'_, T> {} | |
impl<T> DoubleEndedIterator for GridRowIter<'_, T> { | |
fn next_back(&mut self) -> Option<Self::Item> { | |
if self.row_start_index >= self.row_end_index { | |
return None; | |
} | |
let row_iter = self.grid.iter_row(self.row_end_index - 1); | |
self.row_end_index -= 1; | |
Some(row_iter) | |
} | |
} | |
impl<'a, T> Iterator for GridColIter<'a, T> { | |
type Item = StepBy<Iter<'a, T>>; | |
fn next(&mut self) -> Option<Self::Item> { | |
if self.col_start_index >= self.col_end_index { | |
return None; | |
} | |
let col_iter = self.grid.iter_col(self.col_start_index); | |
self.col_start_index += 1; | |
Some(col_iter) | |
} | |
fn size_hint(&self) -> (usize, Option<usize>) { | |
let size = self.col_end_index - self.col_start_index; | |
(size, Some(size)) | |
} | |
} | |
impl<T> ExactSizeIterator for GridColIter<'_, T> {} | |
impl<T> DoubleEndedIterator for GridColIter<'_, T> { | |
fn next_back(&mut self) -> Option<Self::Item> { | |
if self.col_start_index >= self.col_end_index { | |
return None; | |
} | |
let col_iter = self.grid.iter_col(self.col_end_index - 1); | |
self.col_end_index -= 1; | |
Some(col_iter) | |
} | |
} | |
#[cfg(test)] | |
mod test { | |
use super::*; | |
#[cfg(not(feature = "std"))] | |
use alloc::string::String; | |
fn test_grid<T>(grid: &Grid<T>, rows: usize, cols: usize, order: Order, data: &[T]) | |
where | |
T: fmt::Debug + PartialEq, | |
{ | |
assert_eq!(grid.rows, rows, "number of rows is unexpected"); | |
assert_eq!(grid.cols, cols, "number of cols is unexpected"); | |
assert_eq!(grid.order, order, "grid order is unexpected"); | |
assert_eq!(grid.data, data, "internal data is unexpected"); | |
} | |
#[test] | |
fn from_1d_vec() { | |
let grid: Grid<u8> = Grid::from((vec![1, 2, 3], 1)); | |
test_grid(&grid, 3, 1, Order::RowMajor, &[1, 2, 3]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn from_1d_vec_panic() { | |
let _: Grid<u8> = Grid::from((vec![1, 2, 3], 2)); | |
} | |
#[test] | |
fn from_1d_vec_reference() { | |
let vec = vec![1, 2, 3]; | |
let grid: Grid<u8> = Grid::from((&vec, 1)); | |
test_grid(&grid, 3, 1, Order::RowMajor, &[1, 2, 3]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn from_1d_vec_reference_panic() { | |
let vec = vec![1, 2, 3]; | |
let _: Grid<u8> = Grid::from((&vec, 2)); | |
} | |
#[test] | |
fn from_1d_vec_reference_and_reference() { | |
let vec = vec![1, 2, 3]; | |
let cols = 1; | |
let grid: Grid<u8> = Grid::from((&vec, &cols)); | |
test_grid(&grid, 3, 1, Order::RowMajor, &[1, 2, 3]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn from_1d_vec_reference_and_reference_panic() { | |
let vec = vec![1, 2, 3]; | |
let cols = 2; | |
let _: Grid<u8> = Grid::from((&vec, &cols)); | |
} | |
#[test] | |
fn from_2d_vec() { | |
let grid: Grid<u8> = Grid::from(vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]]); | |
test_grid(&grid, 3, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6, 7, 8, 9]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn from_2d_vec_panic() { | |
let _: Grid<u8> = Grid::from(vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8]]); | |
} | |
#[test] | |
fn from_2d_vec_reference() { | |
let vec = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]]; | |
let grid: Grid<u8> = Grid::from(&vec); | |
test_grid(&grid, 3, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6, 7, 8, 9]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn from_2d_vec_reference_panic() { | |
let vec = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8]]; | |
let _: Grid<u8> = Grid::from(&vec); | |
} | |
#[test] | |
fn from_2d_vec_reference_of_references() { | |
let inner_vec1 = vec![1, 2, 3]; | |
let inner_vec2 = vec![4, 5, 6]; | |
let inner_vec3 = vec![7, 8, 9]; | |
let vec = vec![&inner_vec1, &inner_vec2, &inner_vec3]; | |
let grid: Grid<u8> = Grid::from(&vec); | |
test_grid(&grid, 3, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6, 7, 8, 9]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn from_2d_vec_reference_of_references_panic() { | |
let inner_vec1 = vec![1, 2, 3]; | |
let inner_vec2 = vec![4, 5, 6]; | |
let inner_vec3 = vec![7, 8]; | |
let vec = vec![&inner_vec1, &inner_vec2, &inner_vec3]; | |
let _: Grid<u8> = Grid::from(&vec); | |
} | |
#[test] | |
fn from_vec_zero_with_cols() { | |
let grid: Grid<u8> = Grid::from_vec(vec![], 1); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
fn from_vec_zero() { | |
let grid: Grid<u8> = Grid::from_vec(vec![], 0); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn from_vec_panics_1() { | |
let _: Grid<u8> = Grid::from_vec(vec![1, 2, 3], 0); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn from_vec_panics_2() { | |
let _: Grid<u8> = Grid::from_vec(vec![1, 2, 3], 2); | |
} | |
#[test] | |
fn from_vec_uses_original_vec() { | |
let capacity = 10_000_000; | |
let vec = Vec::with_capacity(capacity); | |
let grid: Grid<u8> = Grid::from_vec(vec, 0); | |
assert!(grid.into_vec().capacity() >= capacity); | |
} | |
#[test] | |
fn from_vec_with_order_zero_with_cols() { | |
let grid: Grid<u8> = Grid::from_vec_with_order(vec![], 1, Order::ColumnMajor); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
} | |
#[test] | |
fn from_vec_with_order_zero() { | |
let grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn from_vec_with_order_panics_1() { | |
let _: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3], 0, Order::ColumnMajor); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn from_vec_with_order_panics_2() { | |
let _: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3], 2, Order::ColumnMajor); | |
} | |
#[test] | |
fn from_vec_with_order_uses_original_vec() { | |
let capacity = 10_000_000; | |
let vec = Vec::with_capacity(capacity); | |
let grid: Grid<u8> = Grid::from_vec_with_order(vec, 0, Order::ColumnMajor); | |
assert!(grid.into_vec().capacity() >= capacity); | |
} | |
#[test] | |
fn insert_col_at_end() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); | |
grid.insert_col(2, vec![5, 6]); | |
test_grid(&grid, 2, 3, Order::RowMajor, &[1, 2, 5, 3, 4, 6]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn insert_col_out_of_idx() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); | |
grid.insert_col(3, vec![4, 5]); | |
} | |
#[test] | |
fn insert_col_empty() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); | |
grid.insert_col(0, vec![1, 2, 3]); | |
test_grid(&grid, 3, 1, Order::RowMajor, &[1, 2, 3]); | |
} | |
#[test] | |
fn insert_col_at_end_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
grid.insert_col(2, vec![5, 6]); | |
test_grid(&grid, 2, 3, Order::ColumnMajor, &[1, 3, 2, 4, 5, 6]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn insert_col_out_of_idx_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
grid.insert_col(3, vec![4, 5]); | |
} | |
#[test] | |
fn insert_col_empty_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); | |
grid.insert_col(0, vec![1, 2, 3]); | |
test_grid(&grid, 3, 1, Order::ColumnMajor, &[1, 2, 3]); | |
} | |
#[test] | |
fn insert_row_at_end() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); | |
grid.insert_row(2, vec![5, 6]); | |
test_grid(&grid, 3, 2, Order::RowMajor, &[1, 2, 3, 4, 5, 6]); | |
} | |
#[test] | |
fn insert_row_empty() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); | |
grid.insert_row(0, vec![1, 2, 3]); | |
test_grid(&grid, 1, 3, Order::RowMajor, &[1, 2, 3]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn insert_row_out_of_idx() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); | |
grid.insert_row(3, vec![4, 5]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn insert_row_wrong_size_of_idx() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); | |
grid.insert_row(1, vec![4, 5, 4]); | |
} | |
#[test] | |
fn insert_row_start() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); | |
grid.insert_row(1, vec![5, 6]); | |
test_grid(&grid, 3, 2, Order::RowMajor, &[1, 2, 5, 6, 3, 4]); | |
} | |
#[test] | |
fn insert_row_at_end_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
grid.insert_row(2, vec![5, 6]); | |
test_grid(&grid, 3, 2, Order::ColumnMajor, &[1, 3, 5, 2, 4, 6]); | |
} | |
#[test] | |
fn insert_row_empty_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); | |
grid.insert_row(0, vec![1, 2, 3]); | |
test_grid(&grid, 1, 3, Order::ColumnMajor, &[1, 2, 3]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn insert_row_out_of_idx_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::ColumnMajor); | |
grid.insert_row(3, vec![4, 5]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn insert_row_wrong_size_of_idx_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::ColumnMajor); | |
grid.insert_row(1, vec![4, 5, 4]); | |
} | |
#[test] | |
fn insert_row_start_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
grid.insert_row(1, vec![5, 6]); | |
test_grid(&grid, 3, 2, Order::ColumnMajor, &[1, 5, 3, 2, 6, 4]); | |
} | |
#[test] | |
fn pop_col_1x3() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3], 3, Order::RowMajor); | |
assert_eq!(grid.pop_col(), Some(vec![3])); | |
test_grid(&grid, 1, 2, Order::RowMajor, &[1, 2]); | |
assert_eq!(grid.pop_col(), Some(vec![2])); | |
test_grid(&grid, 1, 1, Order::RowMajor, &[1]); | |
assert_eq!(grid.pop_col(), Some(vec![1])); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
assert_eq!(grid.pop_col(), None); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
fn pop_col_3x1() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3], 1, Order::RowMajor); | |
assert_eq!(grid.pop_col(), Some(vec![1, 2, 3])); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
assert_eq!(grid.pop_col(), None); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
fn pop_col_2x2() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); | |
assert_eq!(grid.pop_col(), Some(vec![2, 4])); | |
assert_eq!(grid.size(), (2, 1)); | |
test_grid(&grid, 2, 1, Order::RowMajor, &[1, 3]); | |
assert_eq!(grid.pop_col(), Some(vec![1, 3])); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
assert_eq!(grid.pop_col(), None); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
fn pop_col_3x4() { | |
let internal = vec![1, 2, 3, 4, 11, 22, 33, 44, 111, 222, 333, 444]; | |
let mut grid: Grid<u16> = Grid::from_vec_with_order(internal, 4, Order::RowMajor); | |
assert_eq!(grid.pop_col(), Some(vec![4, 44, 444])); | |
let expected = [1, 2, 3, 11, 22, 33, 111, 222, 333]; | |
test_grid(&grid, 3, 3, Order::RowMajor, &expected); | |
assert_eq!(grid.pop_col(), Some(vec![3, 33, 333])); | |
test_grid(&grid, 3, 2, Order::RowMajor, &[1, 2, 11, 22, 111, 222]); | |
assert_eq!(grid.pop_col(), Some(vec![2, 22, 222])); | |
test_grid(&grid, 3, 1, Order::RowMajor, &[1, 11, 111]); | |
assert_eq!(grid.pop_col(), Some(vec![1, 11, 111])); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
assert_eq!(grid.pop_col(), None); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
fn pop_col_empty() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); | |
assert_eq!(grid.pop_col(), None); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
fn pop_col_1x3_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3], 3, Order::ColumnMajor); | |
assert_eq!(grid.pop_col(), Some(vec![3])); | |
test_grid(&grid, 1, 2, Order::ColumnMajor, &[1, 2]); | |
assert_eq!(grid.pop_col(), Some(vec![2])); | |
test_grid(&grid, 1, 1, Order::ColumnMajor, &[1]); | |
assert_eq!(grid.pop_col(), Some(vec![1])); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
assert_eq!(grid.pop_col(), None); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
} | |
#[test] | |
fn pop_col_3x1_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 2, 3], 1, Order::ColumnMajor); | |
assert_eq!(grid.pop_col(), Some(vec![1, 2, 3])); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
assert_eq!(grid.pop_col(), None); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
} | |
#[test] | |
fn pop_col_2x2_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
assert_eq!(grid.pop_col(), Some(vec![2, 4])); | |
assert_eq!(grid.size(), (2, 1)); | |
test_grid(&grid, 2, 1, Order::ColumnMajor, &[1, 3]); | |
assert_eq!(grid.pop_col(), Some(vec![1, 3])); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
assert_eq!(grid.pop_col(), None); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
} | |
#[test] | |
fn pop_col_3x4_column_major() { | |
let internal = vec![1, 11, 111, 2, 22, 222, 3, 33, 333, 4, 44, 444]; | |
let mut grid: Grid<u16> = Grid::from_vec_with_order(internal, 4, Order::ColumnMajor); | |
assert_eq!(grid.pop_col(), Some(vec![4, 44, 444])); | |
let expected = [1, 11, 111, 2, 22, 222, 3, 33, 333]; | |
test_grid(&grid, 3, 3, Order::ColumnMajor, &expected); | |
assert_eq!(grid.pop_col(), Some(vec![3, 33, 333])); | |
test_grid(&grid, 3, 2, Order::ColumnMajor, &[1, 11, 111, 2, 22, 222]); | |
assert_eq!(grid.pop_col(), Some(vec![2, 22, 222])); | |
test_grid(&grid, 3, 1, Order::ColumnMajor, &[1, 11, 111]); | |
assert_eq!(grid.pop_col(), Some(vec![1, 11, 111])); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
assert_eq!(grid.pop_col(), None); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
} | |
#[test] | |
fn pop_col_empty_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); | |
assert_eq!(grid.pop_col(), None); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
} | |
#[test] | |
fn pop_row_2x2() { | |
let mut grid: Grid<u8> = Grid::from_vec(vec![1, 2, 3, 4], 2); | |
assert_eq!(grid.pop_row(), Some(vec![3, 4])); | |
test_grid(&grid, 1, 2, Order::RowMajor, &[1, 2]); | |
assert_eq!(grid.pop_row(), Some(vec![1, 2])); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
assert_eq!(grid.pop_row(), None); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
fn pop_row_empty() { | |
let mut grid: Grid<u8> = Grid::from_vec(vec![], 0); | |
assert_eq!(grid.pop_row(), None); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
fn pop_row_2x2_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
assert_eq!(grid.pop_row(), Some(vec![3, 4])); | |
test_grid(&grid, 1, 2, Order::ColumnMajor, &[1, 2]); | |
assert_eq!(grid.pop_row(), Some(vec![1, 2])); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
assert_eq!(grid.pop_row(), None); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
} | |
#[test] | |
fn pop_row_empty_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); | |
assert_eq!(grid.pop_row(), None); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
} | |
#[test] | |
fn ne_full_empty() { | |
let g1 = Grid::from_vec(vec![1, 2, 3, 4], 2); | |
let g2: Grid<u8> = grid![]; | |
assert_ne!(g1, g2); | |
} | |
#[test] | |
fn ne() { | |
let g1 = Grid::from_vec(vec![1, 2, 3, 5], 2); | |
let g2 = Grid::from_vec(vec![1, 2, 3, 4], 2); | |
assert_ne!(g1, g2); | |
} | |
#[test] | |
fn ne_dif_rows() { | |
let g1 = Grid::from_vec(vec![1, 2, 3, 4], 2); | |
let g2 = Grid::from_vec(vec![1, 2, 3, 4], 1); | |
assert_ne!(g1, g2); | |
} | |
#[test] | |
fn equal_empty() { | |
let grid: Grid<char> = grid![]; | |
let grid2: Grid<char> = grid![]; | |
assert_eq!(grid, grid2); | |
} | |
#[test] | |
fn equal() { | |
let grid: Grid<char> = grid![['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']]; | |
let grid2: Grid<char> = grid![['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']]; | |
assert_eq!(grid, grid2); | |
} | |
#[test] | |
fn equal_different_order() { | |
let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); | |
let grid2 = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
assert_eq!(grid, grid2); | |
} | |
#[test] | |
fn equal_partial_eq() { | |
let grid = grid![[1.0]]; | |
let grid2 = Grid::from_vec(vec![1.0], 1); | |
assert_eq!(grid, grid2); | |
} | |
#[test] | |
fn ne_partial_eq() { | |
let grid = grid![[f64::NAN]]; | |
assert_ne!(grid, grid); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn idx_tup_out_of_col_bounds() { | |
let grid: Grid<char> = grid![['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']]; | |
let _ = grid[(0, 5)]; | |
} | |
#[test] | |
fn push_col_2x3() { | |
let mut grid: Grid<u8> = grid![ | |
[0, 1, 2] | |
[10, 11, 12]]; | |
grid.push_col(vec![3, 13]); | |
test_grid(&grid, 2, 4, Order::RowMajor, &[0, 1, 2, 3, 10, 11, 12, 13]); | |
} | |
#[test] | |
fn push_col_3x4() { | |
let mut grid: Grid<char> = grid![ | |
['a', 'b', 'c', 'd'] | |
['a', 'b', 'c', 'd'] | |
['a', 'b', 'c', 'd']]; | |
grid.push_col(vec!['x', 'y', 'z']); | |
let expected = [ | |
'a', 'b', 'c', 'd', 'x', 'a', 'b', 'c', 'd', 'y', 'a', 'b', 'c', 'd', 'z', | |
]; | |
test_grid(&grid, 3, 5, Order::RowMajor, &expected); | |
} | |
#[test] | |
fn push_col_1x3() { | |
let mut grid: Grid<char> = grid![['a', 'b', 'c']]; | |
grid.push_col(vec!['d']); | |
test_grid(&grid, 1, 4, Order::RowMajor, &['a', 'b', 'c', 'd']); | |
} | |
#[test] | |
fn push_col_empty() { | |
let mut grid: Grid<char> = grid![]; | |
grid.push_col(vec!['b', 'b', 'b', 'b']); | |
test_grid(&grid, 4, 1, Order::RowMajor, &['b', 'b', 'b', 'b']); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn push_col_wrong_size() { | |
let mut grid: Grid<char> = grid![['a','a','a']['a','a','a']]; | |
grid.push_col(vec!['b']); | |
grid.push_col(vec!['b', 'b']); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn push_col_zero_len() { | |
let mut grid: Grid<char> = grid![]; | |
grid.push_col(vec![]); | |
} | |
#[test] | |
fn push_col_2x3_column_major() { | |
let internal = vec![0, 10, 1, 11, 2, 12]; | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(internal, 3, Order::ColumnMajor); | |
grid.push_col(vec![3, 13]); | |
let expected = [0, 10, 1, 11, 2, 12, 3, 13]; | |
test_grid(&grid, 2, 4, Order::ColumnMajor, &expected); | |
} | |
#[test] | |
fn push_col_3x4_column_major() { | |
let internal = vec!['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd']; | |
let mut grid: Grid<char> = Grid::from_vec_with_order(internal, 4, Order::ColumnMajor); | |
grid.push_col(vec!['x', 'y', 'z']); | |
let expected = [ | |
'a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd', 'x', 'y', 'z', | |
]; | |
test_grid(&grid, 3, 5, Order::ColumnMajor, &expected); | |
} | |
#[test] | |
fn push_col_1x3_column_major() { | |
let mut grid: Grid<char> = | |
Grid::from_vec_with_order(vec!['a', 'b', 'c'], 3, Order::ColumnMajor); | |
grid.push_col(vec!['d']); | |
test_grid(&grid, 1, 4, Order::ColumnMajor, &['a', 'b', 'c', 'd']); | |
} | |
#[test] | |
fn push_col_empty_column_major() { | |
let mut grid: Grid<char> = Grid::new_with_order(0, 0, Order::ColumnMajor); | |
grid.push_col(vec!['b', 'b', 'b', 'b']); | |
test_grid(&grid, 4, 1, Order::ColumnMajor, &['b', 'b', 'b', 'b']); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn push_col_wrong_size_column_major() { | |
let mut grid: Grid<char> = Grid::init_with_order(2, 3, Order::ColumnMajor, 'a'); | |
grid.push_col(vec!['b']); | |
grid.push_col(vec!['b', 'b']); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn push_col_zero_len_column_major() { | |
let mut grid: Grid<char> = Grid::new_with_order(0, 0, Order::ColumnMajor); | |
grid.push_col(vec![]); | |
} | |
#[test] | |
fn push_row() { | |
let mut grid: Grid<u8> = grid![[1, 2][3, 4]]; | |
grid.push_row(vec![5, 6]); | |
test_grid(&grid, 3, 2, Order::RowMajor, &[1, 2, 3, 4, 5, 6]); | |
} | |
#[test] | |
fn push_row_empty() { | |
let mut grid: Grid<char> = grid![]; | |
grid.push_row(vec!['b', 'b', 'b', 'b']); | |
test_grid(&grid, 1, 4, Order::RowMajor, &['b', 'b', 'b', 'b']); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn push_empty_row() { | |
let mut grid = Grid::init(0, 1, 0); | |
grid.push_row(vec![]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn push_row_wrong_size() { | |
let mut grid: Grid<char> = grid![['a','a','a']['a','a','a']]; | |
grid.push_row(vec!['b']); | |
grid.push_row(vec!['b', 'b', 'b', 'b']); | |
} | |
#[test] | |
fn push_row_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
grid.push_row(vec![5, 6]); | |
test_grid(&grid, 3, 2, Order::ColumnMajor, &[1, 3, 5, 2, 4, 6]); | |
} | |
#[test] | |
fn push_row_empty_column_major() { | |
let mut grid: Grid<char> = Grid::new_with_order(0, 0, Order::ColumnMajor); | |
grid.push_row(vec!['b', 'b', 'b', 'b']); | |
test_grid(&grid, 1, 4, Order::ColumnMajor, &['b', 'b', 'b', 'b']); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn push_empty_row_column_major() { | |
let mut grid = Grid::init_with_order(0, 1, Order::ColumnMajor, 0); | |
grid.push_row(vec![]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn push_row_wrong_size_column_major() { | |
let mut grid: Grid<char> = | |
Grid::from_vec_with_order(vec!['a', 'a', 'a', 'a', 'a', 'a'], 3, Order::ColumnMajor); | |
grid.push_row(vec!['b']); | |
grid.push_row(vec!['b', 'b', 'b', 'b']); | |
} | |
#[test] | |
fn iter_row() { | |
let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); | |
let row: Vec<_> = grid.iter_row(1).collect(); | |
assert_eq!(row, [&4, &5, &6]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_row_out_of_bound() { | |
let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); | |
let _ = grid.iter_row(3); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_row_zero() { | |
let grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); | |
let _ = grid.iter_row(0); | |
} | |
#[test] | |
fn iter_row_rowumn_major() { | |
let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); | |
let row: Vec<_> = grid.iter_row(1).collect(); | |
assert_eq!(row, [&4, &5, &6]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_row_rowumn_major_out_of_bound() { | |
let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); | |
let _ = grid.iter_row(3); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_row_rowumn_major_zero() { | |
let grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); | |
let _ = grid.iter_row(0); | |
} | |
#[test] | |
fn iter_row_mut() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); | |
let row: Vec<_> = grid.iter_row_mut(1).collect(); | |
assert_eq!(row, [&mut 4, &mut 5, &mut 6]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_row_mut_out_of_bound() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); | |
let _ = grid.iter_row_mut(3); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_row_mut_zero() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); | |
let _ = grid.iter_row_mut(0); | |
} | |
#[test] | |
fn iter_row_mut_rowumn_major() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); | |
let row: Vec<_> = grid.iter_row_mut(1).collect(); | |
assert_eq!(row, [&mut 4, &mut 5, &mut 6]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_row_mut_rowumn_major_out_of_bound() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); | |
let _ = grid.iter_row_mut(3); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_row_mut_rowumn_major_zero() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); | |
let _ = grid.iter_row_mut(0); | |
} | |
#[test] | |
fn iter_col() { | |
let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); | |
let col: Vec<_> = grid.iter_col(1).collect(); | |
assert_eq!(col, [&2, &5]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_col_out_of_bound() { | |
let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); | |
let _ = grid.iter_col(3); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_col_zero() { | |
let grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); | |
let _ = grid.iter_col(0); | |
} | |
#[test] | |
fn iter_col_column_major() { | |
let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); | |
let col: Vec<_> = grid.iter_col(1).collect(); | |
assert_eq!(col, [&2, &5]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_col_column_major_out_of_bound() { | |
let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); | |
let _ = grid.iter_col(3); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_col_column_major_zero() { | |
let grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); | |
let _ = grid.iter_col(0); | |
} | |
#[test] | |
fn iter_col_mut() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); | |
let col: Vec<_> = grid.iter_col_mut(1).collect(); | |
assert_eq!(col, [&mut 2, &mut 5]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_col_mut_out_of_bound() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); | |
let _ = grid.iter_col_mut(3); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_col_mut_zero() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); | |
let _ = grid.iter_col_mut(0); | |
} | |
#[test] | |
fn iter_col_mut_column_major() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); | |
let col: Vec<_> = grid.iter_col_mut(1).collect(); | |
assert_eq!(col, [&mut 2, &mut 5]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_col_mut_column_major_out_of_bound() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); | |
let _ = grid.iter_col_mut(3); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn iter_col_mut_column_major_zero() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); | |
let _ = grid.iter_col_mut(0); | |
} | |
#[test] | |
fn iter() { | |
let grid: Grid<u8> = grid![[1,2][3,4]]; | |
let mut iter = grid.iter(); | |
assert_eq!(iter.next(), Some(&1)); | |
assert_eq!(iter.next(), Some(&2)); | |
assert_eq!(iter.next(), Some(&3)); | |
assert_eq!(iter.next(), Some(&4)); | |
assert_eq!(iter.next(), None); | |
} | |
#[test] | |
fn into_iter() { | |
let grid: Grid<u8> = grid![[1,1][1,1]]; | |
for val in &grid { | |
assert_eq!(val, &1); | |
} | |
} | |
#[test] | |
fn into_iter_mut() { | |
let mut grid: Grid<u8> = grid![[1,1][1,1]]; | |
for val in &mut grid { | |
*val = 2; | |
} | |
assert_eq!(grid, grid![[2, 2][2, 2]]); | |
} | |
#[test] | |
fn indexed_iter() { | |
let grid: Grid<u8> = grid![[1,2][3,4]]; | |
let mut iter = grid.indexed_iter(); | |
assert_eq!(iter.next(), Some(((0, 0), &1))); | |
assert_eq!(iter.next(), Some(((0, 1), &2))); | |
assert_eq!(iter.next(), Some(((1, 0), &3))); | |
assert_eq!(iter.next(), Some(((1, 1), &4))); | |
assert_eq!(iter.next(), None); | |
} | |
#[test] | |
fn indexed_iter_empty() { | |
let grid: Grid<u8> = Grid::new(0, 0); | |
let mut iter = grid.indexed_iter(); | |
assert_eq!(iter.next(), None); | |
} | |
#[test] | |
fn indexed_iter_column_major() { | |
let grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
let mut iter = grid.indexed_iter(); | |
assert_eq!(iter.next(), Some(((0, 0), &1))); | |
assert_eq!(iter.next(), Some(((1, 0), &3))); | |
assert_eq!(iter.next(), Some(((0, 1), &2))); | |
assert_eq!(iter.next(), Some(((1, 1), &4))); | |
assert_eq!(iter.next(), None); | |
} | |
#[test] | |
fn indexed_iter_empty_column_major() { | |
let grid: Grid<u8> = Grid::new_with_order(0, 0, Order::ColumnMajor); | |
let mut iter = grid.indexed_iter(); | |
assert_eq!(iter.next(), None); | |
} | |
#[test] | |
fn indexed_iter_mut() { | |
let mut grid: Grid<u8> = grid![[1,2][3,4]]; | |
let mut iter = grid.indexed_iter_mut(); | |
assert_eq!(iter.next(), Some(((0, 0), &mut 1))); | |
assert_eq!(iter.next(), Some(((0, 1), &mut 2))); | |
assert_eq!(iter.next(), Some(((1, 0), &mut 3))); | |
assert_eq!(iter.next(), Some(((1, 1), &mut 4))); | |
assert_eq!(iter.next(), None); | |
} | |
#[test] | |
fn indexed_iter_mut_empty() { | |
let mut grid: Grid<u8> = Grid::new(0, 0); | |
let mut iter = grid.indexed_iter_mut(); | |
assert_eq!(iter.next(), None); | |
} | |
#[test] | |
fn indexed_iter_mut_column_major() { | |
let mut grid: Grid<u8> = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
let mut iter = grid.indexed_iter_mut(); | |
assert_eq!(iter.next(), Some(((0, 0), &mut 1))); | |
assert_eq!(iter.next(), Some(((1, 0), &mut 3))); | |
assert_eq!(iter.next(), Some(((0, 1), &mut 2))); | |
assert_eq!(iter.next(), Some(((1, 1), &mut 4))); | |
assert_eq!(iter.next(), None); | |
} | |
#[test] | |
fn indexed_iter_mut_empty_column_major() { | |
let mut grid: Grid<u8> = Grid::new_with_order(0, 0, Order::ColumnMajor); | |
let mut iter = grid.indexed_iter_mut(); | |
assert_eq!(iter.next(), None); | |
} | |
#[test] | |
fn clear() { | |
let mut grid: Grid<u8> = grid![[1, 2, 3]]; | |
assert!(!grid.is_empty()); | |
grid.clear(); | |
assert!(grid.is_empty()); | |
} | |
#[test] | |
fn is_empty_false() { | |
let grid: Grid<u8> = grid![[1, 2, 3]]; | |
assert!(!grid.is_empty()); | |
} | |
#[test] | |
fn is_empty() { | |
let mut g: Grid<u8> = grid![[]]; | |
assert!(g.is_empty()); | |
g = grid![]; | |
assert!(g.is_empty()); | |
g = Grid::from_vec(vec![], 0); | |
assert!(g.is_empty()); | |
g = Grid::new(0, 0); | |
assert!(g.is_empty()); | |
g = Grid::new(0, 1); | |
assert!(g.is_empty()); | |
g = Grid::new(1, 0); | |
assert!(g.is_empty()); | |
g = Grid::init(0, 0, 10); | |
assert!(g.is_empty()); | |
} | |
#[test] | |
fn fmt_empty() { | |
let grid: Grid<u8> = grid![]; | |
assert_eq!(format!("{grid:?}"), "[]"); | |
} | |
#[test] | |
fn fmt_row() { | |
let grid: Grid<u8> = grid![[1, 2, 3]]; | |
assert_eq!(format!("{grid:?}"), "[[1, 2, 3]]"); | |
} | |
#[test] | |
fn fmt_grid() { | |
let grid: Grid<u8> = grid![[1,2,3][4,5,6][7,8,9]]; | |
assert_eq!(format!("{grid:?}"), "[[1, 2, 3][4, 5, 6][7, 8, 9]]"); | |
} | |
#[test] | |
fn fmt_column_major() { | |
let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); | |
assert_eq!(format!("{grid:?}"), "[[1, 2, 3][4, 5, 6]]"); | |
} | |
#[test] | |
fn fmt_pretty_empty() { | |
let grid: Grid<f32> = grid![]; | |
assert_eq!(format!("{grid:#?}"), "[]"); | |
} | |
#[test] | |
fn fmt_pretty_int() { | |
let grid: Grid<u8> = grid![ | |
[1,2,3] | |
[4,5,6] | |
[7,8,95] | |
]; | |
let expected_output = r"[ | |
[ 1, 2, 3] | |
[ 4, 5, 6] | |
[ 7, 8, 95] | |
]"; | |
assert_eq!(format!("{grid:#?}"), expected_output); | |
let expected_output = r"[ | |
[ 1, 2, 3] | |
[ 4, 5, 6] | |
[ 7, 8, 95] | |
]"; | |
assert_eq!(format!("{grid:#3?}"), expected_output); | |
} | |
#[test] | |
fn fmt_pretty_float() { | |
let grid: Grid<f32> = grid![ | |
[1.5,2.6,3.44] | |
[4.775,5.,6.] | |
[7.1,8.23444,95.55] | |
]; | |
let expected_output = r"[ | |
[ 1.5, 2.6, 3.4] | |
[ 4.8, 5.0, 6.0] | |
[ 7.1, 8.2, 95.6] | |
]"; | |
assert_eq!(format!("{grid:#5.1?}"), expected_output); | |
let expected_output = r"[ | |
[ 1.50000, 2.60000, 3.44000] | |
[ 4.77500, 5.00000, 6.00000] | |
[ 7.10000, 8.23444, 95.55000] | |
]"; | |
assert_eq!(format!("{grid:#8.5?}"), expected_output); | |
} | |
#[test] | |
fn fmt_pretty_tuple() { | |
let grid: Grid<(i32, i32)> = grid![ | |
[(5,66), (432, 55)] | |
[(80, 90), (5, 6)] | |
]; | |
let expected_output = r"[ | |
[ ( 5, 66), ( 432, 55)] | |
[ ( 80, 90), ( 5, 6)] | |
]"; | |
assert_eq!(format!("{grid:#?}"), expected_output); | |
let expected_output = r"[ | |
[ ( 5, 66), (432, 55)] | |
[ ( 80, 90), ( 5, 6)] | |
]"; | |
assert_eq!(format!("{grid:#3?}"), expected_output); | |
} | |
#[test] | |
fn fmt_pretty_struct_derived() { | |
#[derive(Debug)] | |
struct Person { | |
_name: String, | |
_precise_age: f32, | |
} | |
impl Person { | |
fn new(name: &str, precise_age: f32) -> Self { | |
Self { | |
_name: name.into(), | |
_precise_age: precise_age, | |
} | |
} | |
} | |
let grid: Grid<Person> = grid![ | |
[Person::new("Vic", 24.5), Person::new("Mr. Very Long Name", 1955.)] | |
[Person::new("Sam", 8.9995), Person::new("John Doe", 40.14)] | |
]; | |
let expected_output = r#"[ | |
[ Person { _name: "Vic", _precise_age: 24.50000 }, Person { _name: "Mr. Very Long Name", _precise_age: 1955.00000 }] | |
[ Person { _name: "Sam", _precise_age: 8.99950 }, Person { _name: "John Doe", _precise_age: 40.14000 }] | |
]"#; | |
assert_eq!(format!("{grid:#5.5?}"), expected_output); | |
} | |
#[test] | |
fn fmt_pretty_column_major() { | |
let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); | |
let expected_output = r"[ | |
[ 1, 2, 3] | |
[ 4, 5, 6] | |
]"; | |
assert_eq!(format!("{grid:#?}"), expected_output); | |
} | |
#[test] | |
fn clone() { | |
let grid = grid![[1, 2, 3][4, 5, 6]]; | |
let mut clone = grid.clone(); | |
clone[(0, 2)] = 10; | |
test_grid(&grid, 2, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6]); | |
test_grid(&clone, 2, 3, Order::RowMajor, &[1, 2, 10, 4, 5, 6]); | |
} | |
#[cfg(feature = "std")] | |
#[test] | |
fn hash_std() { | |
let mut set = std::collections::HashSet::new(); | |
set.insert(grid![[1,2,3][4,5,6]]); | |
set.insert(grid![[1,3,3][4,5,6]]); | |
set.insert(grid![[1,2,3][4,5,6]]); | |
assert_eq!(set.len(), 2); | |
} | |
#[test] | |
fn macro_init() { | |
let grid = grid![[1, 2, 3][4, 5, 6]]; | |
test_grid(&grid, 2, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6]); | |
} | |
#[test] | |
fn macro_init_2() { | |
let grid = grid![[1, 2, 3] | |
[4, 5, 6] | |
[7, 8, 9]]; | |
test_grid(&grid, 3, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6, 7, 8, 9]); | |
} | |
#[test] | |
fn macro_init_char() { | |
let grid = grid![['a', 'b', 'c'] | |
['a', 'b', 'c'] | |
['a', 'b', 'c']]; | |
let expected = ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']; | |
test_grid(&grid, 3, 3, Order::RowMajor, &expected); | |
} | |
#[test] | |
fn macro_one_row() { | |
let grid: Grid<usize> = grid![[1, 2, 3, 4]]; | |
test_grid(&grid, 1, 4, Order::RowMajor, &[1, 2, 3, 4]); | |
} | |
#[test] | |
fn macro2_empty() { | |
let grid: Grid<u8> = grid_cm![]; | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
} | |
#[test] | |
fn macro2_init() { | |
let grid = grid_cm![[1, 2, 3] | |
[4, 5, 6] | |
[7, 8, 9]]; | |
let expected = [1, 4, 7, 2, 5, 8, 3, 6, 9]; | |
test_grid(&grid, 3, 3, Order::ColumnMajor, &expected); | |
} | |
#[test] | |
fn macro2_init_char() { | |
let grid = grid_cm![['a', 'b']['c', 'd']]; | |
test_grid(&grid, 2, 2, Order::ColumnMajor, &['a', 'c', 'b', 'd']); | |
} | |
#[test] | |
fn macro2_one_row() { | |
let grid = grid_cm![[1, 2, 3, 4]]; | |
test_grid(&grid, 1, 4, Order::ColumnMajor, &[1, 2, 3, 4]); | |
} | |
#[test] | |
fn init() { | |
let grid = Grid::init(1, 2, 3); | |
test_grid(&grid, 1, 2, Order::RowMajor, &[3, 3]); | |
let grid = Grid::init(1, 2, 1.2); | |
test_grid(&grid, 1, 2, Order::RowMajor, &[1.2, 1.2]); | |
let grid = Grid::init(1, 2, 'a'); | |
test_grid(&grid, 1, 2, Order::RowMajor, &['a', 'a']); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn init_panics() { | |
Grid::init(usize::MAX, 2, 3); | |
} | |
#[test] | |
fn init_empty() { | |
let grid = Grid::init(0, 1, 0); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
let grid = Grid::init(1, 0, -1); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
fn init_with_order() { | |
let grid = Grid::init_with_order(1, 2, Order::RowMajor, 3); | |
test_grid(&grid, 1, 2, Order::RowMajor, &[3, 3]); | |
let grid = Grid::init_with_order(1, 2, Order::ColumnMajor, 1.2); | |
test_grid(&grid, 1, 2, Order::ColumnMajor, &[1.2, 1.2]); | |
let grid = Grid::init_with_order(1, 2, Order::ColumnMajor, 'a'); | |
test_grid(&grid, 1, 2, Order::ColumnMajor, &['a', 'a']); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn init_with_order_panics() { | |
Grid::init_with_order(usize::MAX, 2, Order::ColumnMajor, 3); | |
} | |
#[test] | |
fn init_with_order_empty() { | |
let grid = Grid::init_with_order(0, 1, Order::ColumnMajor, 0); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
let grid = Grid::init_with_order(1, 0, Order::RowMajor, -1); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
fn new() { | |
let grid: Grid<u8> = Grid::new(1, 2); | |
test_grid(&grid, 1, 2, Order::RowMajor, &[0, 0]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn new_panics() { | |
let _: Grid<u8> = Grid::new(usize::MAX, 2); | |
} | |
#[test] | |
fn new_empty() { | |
let grid: Grid<u8> = Grid::new(0, 1); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
let grid: Grid<u8> = Grid::new(1, 0); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
fn new_with_order() { | |
let grid: Grid<u8> = Grid::new_with_order(2, 2, Order::ColumnMajor); | |
test_grid(&grid, 2, 2, Order::ColumnMajor, &[0, 0, 0, 0]); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn new_with_order_panics() { | |
let _: Grid<u8> = Grid::new_with_order(usize::MAX, 2, Order::ColumnMajor); | |
} | |
#[test] | |
fn new_with_order_empty() { | |
let grid: Grid<u8> = Grid::new_with_order(0, 3, Order::RowMajor); | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
let grid: Grid<u8> = Grid::new_with_order(3, 0, Order::ColumnMajor); | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
} | |
#[test] | |
fn with_capacity() { | |
// doesn't impl Default | |
struct Foo(); | |
let grid: Grid<Foo> = Grid::with_capacity(20, 20); | |
assert!(grid.is_empty()); | |
assert_eq!(grid.order(), Order::default()); | |
} | |
#[test] | |
fn with_capacity_and_order() { | |
// doesn't impl Default | |
struct Foo(); | |
let grid: Grid<Foo> = Grid::with_capacity_and_order(20, 20, Order::ColumnMajor); | |
assert!(grid.is_empty()); | |
assert_eq!(grid.order(), Order::ColumnMajor); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn with_capacity_panics_internal() { | |
// doesn't impl Default | |
struct Foo(); | |
let _grid: Grid<Foo> = Grid::with_capacity_and_order(usize::MAX, 2, Order::RowMajor); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn with_capacity_panics_vec() { | |
let rows: usize = isize::MAX.try_into().expect("isize::MAX is positive"); | |
assert!( | |
core::mem::size_of::<u8>() * rows < usize::MAX, | |
"shows that panic is from Vec::with_capacity, not internal check" | |
); | |
let _grid: Grid<u8> = Grid::with_capacity_and_order(rows, 2, Order::RowMajor); | |
} | |
#[test] | |
fn get() { | |
let grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); | |
assert_eq!(grid.get(0_i64, 1_i32), Some(&2)); | |
} | |
#[test] | |
fn get_column_major() { | |
let grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); | |
assert_eq!(grid.get(1, 0), Some(&2)); | |
} | |
#[test] | |
fn get_none() { | |
let grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); | |
assert_eq!(grid.get(1, 0), None); | |
} | |
#[test] | |
fn get_none_column_major() { | |
let grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); | |
assert_eq!(grid.get(0, 1), None); | |
} | |
#[test] | |
fn get_mut() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); | |
assert_eq!(grid.get_mut(0_i64, 1_i32), Some(&mut 2)); | |
} | |
#[test] | |
fn get_mut_column_major() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); | |
assert_eq!(grid.get_mut(1, 0), Some(&mut 2)); | |
} | |
#[test] | |
fn get_mut_none() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); | |
assert_eq!(grid.get_mut(1, 0), None); | |
} | |
#[test] | |
fn get_mut_none_column_major() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); | |
assert_eq!(grid.get_mut(0, 1), None); | |
} | |
#[test] | |
fn idx_tup() { | |
let grid: Grid<u8> = Grid::from_vec(vec![1, 2, 3, 4], 2); | |
assert_eq!(grid[(0, 0)], 1); | |
assert_eq!(grid[(0, 1)], 2); | |
assert_eq!(grid[(1, 0)], 3); | |
assert_eq!(grid[(1, 1)], 4); | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn idx_tup_panic_1() { | |
let grid = Grid::init(1, 2, 3); | |
let _ = grid[(20, 0)]; | |
} | |
#[test] | |
#[should_panic] | |
#[allow(clippy::should_panic_without_expect)] | |
fn idx_tup_panic_2() { | |
let grid = Grid::init(1, 2, 3); | |
let _ = grid[(0, 20)]; | |
} | |
#[test] | |
fn idx_tup_set() { | |
let mut grid = Grid::init(1, 2, 3); | |
grid[(0, 0)] = 4; | |
assert_eq!(grid[(0, 0)], 4); | |
} | |
#[test] | |
fn size() { | |
let grid = Grid::init(1, 2, 3); | |
assert_eq!(grid.size(), (1, 2)); | |
} | |
#[test] | |
fn transpose() { | |
let mut grid: Grid<u8> = grid![[1,2,3][4,5,6]]; | |
grid.transpose(); | |
assert_eq!(grid, grid![[1,4][2,5][3,6]]); | |
} | |
#[test] | |
fn fill() { | |
let mut grid: Grid<u8> = grid![[1,2,3][4,5,6]]; | |
grid.fill(7); | |
test_grid(&grid, 2, 3, Order::RowMajor, &[7, 7, 7, 7, 7, 7]); | |
} | |
#[test] | |
fn fill_with() { | |
let mut grid: Grid<u8> = grid![[1,2,3][4,5,6]]; | |
grid.fill_with(Default::default); | |
test_grid(&grid, 2, 3, Order::RowMajor, &[0, 0, 0, 0, 0, 0]); | |
} | |
#[test] | |
fn map() { | |
let grid: Grid<u8> = grid![[1,2,3][4,5,6]]; | |
let mapped = grid.map(|x| x * 2); | |
test_grid(&mapped, 2, 3, Order::RowMajor, &[2, 4, 6, 8, 10, 12]); | |
} | |
#[test] | |
fn map_ref() { | |
let grid: Grid<u8> = grid![[1,2,3][4,5,6]]; | |
let mapped = grid.map_ref(|x| *x * 2); | |
test_grid(&mapped, 2, 3, Order::RowMajor, &[2, 4, 6, 8, 10, 12]); | |
} | |
#[test] | |
#[allow(clippy::redundant_closure_for_method_calls)] | |
fn iter_rows() { | |
let grid: Grid<u8> = grid![[1,2,3][4,5,6]]; | |
let max_by_row: Vec<u8> = grid | |
.iter_rows() | |
.map(|row| row.max().unwrap()) | |
.copied() | |
.collect(); | |
assert_eq!(max_by_row, vec![3, 6]); | |
let sum_by_row: Vec<u8> = grid.iter_rows().map(|row| row.sum()).collect(); | |
assert_eq!(sum_by_row, vec![1 + 2 + 3, 4 + 5 + 6]); | |
} | |
#[test] | |
#[allow(clippy::redundant_closure_for_method_calls)] | |
fn iter_rows_rev() { | |
let grid: Grid<u8> = grid![[1,2,3][4,5,6]]; | |
let max_by_row: Vec<u8> = grid | |
.iter_rows() | |
.rev() | |
.map(|row| row.max().unwrap()) | |
.copied() | |
.collect(); | |
assert_eq!(max_by_row, vec![6, 3]); | |
let sum_by_row: Vec<u8> = grid.iter_rows().rev().map(|row| row.sum()).collect(); | |
assert_eq!(sum_by_row, vec![4 + 5 + 6, 1 + 2 + 3]); | |
} | |
#[test] | |
fn iter_rows_exact_size() { | |
let grid: Grid<u8> = grid![[1,2,3][4,5,6]]; | |
let mut row_iter = grid.iter_rows(); | |
assert_eq!(row_iter.len(), 2); | |
assert!(row_iter.next().is_some()); | |
assert_eq!(row_iter.len(), 1); | |
assert!(row_iter.next().is_some()); | |
assert_eq!(row_iter.len(), 0); | |
assert!(row_iter.next().is_none()); | |
} | |
#[test] | |
#[allow(clippy::redundant_closure_for_method_calls)] | |
fn iter_cols() { | |
let grid: Grid<u8> = grid![[1,2,3][4,5,6]]; | |
let max_by_col: Vec<u8> = grid | |
.iter_cols() | |
.map(|col| col.max().unwrap()) | |
.copied() | |
.collect(); | |
assert_eq!(max_by_col, vec![4, 5, 6]); | |
let sum_by_col: Vec<u8> = grid.iter_cols().map(|row| row.sum()).collect(); | |
assert_eq!(sum_by_col, vec![1 + 4, 2 + 5, 3 + 6]); | |
} | |
#[test] | |
#[allow(clippy::redundant_closure_for_method_calls)] | |
fn iter_cols_rev() { | |
let grid: Grid<u8> = grid![[1,2,3][4,5,6]]; | |
let max_by_col: Vec<u8> = grid | |
.iter_cols() | |
.rev() | |
.map(|col| col.max().unwrap()) | |
.copied() | |
.collect(); | |
assert_eq!(max_by_col, vec![6, 5, 4]); | |
let sum_by_col: Vec<u8> = grid.iter_cols().rev().map(|row| row.sum()).collect(); | |
assert_eq!(sum_by_col, vec![3 + 6, 2 + 5, 1 + 4]); | |
} | |
#[test] | |
fn iter_cols_exact_size() { | |
let grid: Grid<u8> = grid![[1,2,3][4,5,6]]; | |
let mut col_iter = grid.iter_cols(); | |
assert_eq!(col_iter.len(), 3); | |
assert!(col_iter.next().is_some()); | |
assert_eq!(col_iter.len(), 2); | |
assert!(col_iter.next().is_some()); | |
assert_eq!(col_iter.len(), 1); | |
assert!(col_iter.next().is_some()); | |
assert_eq!(col_iter.len(), 0); | |
assert!(col_iter.next().is_none()); | |
} | |
#[test] | |
fn remove_row() { | |
let mut grid = grid![[1,2][3,4][5,6]]; | |
assert_eq![grid.remove_row(1), Some(vec![3, 4])]; | |
test_grid(&grid, 2, 2, Order::RowMajor, &[1, 2, 5, 6]); | |
assert_eq![grid.remove_row(0), Some(vec![1, 2])]; | |
test_grid(&grid, 1, 2, Order::RowMajor, &[5, 6]); | |
assert_eq![grid.remove_row(0), Some(vec![5, 6])]; | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
assert_eq![grid.remove_row(0), None]; | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
fn remove_row_out_of_bound() { | |
let mut grid = grid![[1, 2][3, 4]]; | |
assert_eq![grid.remove_row(5), None]; | |
test_grid(&grid, 2, 2, Order::RowMajor, &[1, 2, 3, 4]); | |
assert_eq![grid.remove_row(1), Some(vec![3, 4])]; | |
test_grid(&grid, 1, 2, Order::RowMajor, &[1, 2]); | |
} | |
#[test] | |
fn remove_row_column_major() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 3, 5, 2, 4, 6], 2, Order::ColumnMajor); | |
assert_eq![grid.remove_row(1), Some(vec![3, 4])]; | |
test_grid(&grid, 2, 2, Order::ColumnMajor, &[1, 5, 2, 6]); | |
assert_eq![grid.remove_row(0), Some(vec![1, 2])]; | |
test_grid(&grid, 1, 2, Order::ColumnMajor, &[5, 6]); | |
assert_eq![grid.remove_row(0), Some(vec![5, 6])]; | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
assert_eq![grid.remove_row(0), None]; | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
} | |
#[test] | |
fn remove_row_out_of_bound_column_major() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
assert_eq![grid.remove_row(5), None]; | |
test_grid(&grid, 2, 2, Order::ColumnMajor, &[1, 3, 2, 4]); | |
assert_eq![grid.remove_row(1), Some(vec![3, 4])]; | |
test_grid(&grid, 1, 2, Order::ColumnMajor, &[1, 2]); | |
} | |
#[test] | |
fn remove_col() { | |
let mut grid = grid![[1,2,3,4][5,6,7,8][9,10,11,12][13,14,15,16]]; | |
assert_eq![grid.remove_col(3), Some(vec![4, 8, 12, 16])]; | |
let expected = [1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15]; | |
test_grid(&grid, 4, 3, Order::RowMajor, &expected); | |
assert_eq![grid.remove_col(0), Some(vec![1, 5, 9, 13])]; | |
test_grid(&grid, 4, 2, Order::RowMajor, &[2, 3, 6, 7, 10, 11, 14, 15]); | |
assert_eq![grid.remove_col(1), Some(vec![3, 7, 11, 15])]; | |
test_grid(&grid, 4, 1, Order::RowMajor, &[2, 6, 10, 14]); | |
assert_eq![grid.remove_col(0), Some(vec![2, 6, 10, 14])]; | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
assert_eq![grid.remove_col(0), None]; | |
test_grid(&grid, 0, 0, Order::RowMajor, &[]); | |
} | |
#[test] | |
fn remove_col_out_of_bound() { | |
let mut grid = grid![[1, 2][3, 4]]; | |
assert_eq!(grid.remove_col(5), None); | |
test_grid(&grid, 2, 2, Order::RowMajor, &[1, 2, 3, 4]); | |
assert_eq!(grid.remove_col(1), Some(vec![2, 4])); | |
test_grid(&grid, 2, 1, Order::RowMajor, &[1, 3]); | |
} | |
#[test] | |
fn remove_col_column_major() { | |
let internal = vec![1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16]; | |
let mut grid = Grid::from_vec_with_order(internal, 4, Order::ColumnMajor); | |
assert_eq![grid.remove_col(3), Some(vec![4, 8, 12, 16])]; | |
let expected = [1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15]; | |
test_grid(&grid, 4, 3, Order::ColumnMajor, &expected); | |
assert_eq![grid.remove_col(0), Some(vec![1, 5, 9, 13])]; | |
let expected = [2, 6, 10, 14, 3, 7, 11, 15]; | |
test_grid(&grid, 4, 2, Order::ColumnMajor, &expected); | |
assert_eq![grid.remove_col(1), Some(vec![3, 7, 11, 15])]; | |
test_grid(&grid, 4, 1, Order::ColumnMajor, &[2, 6, 10, 14]); | |
assert_eq![grid.remove_col(0), Some(vec![2, 6, 10, 14])]; | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
assert_eq![grid.remove_col(0), None]; | |
test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); | |
} | |
#[test] | |
fn remove_col_out_of_bound_column_major() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
assert_eq!(grid.remove_col(5), None); | |
test_grid(&grid, 2, 2, Order::ColumnMajor, &[1, 3, 2, 4]); | |
assert_eq!(grid.remove_col(1), Some(vec![2, 4])); | |
test_grid(&grid, 2, 1, Order::ColumnMajor, &[1, 3]); | |
} | |
#[test] | |
fn flip_cols() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); | |
grid.flip_cols(); | |
test_grid(&grid, 2, 2, Order::RowMajor, &[2, 1, 4, 3]); | |
} | |
#[test] | |
fn flip_cols_column_major() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
grid.flip_cols(); | |
test_grid(&grid, 2, 2, Order::ColumnMajor, &[2, 4, 1, 3]); | |
} | |
#[test] | |
fn flip_rows() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); | |
grid.flip_rows(); | |
test_grid(&grid, 2, 2, Order::RowMajor, &[3, 4, 1, 2]); | |
} | |
#[test] | |
fn flip_rows_column_major() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); | |
grid.flip_rows(); | |
test_grid(&grid, 2, 2, Order::ColumnMajor, &[3, 1, 4, 2]); | |
} | |
#[test] | |
fn rotate_left() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); | |
grid.rotate_left(); | |
test_grid(&grid, 3, 2, Order::ColumnMajor, &[3, 2, 1, 6, 5, 4]); | |
assert_eq!(grid, grid![[3,6][2,5][1,4]]); | |
} | |
#[test] | |
fn rotate_left_column_major() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); | |
grid.rotate_left(); | |
test_grid(&grid, 3, 2, Order::RowMajor, &[3, 6, 2, 5, 1, 4]); | |
assert_eq!(grid, grid![[3,6][2,5][1,4]]); | |
} | |
#[test] | |
fn rotate_right() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); | |
grid.rotate_right(); | |
test_grid(&grid, 3, 2, Order::ColumnMajor, &[4, 5, 6, 1, 2, 3]); | |
assert_eq!(grid, grid![[4,1][5,2][6,3]]); | |
} | |
#[test] | |
fn rotate_right_column_major() { | |
let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); | |
grid.rotate_right(); | |
test_grid(&grid, 3, 2, Order::RowMajor, &[4, 1, 5, 2, 6, 3]); | |
assert_eq!(grid, grid![[4,1][5,2][6,3]]); | |
} | |
#[test] | |
fn iter_cols_clone() { | |
let grid = grid![[1,2,3][4,5,6]]; | |
let mut cols = grid.iter_cols().skip(1); | |
let c3: u8 = cols.clone().nth(1).unwrap().sum(); | |
let c2: u8 = cols.next().unwrap().sum(); | |
assert_eq!(c2, 2 + 5); | |
assert_eq!(c3, 3 + 6); | |
} | |
#[test] | |
fn iter_rows_clone() { | |
let grid = grid![[1,2,3][4,5,6][7,8,9]]; | |
let mut rows = grid.iter_rows().skip(1); | |
let r3: u8 = rows.clone().nth(1).unwrap().sum(); | |
let r2: u8 = rows.next().unwrap().sum(); | |
assert_eq!(r2, 4 + 5 + 6); | |
assert_eq!(r3, 7 + 8 + 9); | |
} | |
#[test] | |
fn swap() { | |
let mut grid = grid![[1,2][4,5]]; | |
grid.swap((0, 0), (1, 0)); | |
let end_grid = grid![[4,2][1,5]]; | |
assert_eq!(grid, end_grid); | |
} | |
#[test] | |
#[should_panic(expected = "grid index out of bounds: (2,0) out of (2,2)")] | |
fn swap_out_of_bounds() { | |
let mut grid = grid![[1,2][4,5]]; | |
grid.swap((0, 0), (2, 0)); | |
} | |
#[cfg(feature = "serde")] | |
mod serde_tests { | |
use super::*; | |
#[test] | |
fn serialize() { | |
let grid: Grid<u8> = grid![[1, 2][3, 4]]; | |
let s = serde_json::to_string(&grid).unwrap(); | |
assert_eq!(s, r#"{"cols":2,"data":[1,2,3,4],"order":"RowMajor"}"#); | |
} | |
#[test] | |
fn deserialize() { | |
let s = "{ \"cols\": 2, \"data\": [1, 2, 3, 4] }"; | |
let grid: Grid<u8> = serde_json::from_str(s).unwrap(); | |
assert_eq!(grid, grid![[1, 2][3, 4]]); | |
} | |
#[test] | |
fn deserialize_with_order() { | |
let s = "{ \"cols\": 2, \"data\": [1, 3, 2, 4], \"order\": \"ColumnMajor\" }"; | |
let grid: Grid<u8> = serde_json::from_str(s).unwrap(); | |
test_grid(&grid, 2, 2, Order::ColumnMajor, &[1, 3, 2, 4]); | |
} | |
} | |
} |