From 7fa00e4d863af8c0105cf502482e6df46705e202 Mon Sep 17 00:00:00 2001 From: Chris Bowers Date: Wed, 13 Dec 2023 11:22:06 -0500 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=E2=9C=A8=20Improve=20get=20and=20g?= =?UTF-8?q?et=5Fmut=20signatures?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 606eb6e..89493c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,7 +52,6 @@ use serde::{ ser::{Serialize, SerializeStruct, Serializer}, }; -use core::cmp; use core::cmp::Eq; use core::fmt; use core::iter::StepBy; @@ -60,6 +59,7 @@ 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] @@ -516,9 +516,11 @@ impl Grid { /// 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: usize, col: usize) -> Option<&T> { - if row < self.rows && col < self.cols { - unsafe { Some(self.get_unchecked(row, col)) } + pub fn get>(&self, row: U, col: U) -> 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 } @@ -527,9 +529,11 @@ impl Grid { /// 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: usize, col: usize) -> Option<&mut T> { - if row < self.rows && col < self.cols { - unsafe { Some(self.get_unchecked_mut(row, col)) } + pub fn get_mut>(&mut self, row: U, col: U) -> 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 } From 3c4c7e2f9ee674704dd0e8f360b9a7cd25006078 Mon Sep 17 00:00:00 2001 From: Chris Bowers Date: Wed, 13 Dec 2023 11:45:25 -0500 Subject: [PATCH 2/6] =?UTF-8?q?chore:=20=F0=9F=9A=A8=20Fix=20clippy=20lint?= =?UTF-8?q?=20warnings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 10 +++--- src/lib.rs | 97 +++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 75 insertions(+), 32 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9c789c7..be4582a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,8 @@ version = "0.12.0" authors = ["Armin Becher "] edition = "2018" description = "Dynamic generic 2D data structure." -keywords = [ "2D", "array", "matrix", "data-structure", "2D-vector"] -categories = [ "science", "data-structures",] +keywords = ["2D", "array", "matrix", "data-structure", "2D-vector"] +categories = ["science", "data-structures"] readme = "README.md" license = "MIT" repository = "https://github.com/becheran/grid" @@ -23,7 +23,7 @@ serde = { version = "1.0.188", features = ["derive"], optional = true } [dev-dependencies] criterion = "0.3.6" -rand="0.8.5" +rand = "0.8.5" serde_json = "1.0.106" [[bench]] @@ -31,6 +31,6 @@ name = "benches" harness = false [features] -default = [ "std" ] # Default to using the std +default = ["std"] # Default to using the std std = [] -serde = [ "std", "dep:serde" ] +serde = ["std", "dep:serde"] diff --git a/src/lib.rs b/src/lib.rs index 89493c9..dcd9661 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1592,12 +1592,14 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn from_vec_panics_1() { let _: Grid = Grid::from_vec(vec![1, 2, 3], 0); } #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn from_vec_panics_2() { let _: Grid = Grid::from_vec(vec![1, 2, 3], 2); } @@ -1624,12 +1626,14 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn from_vec_with_order_panics_1() { let _: Grid = 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 = Grid::from_vec_with_order(vec![1, 2, 3], 2, Order::ColumnMajor); } @@ -1651,6 +1655,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn insert_col_out_of_idx() { let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); grid.insert_col(3, vec![4, 5]); @@ -1672,6 +1677,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn insert_col_out_of_idx_column_major() { let mut grid: Grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); grid.insert_col(3, vec![4, 5]); @@ -1700,6 +1706,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn insert_row_out_of_idx() { let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); grid.insert_row(3, vec![4, 5]); @@ -1707,6 +1714,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn insert_row_wrong_size_of_idx() { let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); grid.insert_row(1, vec![4, 5, 4]); @@ -1735,6 +1743,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn insert_row_out_of_idx_column_major() { let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::ColumnMajor); grid.insert_row(3, vec![4, 5]); @@ -1742,6 +1751,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn insert_row_wrong_size_of_idx_column_major() { let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::ColumnMajor); grid.insert_row(1, vec![4, 5, 4]); @@ -1950,6 +1960,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn idx_tup_out_of_col_bounds() { let grid: Grid = grid![['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']]; let _ = grid[(0, 5)]; @@ -1993,6 +2004,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn push_col_wrong_size() { let mut grid: Grid = grid![['a','a','a']['a','a','a']]; grid.push_col(vec!['b']); @@ -2001,6 +2013,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn push_col_zero_len() { let mut grid: Grid = grid![]; grid.push_col(vec![]); @@ -2043,6 +2056,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn push_col_wrong_size_column_major() { let mut grid: Grid = Grid::init_with_order(2, 3, Order::ColumnMajor, 'a'); grid.push_col(vec!['b']); @@ -2051,6 +2065,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn push_col_zero_len_column_major() { let mut grid: Grid = Grid::new_with_order(0, 0, Order::ColumnMajor); grid.push_col(vec![]); @@ -2072,6 +2087,7 @@ mod test { #[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![]); @@ -2079,6 +2095,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn push_row_wrong_size() { let mut grid: Grid = grid![['a','a','a']['a','a','a']]; grid.push_row(vec!['b']); @@ -2101,6 +2118,7 @@ mod test { #[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![]); @@ -2108,6 +2126,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn push_row_wrong_size_column_major() { let mut grid: Grid = Grid::from_vec_with_order(vec!['a', 'a', 'a', 'a', 'a', 'a'], 3, Order::ColumnMajor); @@ -2124,6 +2143,7 @@ mod test { #[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); @@ -2131,6 +2151,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn iter_row_zero() { let grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); let _ = grid.iter_row(0); @@ -2145,6 +2166,7 @@ mod test { #[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); @@ -2152,6 +2174,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn iter_row_rowumn_major_zero() { let grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); let _ = grid.iter_row(0); @@ -2166,6 +2189,7 @@ mod test { #[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); @@ -2173,6 +2197,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn iter_row_mut_zero() { let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); let _ = grid.iter_row_mut(0); @@ -2187,6 +2212,7 @@ mod test { #[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); @@ -2194,6 +2220,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn iter_row_mut_rowumn_major_zero() { let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); let _ = grid.iter_row_mut(0); @@ -2208,6 +2235,7 @@ mod test { #[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); @@ -2215,6 +2243,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn iter_col_zero() { let grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); let _ = grid.iter_col(0); @@ -2229,6 +2258,7 @@ mod test { #[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); @@ -2236,6 +2266,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn iter_col_column_major_zero() { let grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); let _ = grid.iter_col(0); @@ -2250,6 +2281,7 @@ mod test { #[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); @@ -2257,6 +2289,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn iter_col_mut_zero() { let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); let _ = grid.iter_col_mut(0); @@ -2271,6 +2304,7 @@ mod test { #[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); @@ -2278,6 +2312,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn iter_col_mut_column_major_zero() { let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); let _ = grid.iter_col_mut(0); @@ -2365,31 +2400,31 @@ mod test { #[test] fn fmt_empty() { let grid: Grid = grid![]; - assert_eq!(format!("{:?}", grid), "[]"); + assert_eq!(format!("{grid:?}"), "[]"); } #[test] fn fmt_row() { let grid: Grid = grid![[1, 2, 3]]; - assert_eq!(format!("{:?}", grid), "[[1, 2, 3]]"); + assert_eq!(format!("{grid:?}"), "[[1, 2, 3]]"); } #[test] fn fmt_grid() { let grid: Grid = grid![[1,2,3][4,5,6][7,8,9]]; - assert_eq!(format!("{:?}", 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]]"); + assert_eq!(format!("{grid:?}"), "[[1, 2, 3][4, 5, 6]]"); } #[test] fn fmt_pretty_empty() { let grid: Grid = grid![]; - assert_eq!(format!("{:#?}", grid), "[]"); + assert_eq!(format!("{grid:#?}"), "[]"); } #[test] @@ -2400,21 +2435,21 @@ mod test { [7,8,95] ]; - let expected_output = r#"[ + let expected_output = r"[ [ 1, 2, 3] [ 4, 5, 6] [ 7, 8, 95] -]"#; +]"; - assert_eq!(format!("{:#?}", grid), expected_output); + assert_eq!(format!("{grid:#?}"), expected_output); - let expected_output = r#"[ + let expected_output = r"[ [ 1, 2, 3] [ 4, 5, 6] [ 7, 8, 95] -]"#; +]"; - assert_eq!(format!("{:#3?}", grid), expected_output); + assert_eq!(format!("{grid:#3?}"), expected_output); } #[test] @@ -2425,21 +2460,21 @@ mod test { [7.1,8.23444,95.55] ]; - let expected_output = r#"[ + 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!("{:#5.1?}", grid), expected_output); + assert_eq!(format!("{grid:#5.1?}"), expected_output); - let expected_output = r#"[ + 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!("{:#8.5?}", grid), expected_output); + assert_eq!(format!("{grid:#8.5?}"), expected_output); } #[test] @@ -2449,19 +2484,19 @@ mod test { [(80, 90), (5, 6)] ]; - let expected_output = r#"[ + let expected_output = r"[ [ ( 5, 66), ( 432, 55)] [ ( 80, 90), ( 5, 6)] -]"#; +]"; assert_eq!(format!("{grid:#?}"), expected_output); - let expected_output = r#"[ + let expected_output = r"[ [ ( 5, 66), (432, 55)] [ ( 80, 90), ( 5, 6)] -]"#; +]"; - assert_eq!(format!("{:#3?}", grid), expected_output); + assert_eq!(format!("{grid:#3?}"), expected_output); } #[test] @@ -2491,17 +2526,17 @@ mod test { [ Person { _name: "Sam", _precise_age: 8.99950 }, Person { _name: "John Doe", _precise_age: 40.14000 }] ]"#; - assert_eq!(format!("{:#5.5?}", grid), expected_output); + 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#"[ + let expected_output = r"[ [ 1, 2, 3] [ 4, 5, 6] -]"#; - assert_eq!(format!("{:#?}", grid), expected_output); +]"; + assert_eq!(format!("{grid:#?}"), expected_output); } #[test] @@ -2583,6 +2618,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn init_panics() { Grid::init(usize::MAX, 2, 3); } @@ -2610,6 +2646,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn init_with_order_panics() { Grid::init_with_order(usize::MAX, 2, Order::ColumnMajor, 3); } @@ -2631,6 +2668,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn new_panics() { let _: Grid = Grid::new(usize::MAX, 2); } @@ -2652,6 +2690,7 @@ mod test { #[test] #[should_panic] + #[allow(clippy::should_panic_without_expect)] fn new_with_order_panics() { let _: Grid = Grid::new_with_order(usize::MAX, 2, Order::ColumnMajor); } @@ -2724,6 +2763,7 @@ mod test { #[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)]; @@ -2731,6 +2771,7 @@ mod test { #[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)]; @@ -2771,6 +2812,7 @@ mod test { } #[test] + #[allow(clippy::redundant_closure_for_method_calls)] fn iter_rows() { let grid: Grid = grid![[1,2,3][4,5,6]]; let max_by_row: Vec = grid @@ -2785,6 +2827,7 @@ mod test { } #[test] + #[allow(clippy::redundant_closure_for_method_calls)] fn iter_cols() { let grid: Grid = grid![[1,2,3][4,5,6]]; let max_by_col: Vec = grid @@ -2795,7 +2838,7 @@ mod test { assert_eq!(max_by_col, vec![4, 5, 6]); - let sum_by_col: Vec = grid.iter_cols().map(|col| col.sum()).collect(); + let sum_by_col: Vec = grid.iter_cols().map(|row| row.sum()).collect(); assert_eq!(sum_by_col, vec![1 + 4, 2 + 5, 3 + 6]); } From db87ad82649e7c0affd5330b014ee30bda1fd2cb Mon Sep 17 00:00:00 2001 From: Chris Bowers Date: Wed, 13 Dec 2023 12:05:34 -0500 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=E2=9C=A8=20Improved=20signature=20?= =?UTF-8?q?for=20get=5Funchecked=5Fmut=20and=20get=5Funchecked=20so=20that?= =?UTF-8?q?=20guarantees=20conversion=20into=20a=20usize=20works?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way get_unchecked and get_unchecked_mut are a little more versatile, but still won't randomly panic on you. --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index dcd9661..90e31ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -495,8 +495,8 @@ impl Grid { /// 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: usize, col: usize) -> &T { - let index = self.get_index(row, col); + pub unsafe fn get_unchecked>(&self, row: U, col: U) -> &T { + let index = self.get_index(row.into(), col.into()); self.data.get_unchecked(index) } @@ -508,8 +508,8 @@ impl Grid { /// 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: usize, col: usize) -> &mut T { - let index = self.get_index(row, col); + pub unsafe fn get_unchecked_mut>(&mut self, row: U, col: U) -> &mut T { + let index = self.get_index(row.into(), col.into()); self.data.get_unchecked_mut(index) } From cc60b7a189b4b2d12f3600ddd32bf703abed9e50 Mon Sep 17 00:00:00 2001 From: Chris Bowers Date: Wed, 13 Dec 2023 13:21:40 -0500 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20=E2=9C=A8=20Add=20implementations?= =?UTF-8?q?=20for=20`From`=20to=20improve=20ability=20to=20create=20items?= =?UTF-8?q?=20from=20a=202d=20and=20(1d,=20size)=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 90e31ce..043da98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1519,6 +1519,59 @@ impl PartialEq for Grid { impl Eq for Grid {} +impl From>> for Grid { + #[allow(clippy::redundant_closure_for_method_calls)] + fn from(vec: Vec>) -> 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 From<&Vec>> for Grid { + #[allow(clippy::redundant_closure_for_method_calls)] + fn from(vec: &Vec>) -> 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 From<&Vec<&Vec>> for Grid { + #[allow(clippy::redundant_closure_for_method_calls)] + fn from(vec: &Vec<&Vec>) -> 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 From<(Vec, usize)> for Grid { + fn from(value: (Vec, usize)) -> Self { + Self::from_vec_with_order(value.0, value.1, Order::default()) + } +} + +impl From<(&Vec, usize)> for Grid { + fn from(value: (&Vec, usize)) -> Self { + Self::from_vec_with_order(value.0.clone(), value.1, Order::default()) + } +} + +impl From<(&Vec, &usize)> for Grid { + fn from(value: (&Vec, &usize)) -> Self { + Self::from_vec_with_order(value.0.clone(), *value.1, Order::default()) + } +} + pub struct GridRowIter<'a, T> { grid: &'a Grid, row_index: usize, @@ -1578,6 +1631,100 @@ mod test { assert_eq!(grid.data, data, "internal data is unexpected"); } + #[test] + fn from_1d_vec() { + let grid: Grid = 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 = Grid::from((vec![1, 2, 3], 2)); + } + + #[test] + fn from_1d_vec_reference() { + let vec = vec![1, 2, 3]; + let grid: Grid = 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 = Grid::from((&vec, 2)); + } + + #[test] + fn from_1d_vec_reference_and_reference() { + let vec = vec![1, 2, 3]; + let cols = 1; + let grid: Grid = 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 = Grid::from((&vec, &cols)); + } + + #[test] + fn from_2d_vec() { + let grid: Grid = 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 = 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 = 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 = 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 = 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 = Grid::from(&vec); + } + #[test] fn from_vec_zero_with_cols() { let grid: Grid = Grid::from_vec(vec![], 1); From 0abdd03f8ac06f55de5fb90faf3b0571de61a165 Mon Sep 17 00:00:00 2001 From: Chris Bowers Date: Sat, 16 Dec 2023 13:37:04 -0500 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20=E2=9C=A8=20Add=20support=20for=20d?= =?UTF-8?q?ifferent=20types=20in=20`get`=20methods=20via=20two=20generics?= =?UTF-8?q?=20instead=20of=20one?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0fc81f2..f66fd1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -496,7 +496,7 @@ impl Grid { /// 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: U, col: U) -> &T { + pub unsafe fn get_unchecked(&self, row: impl Into, col: impl Into) -> &T { let index = self.get_index(row.into(), col.into()); self.data.get_unchecked(index) } @@ -509,7 +509,7 @@ impl Grid { /// 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: U, col: U) -> &mut T { + pub unsafe fn get_unchecked_mut(&mut self, row: impl Into, col: impl Into) -> &mut T { let index = self.get_index(row.into(), col.into()); self.data.get_unchecked_mut(index) } @@ -517,7 +517,7 @@ impl Grid { /// 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: U, col: U) -> Option<&T> { + pub fn get(&self, row: impl TryInto, col: impl TryInto) -> 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 { @@ -530,7 +530,7 @@ impl Grid { /// 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: U, col: U) -> Option<&mut T> { + pub fn get_mut(&mut self, row: impl TryInto, col: impl TryInto) -> 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 { @@ -2877,7 +2877,7 @@ mod test { #[test] fn get() { let grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); - assert_eq!(grid.get(0, 1), Some(&2)); + assert_eq!(grid.get(0_i64, 1_i32), Some(&2)); } #[test] @@ -2901,7 +2901,7 @@ mod test { #[test] fn get_mut() { let mut grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); - assert_eq!(grid.get_mut(0, 1), Some(&mut 2)); + assert_eq!(grid.get_mut(0_i64, 1_i32), Some(&mut 2)); } #[test] From 2b72fb7610485c4cdba62feb3b2456a8189a1dce Mon Sep 17 00:00:00 2001 From: Chris Bowers Date: Sat, 16 Dec 2023 14:14:57 -0500 Subject: [PATCH 6/6] =?UTF-8?q?style:=20=F0=9F=8E=A8=20Run=20cargo=20forma?= =?UTF-8?q?t=20on=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f66fd1d..25e4641 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -509,7 +509,11 @@ impl Grid { /// 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, col: impl Into) -> &mut T { + pub unsafe fn get_unchecked_mut( + &mut self, + row: impl Into, + col: impl Into, + ) -> &mut T { let index = self.get_index(row.into(), col.into()); self.data.get_unchecked_mut(index) } @@ -530,7 +534,11 @@ impl Grid { /// 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, col: impl TryInto) -> Option<&mut T> { + pub fn get_mut( + &mut self, + row: impl TryInto, + col: impl TryInto, + ) -> 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 {