From 5d33f75c05b212c7f2f78ad55dcd2aa11eae37fb Mon Sep 17 00:00:00 2001 From: Alberto Ibarrondo Date: Thu, 22 Aug 2024 18:08:17 +0200 Subject: [PATCH 1/5] Quick linter fixes --- src/lib.rs | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3fa7967..f373606 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,15 +52,15 @@ use serde::{ 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}; +use core::{ + cmp, + cmp::Eq, + convert::TryInto, + fmt, hash, + iter::StepBy, + ops::{Index, IndexMut}, + slice::{Iter, IterMut}, +}; #[doc(hidden)] #[macro_export] @@ -321,7 +321,7 @@ impl Grid { /// /// ``` /// use grid::Grid; - /// let grid : Grid = Grid::new(2,3); + /// let grid: Grid = Grid::new(2, 3); /// assert_eq!(grid[(0, 0)], 0); /// ``` /// @@ -422,7 +422,7 @@ impl Grid { /// /// ``` /// use grid::Grid; - /// let grid = Grid::from_vec(vec![1,2,3,4,5,6], 3); + /// let grid = Grid::from_vec(vec![1, 2, 3, 4, 5, 6], 3); /// assert_eq!(grid.size(), (2, 3)); /// ``` /// @@ -434,7 +434,7 @@ impl Grid { /// /// ``` should_panic /// use grid::Grid; - /// Grid::from_vec(vec![1,2,3,4,5], 3); + /// Grid::from_vec(vec![1, 2, 3, 4, 5], 3); /// ``` /// /// # Panics @@ -493,7 +493,8 @@ impl Grid { /// /// # Safety /// - /// Calling this method with an out-of-bounds index is undefined behavior even if the resulting reference is not used. + /// 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, col: impl Into) -> &T { @@ -506,7 +507,8 @@ impl Grid { /// /// # Safety /// - /// Calling this method with an out-of-bounds index is undefined behavior even if the resulting reference is not used. + /// 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( @@ -577,7 +579,7 @@ impl Grid { /// For example: /// ``` /// use grid::*; - /// let grid : Grid = grid![]; + /// let grid: Grid = grid![]; /// assert!(grid.is_empty()); /// ``` #[must_use] @@ -875,7 +877,7 @@ impl Grid { /// ``` /// use grid::*; /// let mut grid: Grid = grid![]; - /// let row = vec![1,2,3]; + /// let row = vec![1, 2, 3]; /// grid.push_row(row); /// assert_eq!(grid.size(), (1, 3)); /// ``` @@ -929,7 +931,7 @@ impl Grid { /// ``` /// use grid::*; /// let mut grid: Grid = grid![]; - /// let col = vec![1,2,3]; + /// let col = vec![1, 2, 3]; /// grid.push_col(col); /// assert_eq!(grid.size(), (3, 1)); /// ``` @@ -1336,8 +1338,8 @@ impl Grid { /// /// # Performance /// - /// This method will be significantly slower if the grid initialy uses a column-major memory layout, - /// which is the default. + /// 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(); @@ -1358,8 +1360,8 @@ impl Grid { /// /// # Performance /// - /// This method will be significantly slower if the grid initialy uses a row-major memory layout, - /// which is the default. + /// 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(); From c2b2ad75c369d20200053bcd098a32946288d436 Mon Sep 17 00:00:00 2001 From: Alberto Ibarrondo Date: Thu, 22 Aug 2024 18:36:38 +0200 Subject: [PATCH 2/5] get_row and get_col --- src/lib.rs | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index f373606..4e4a610 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -550,6 +550,62 @@ impl Grid { } } + /// Access a certain row on the grid. + /// Returns `None` if a row beyond the grid bounds is tried to be accessed, + /// or if the grid is column-major. + #[must_use] + pub fn get_row(&self, row: impl TryInto) -> Option<&[T]> { + let row_usize = row.try_into().ok()?; + if row_usize < self.rows && self.order == Order::RowMajor { + let start = row_usize * self.cols; + Some(self.data[start..(start + self.cols)].as_ref()) + } else { + None + } + } + + /// Mutable access to a certain row on the grid. + /// Returns `None` if a row beyond the grid bounds is tried to be accessed, + /// or if the grid is column-major. + #[must_use] + pub fn get_mut_row(&mut self, row: impl TryInto) -> Option<&mut [T]> { + let row_usize = row.try_into().ok()?; + if row_usize < self.rows && self.order == Order::RowMajor { + let start = row_usize * self.cols; + Some(self.data[start..(start + self.cols)].as_mut()) + } else { + None + } + } + + /// Access a certain column on the grid. + /// Returns `None` if a column beyond the grid bounds is tried to be accessed, + /// or if the grid is row-major. + #[must_use] + pub fn get_col(&self, column: impl TryInto) -> Option<&[T]> { + let column_usize = column.try_into().ok()?; + if column_usize < self.cols && self.order == Order::ColumnMajor { + let start = column_usize * self.rows; + Some(self.data[start..(start + self.rows)].as_ref()) + } else { + None + } + } + + /// Mutable access to a certain column on the grid. + /// Returns `None` if a column beyond the grid bounds is tried to be accessed, + /// or if the grid is row-major. + #[must_use] + pub fn get_mut_col(&mut self, column: impl TryInto) -> Option<&mut [T]> { + let column_usize = column.try_into().ok()?; + if column_usize < self.cols && self.order == Order::ColumnMajor { + let start = column_usize * self.rows; + Some(self.data[start..(start + self.rows)].as_mut()) + } 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] @@ -3075,6 +3131,54 @@ mod test { assert_eq!(grid.get(0, 1), None); } + #[test] + fn get_row() { + let grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); + assert_eq!(grid.get_row(0), Some([1, 2].as_slice())); + } + + #[test] + fn get_row_column_major() { + let grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); + assert_eq!(grid.get_row(0), None); + } + + #[test] + fn get_row_none() { + let grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); + assert_eq!(grid.get_row(1), None); + } + + #[test] + fn get_row_none_column_major() { + let grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); + assert_eq!(grid.get_row(1), None); + } + + #[test] + fn get_col() { + let grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); + assert_eq!(grid.get_col(0), Some([1, 2].as_slice())); + } + + #[test] + fn get_col_row_major() { + let grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::RowMajor); + assert_eq!(grid.get_col(0), None); + } + + #[test] + fn get_col_none() { + let grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); + assert_eq!(grid.get_col(1), None); + } + + #[test] + fn get_col_none_column_major() { + let grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::RowMajor); + assert_eq!(grid.get_col(1), None); + } + #[test] fn get_mut() { let mut grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); @@ -3099,6 +3203,54 @@ mod test { assert_eq!(grid.get_mut(0, 1), None); } + #[test] + fn get_mut_col() { + let mut grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); + assert_eq!(grid.get_mut_col(0), Some([1, 2].as_mut_slice())); + } + + #[test] + fn get_mut_col_row_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::RowMajor); + assert_eq!(grid.get_mut_col(0), None); + } + + #[test] + fn get_mut_col_none() { + let mut grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); + assert_eq!(grid.get_mut_col(1), None); + } + + #[test] + fn get_mut_col_none_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::RowMajor); + assert_eq!(grid.get_mut_col(1), None); + } + + #[test] + fn get_mut_row() { + let mut grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); + assert_eq!(grid.get_mut_row(0), Some([1, 2].as_mut_slice())); + } + + #[test] + fn get_mut_row_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); + assert_eq!(grid.get_mut_row(0), None); + } + + #[test] + fn get_mut_row_none() { + let mut grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); + assert_eq!(grid.get_mut_row(1), None); + } + + #[test] + fn get_mut_row_none_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); + assert_eq!(grid.get_mut_row(1), None); + } + #[test] fn idx_tup() { let grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); From a22eaa93e4bed4d54a1ad9f3b48d5a3ffa9e84fc Mon Sep 17 00:00:00 2001 From: Alberto Ibarrondo Date: Wed, 28 Aug 2024 17:19:26 +0200 Subject: [PATCH 3/5] iter_rows_as_slices and iter_cols_as_slices --- src/lib.rs | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 4e4a610..768b177 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1507,6 +1507,33 @@ impl Grid { } } + /// Iterate over the rows of the grid as slices. It only holds meaning if the grid + /// is row-major. + #[must_use] + pub fn iter_rows_as_slices( + &self, + ) -> Option + ExactSizeIterator> { + if self.order == Order::RowMajor { + Some(self.data.chunks_exact(self.cols)) + } else { + None + } + } + + /// Iterate over the rows of the grid as slices. It only holds meaning if the grid + /// is row-major. + #[must_use] + pub fn iter_rows_as_slices_mut( + &mut self, + ) -> Option + ExactSizeIterator> + { + if self.order == Order::RowMajor { + Some(self.data.chunks_exact_mut(self.cols)) + } else { + None + } + } + /// Iterate over the columns of the grid. Each time an iterator over a single /// column is returned. /// @@ -1530,6 +1557,33 @@ impl Grid { } } + /// Iterate over the columns of the grid as slices. It only holds meaning if the + /// grid is column-major. + #[must_use] + pub fn iter_cols_as_slices( + &self, + ) -> Option + ExactSizeIterator> { + if self.order == Order::ColumnMajor { + Some(self.data.chunks_exact(self.rows)) + } else { + None + } + } + + /// Iterate over the columns of the grid as slices. It only holds meaning if the + /// grid is column-major. + #[must_use] + pub fn iter_cols_as_slices_mut( + &mut self, + ) -> Option + ExactSizeIterator> + { + if self.order == Order::ColumnMajor { + Some(self.data.chunks_exact_mut(self.rows)) + } else { + None + } + } + /// Swaps two elements in the Grid. /// Similar to `Vec::swap()`. /// @@ -3353,6 +3407,66 @@ mod test { assert!(row_iter.next().is_none()); } + #[test] + fn iter_rows_as_slices() { + let grid: Grid = grid![[1,2,3][4,5,6]]; + let mut row_iter = grid.iter_rows_as_slices().unwrap(); + assert_eq!(row_iter.next(), Some(&[1, 2, 3][..])); + assert_eq!(row_iter.next(), Some(&[4, 5, 6][..])); + assert_eq!(row_iter.next(), None); + } + + #[test] + fn iter_rows_as_slices_rev() { + let grid: Grid = grid![[1,2,3][4,5,6]]; + let mut row_iter = grid.iter_rows_as_slices().unwrap().rev(); + assert_eq!(row_iter.next(), Some(&[4, 5, 6][..])); + assert_eq!(row_iter.next(), Some(&[1, 2, 3][..])); + assert_eq!(row_iter.next(), None); + } + + #[test] + fn iter_rows_as_slices_exact_size() { + let grid: Grid = grid![[1,2,3][4,5,6]]; + let mut row_iter = grid.iter_rows_as_slices().unwrap(); + 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] + fn iter_rows_as_slices_mut() { + let mut grid: Grid = grid![[1,2,3][4,5,6]]; + let mut row_iter = grid.iter_rows_as_slices_mut().unwrap(); + assert_eq!(row_iter.next(), Some(&mut [1, 2, 3][..])); + assert_eq!(row_iter.next(), Some(&mut [4, 5, 6][..])); + assert_eq!(row_iter.next(), None); + } + + #[test] + fn iter_rows_as_slices_mut_rev() { + let mut grid: Grid = grid![[1,2,3][4,5,6]]; + let mut row_iter = grid.iter_rows_as_slices_mut().unwrap().rev(); + assert_eq!(row_iter.next(), Some(&mut [4, 5, 6][..])); + assert_eq!(row_iter.next(), Some(&mut [1, 2, 3][..])); + assert_eq!(row_iter.next(), None); + } + + #[test] + fn iter_rows_as_slices_mut_exact_size() { + let mut grid: Grid = grid![[1,2,3][4,5,6]]; + let mut row_iter = grid.iter_rows_as_slices_mut().unwrap(); + 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() { @@ -3400,6 +3514,74 @@ mod test { assert!(col_iter.next().is_none()); } + #[test] + fn iter_cols_as_slices() { + let grid: Grid = grid_cm![[1,2,3][4,5,6]]; + let mut col_iter = grid.iter_cols_as_slices().unwrap(); + assert_eq!(col_iter.next(), Some(&[1, 4][..])); + assert_eq!(col_iter.next(), Some(&[2, 5][..])); + assert_eq!(col_iter.next(), Some(&[3, 6][..])); + assert_eq!(col_iter.next(), None); + } + + #[test] + fn iter_cols_as_slices_rev() { + let grid: Grid = grid_cm![[1,2,3][4,5,6]]; + let mut col_iter = grid.iter_cols_as_slices().unwrap().rev(); + assert_eq!(col_iter.next(), Some(&[3, 6][..])); + assert_eq!(col_iter.next(), Some(&[2, 5][..])); + assert_eq!(col_iter.next(), Some(&[1, 4][..])); + assert_eq!(col_iter.next(), None); + } + + #[test] + fn iter_cols_as_slices_exact_size() { + let grid: Grid = grid_cm![[1,2,3][4,5,6]]; + let mut col_iter = grid.iter_cols_as_slices().unwrap(); + 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 iter_cols_as_slices_mut() { + let mut grid: Grid = grid_cm![[1,2,3][4,5,6]]; + let mut col_iter = grid.iter_cols_as_slices_mut().unwrap(); + assert_eq!(col_iter.next(), Some(&mut [1, 4][..])); + assert_eq!(col_iter.next(), Some(&mut [2, 5][..])); + assert_eq!(col_iter.next(), Some(&mut [3, 6][..])); + assert_eq!(col_iter.next(), None); + } + + #[test] + fn iter_cols_as_slices_mut_rev() { + let mut grid: Grid = grid_cm![[1,2,3][4,5,6]]; + let mut col_iter = grid.iter_cols_as_slices_mut().unwrap().rev(); + assert_eq!(col_iter.next(), Some(&mut [3, 6][..])); + assert_eq!(col_iter.next(), Some(&mut [2, 5][..])); + assert_eq!(col_iter.next(), Some(&mut [1, 4][..])); + assert_eq!(col_iter.next(), None); + } + + #[test] + fn iter_cols_as_slices_mut_exact_size() { + let mut grid: Grid = grid_cm![[1,2,3][4,5,6]]; + let mut col_iter = grid.iter_cols_as_slices_mut().unwrap(); + 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]]; From 8ab91dfeb1c261c3735f73398b7b32b5bb71289d Mon Sep 17 00:00:00 2001 From: Alberto Ibarrondo Date: Wed, 28 Aug 2024 17:19:47 +0200 Subject: [PATCH 4/5] IntoIterator --- src/lib.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 768b177..d73ccce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1786,6 +1786,22 @@ impl From<(&Vec, &usize)> for Grid { } } +impl<'a, T> IntoIterator for &'a Grid { + type IntoIter = std::slice::Iter<'a, T>; + type Item = &'a T; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, T> IntoIterator for &'a mut Grid { + type IntoIter = std::slice::IterMut<'a, T>; + type Item = &'a mut T; + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + #[derive(Clone)] pub struct GridRowIter<'a, T> { grid: &'a Grid, From 32f6ae1147b2eb78cf0707686d6008f962ed5b05 Mon Sep 17 00:00:00 2001 From: Alberto Ibarrondo Date: Wed, 28 Aug 2024 17:35:40 +0200 Subject: [PATCH 5/5] Avoiding anonymous types in as_slice iterators --- src/lib.rs | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d73ccce..256a2d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,13 +53,12 @@ use serde::{ }; use core::{ - cmp, - cmp::Eq, + cmp::{self, Eq}, convert::TryInto, fmt, hash, iter::StepBy, ops::{Index, IndexMut}, - slice::{Iter, IterMut}, + slice::{ChunksExact, ChunksExactMut, Iter, IterMut}, }; #[doc(hidden)] @@ -1510,9 +1509,7 @@ impl Grid { /// Iterate over the rows of the grid as slices. It only holds meaning if the grid /// is row-major. #[must_use] - pub fn iter_rows_as_slices( - &self, - ) -> Option + ExactSizeIterator> { + pub fn iter_rows_as_slices(&self) -> Option> { if self.order == Order::RowMajor { Some(self.data.chunks_exact(self.cols)) } else { @@ -1523,10 +1520,7 @@ impl Grid { /// Iterate over the rows of the grid as slices. It only holds meaning if the grid /// is row-major. #[must_use] - pub fn iter_rows_as_slices_mut( - &mut self, - ) -> Option + ExactSizeIterator> - { + pub fn iter_rows_as_slices_mut(&mut self) -> Option> { if self.order == Order::RowMajor { Some(self.data.chunks_exact_mut(self.cols)) } else { @@ -1560,9 +1554,7 @@ impl Grid { /// Iterate over the columns of the grid as slices. It only holds meaning if the /// grid is column-major. #[must_use] - pub fn iter_cols_as_slices( - &self, - ) -> Option + ExactSizeIterator> { + pub fn iter_cols_as_slices(&self) -> Option> { if self.order == Order::ColumnMajor { Some(self.data.chunks_exact(self.rows)) } else { @@ -1573,10 +1565,7 @@ impl Grid { /// Iterate over the columns of the grid as slices. It only holds meaning if the /// grid is column-major. #[must_use] - pub fn iter_cols_as_slices_mut( - &mut self, - ) -> Option + ExactSizeIterator> - { + pub fn iter_cols_as_slices_mut(&mut self) -> Option> { if self.order == Order::ColumnMajor { Some(self.data.chunks_exact_mut(self.rows)) } else {