From cf0bcdf28463ae8c3d70c34306207c24813b2b6e Mon Sep 17 00:00:00 2001 From: Jack Maguire Date: Mon, 17 Apr 2023 21:51:43 +0100 Subject: [PATCH] clippy + tests --- src/lib.rs | 177 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 103 insertions(+), 74 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index aee628b..33627ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![warn(clippy::all, clippy::pedantic)] + /*! # Two Dimensional Grid Continuous growable 2D data structure. @@ -195,7 +197,11 @@ impl Grid { /// use grid::Grid; /// Grid::from_vec(vec![1,2,3,4,5], 3); /// ``` - pub fn from_vec(vec: Vec, cols: usize) -> Grid { + /// + /// # Panics + /// + /// This can panic if the vector is empty, or if the vector length isn't a multiple of the number of columns. + #[must_use] pub fn from_vec(vec: Vec, cols: usize) -> Grid { let rows = vec.len(); if rows == 0 { if cols == 0 { @@ -266,17 +272,17 @@ impl Grid { /// Returns the size of the gird as a two element tuple. /// First element are the number of rows and the second the columns. - pub fn size(&self) -> (usize, usize) { + #[must_use] pub fn size(&self) -> (usize, usize) { (self.rows, self.cols) } /// Returns the number of rows of the grid. - pub fn rows(&self) -> usize { + #[must_use] pub fn rows(&self) -> usize { self.rows } /// Returns the number of columns of the grid. - pub fn cols(&self) -> usize { + #[must_use] pub fn cols(&self) -> usize { self.cols } @@ -287,7 +293,7 @@ impl Grid { /// let grid : Grid = grid![]; /// assert!(grid.is_empty()); /// ``` - pub fn is_empty(&self) -> bool { + #[must_use] pub fn is_empty(&self) -> bool { self.data.is_empty() } @@ -345,12 +351,11 @@ impl Grid { pub fn iter_col(&self, col: usize) -> StepBy> { if col < self.cols { return self.data[col..].iter().step_by(self.cols); - } else { - panic!( - "out of bounds. Column must be less than {:?}, but is {:?}.", - self.cols, col - ) } + panic!( + "out of bounds. Column must be less than {:?}, but is {:?}.", + self.cols, col + ) } /// Returns a mutable iterator over a column. @@ -374,12 +379,11 @@ impl Grid { let cols = self.cols; if col < cols { return self.data[col..].iter_mut().step_by(cols); - } else { - panic!( - "out of bounds. Column must be less than {:?}, but is {:?}.", - self.cols, col - ) } + panic!( + "out of bounds. Column must be less than {:?}, but is {:?}.", + self.cols, col + ) } /// Returns an iterator over a row. @@ -467,17 +471,13 @@ impl Grid { /// /// # Panics /// - /// Panics if the grid is not empty and `row.len() != grid.cols()`. - /// - /// Also panics if `row.len() == 0` + /// Panics if: + /// - the grid is not empty and `row.len() != grid.cols()` + /// - `row.len() == 0` pub fn push_row(&mut self, row: Vec) { assert_ne!(row.len(), 0); - if self.rows > 0 && row.len() != self.cols { - panic!( - "pushed row does not match. Length must be {:?}, but was {:?}.", - self.cols, row.len() - ) - } + 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); self.rows += 1; if self.cols == 0{ @@ -515,17 +515,13 @@ impl Grid { /// /// # Panics /// - /// Panics if the grid is not empty and `col.len() != grid.rows()`. - /// - /// Also panics if `col.len() == 0` + /// Panics if: + /// - the grid is not empty and `col.len() != grid.rows()` + /// - `col.len() == 0` pub fn push_col(&mut self, col: Vec) { assert_ne!(col.len(), 0); - if self.cols > 0 && col.len() != self.rows { - panic!( - "pushed column does not match. Length must be {:?}, but was {:?}.", - self.rows, col.len() - ) - } + 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); for i in (1..self.rows).rev() { let row_idx = i * self.cols; @@ -604,15 +600,13 @@ impl Grid { /// /// # Panics /// - /// Panics if the grid is not empty and `row.len() != grid.cols()`. + /// 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) { let input_len = row.len(); - if self.cols > 0 && input_len != self.cols { - panic!("Inserted row must be of length {}, but was {}.", self.cols, row.len()); - } - if index > self.rows { - panic!("Out of range. Index was {}, but must be less or equal to {}.", index, self.rows); - } + 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); let data_idx = index * input_len; self.data.splice(data_idx..data_idx, row.into_iter()); self.cols = input_len; @@ -636,15 +630,13 @@ impl Grid { /// /// # Panics /// - /// Panics if the grid is not empty and `col.len() != grid.rows()`. + /// 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) { let input_len = col.len(); - if self.rows > 0 && input_len != self.rows { - panic!("Inserted col must be of length {}, but was {}.", self.rows, col.len()); - } - if index > self.cols { - panic!("Out of range. Index was {}, but must be less or equal to {}.", index, self.cols); - } + 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); 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); @@ -665,17 +657,17 @@ impl Grid { /// let flat = grid.flatten(); /// assert_eq!(flat, &vec![1,2,3,4,5,6]); /// ``` - pub fn flatten(&self) -> &Vec { + #[must_use] pub fn flatten(&self) -> &Vec { &self.data } /// Converts self into a vector without clones or allocation. - pub fn into_vec(self) -> Vec { + #[must_use] pub fn into_vec(self) -> Vec { self.data } /// Transpose the grid so that columns become rows in new grid. - pub fn transpose(&self) -> Grid + #[must_use] pub fn transpose(&self) -> Grid where T: Clone, { @@ -707,7 +699,7 @@ impl Grid { where T: Clone { - self.data.fill(value) + self.data.fill(value); } /// Fills the grid with elements returned by calling a closure repeatedly. @@ -732,13 +724,13 @@ impl Grid { where F: FnMut() -> T, { - self.data.fill_with(f) + self.data.fill_with(f); } /// 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) + /// An item in this iterator is equal to a call to `Grid.iter_row(row_index)` /// of the corresponding row. /// /// # Examples @@ -749,14 +741,14 @@ impl Grid { /// let sum_by_row: Vec = grid.iter_rows().map(|row| row.sum()).collect(); /// assert_eq!(sum_by_row, vec![1+2+3, 4+5+6]) /// ``` - pub fn iter_rows(&self) -> GridRowIter<'_, T> { + #[must_use] pub fn iter_rows(&self) -> GridRowIter<'_, T> { GridRowIter{grid: self, row_index: 0} } /// 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) + /// An item in this iterator is equal to a call to `Grid.iter_col(col_index)` /// of the corresponding column. /// /// # Examples @@ -767,7 +759,7 @@ impl Grid { /// let sum_by_col: Vec = grid.iter_cols().map(|col| col.sum()).collect(); /// assert_eq!(sum_by_col, vec![1+4, 2+5, 3+6]) /// ``` - pub fn iter_cols(&self) -> GridColIter<'_, T> { + #[must_use] pub fn iter_cols(&self) -> GridColIter<'_, T> { GridColIter { grid: self, col_index: 0 } } } @@ -805,15 +797,17 @@ impl Index<(usize, usize)> for Grid { type Output = T; #[inline] - fn index(&self, (x, y): (usize, usize)) -> &T { - &self.data[y * self.cols + x] + 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); + &self.data[row * self.cols + col] } } impl IndexMut<(usize, usize)> for Grid { #[inline] - fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut T { - &mut self.data[y * self.cols + x] + 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); + &mut self.data[row * self.cols + col] } } @@ -823,7 +817,7 @@ impl fmt::Debug for Grid { write!(f, "["); if self.cols > 0 { if f.alternate() { - write!(f, "\n"); + writeln!(f); /* WARNING @@ -848,14 +842,14 @@ impl fmt::Debug for Grid { write!( f, " {item:width$.precision$?}", - width = width, - precision = precision + // width = width, + // precision = precision ); if row.peek().is_some() { write!(f, ","); } } - write!(f, "]\n"); + writeln!(f, "]"); } } else { for (i, _) in self.data.iter().enumerate().step_by(self.cols) { @@ -892,7 +886,7 @@ impl<'a, T> Iterator for GridRowIter<'a, T> { let row_iter = self.grid.iter_row(row_index); self.row_index += 1; - return Some(row_iter); + Some(row_iter) } } @@ -909,7 +903,7 @@ impl<'a, T> Iterator for GridColIter<'a, T> { let row_iter = self.grid.iter_col(col_index); self.col_index += 1; - return Some(row_iter); + Some(row_iter) } } @@ -929,7 +923,7 @@ mod test { #[test] fn from_vec_zero() { let grid: Grid = Grid::from_vec(vec![], 0); - grid.is_empty(); + let _ = grid.is_empty(); assert_eq!(grid.rows(), 0); assert_eq!(grid.cols(), 0); } @@ -1103,6 +1097,13 @@ mod test { let _ = grid[0][5]; } + #[test] + #[should_panic] + 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)]; + } + #[test] fn push_col_2x3() { let mut grid: Grid = grid![ @@ -1369,7 +1370,7 @@ r#"[ [ ( 80, 90), ( 5, 6)] ]"#; - assert_eq!(format!("{:#?}", grid), expected_output); + assert_eq!(format!("{grid:#?}"), expected_output); let expected_output = r#"[ @@ -1552,6 +1553,15 @@ r#"[ assert_eq!(grid[1][1], 4); } + #[test] + fn idx_tup() { + let grid: Grid = 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] fn idx_panic_1() { @@ -1559,6 +1569,13 @@ r#"[ let _ = grid[20][0]; } + #[test] + #[should_panic] + fn idx_tup_panic_1() { + let grid = Grid::init(1, 2, 3); + let _ = grid[(20, 0)]; + } + #[test] #[should_panic] fn idx_panic_2() { @@ -1566,6 +1583,13 @@ r#"[ let _ = grid[0][20]; } + #[test] + #[should_panic] + fn idx_tup_panic_2() { + let grid = Grid::init(1, 2, 3); + let _ = grid[(0, 20)]; + } + #[test] fn idx_set() { let mut grid = Grid::init(1, 2, 3); @@ -1573,6 +1597,13 @@ r#"[ assert_eq!(grid[0][0], 4); } + #[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); @@ -1606,13 +1637,12 @@ r#"[ let grid: Grid = grid![[1,2,3][4,5,6]]; let max_by_row: Vec = grid .iter_rows() - .map(|row| row.max().unwrap()) - .map(|item| *item) + .map(|row| row.max().unwrap()).copied() .collect(); assert_eq!(max_by_row, vec![3, 6]); let sum_by_row: Vec = grid.iter_rows().map(|row| row.sum()).collect(); - assert_eq!(sum_by_row, vec![1+2+3, 4+5+6]) + assert_eq!(sum_by_row, vec![1+2+3, 4+5+6]); } #[test] @@ -1620,13 +1650,12 @@ r#"[ let grid: Grid = grid![[1,2,3][4,5,6]]; let max_by_col: Vec = grid .iter_cols() - .map(|col| col.max().unwrap()) - .map(|item| *item) + .map(|col| col.max().unwrap()).copied() .collect(); assert_eq!(max_by_col, vec![4,5,6]); let sum_by_col: Vec = grid.iter_cols().map(|col| col.sum()).collect(); - assert_eq!(sum_by_col, vec![1+4, 2+5, 3+6]) + assert_eq!(sum_by_col, vec![1+4, 2+5, 3+6]); } }