From cabf1d32ede39081465070589e09ed507c409108 Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Wed, 9 Jul 2025 22:10:11 +0200 Subject: [PATCH] move more stuff to traits --- src/containers/char_grid.rs | 27 ------- src/containers/char_grid_ext.rs | 30 ++++++++ src/containers/grid.rs | 122 +++++++++++++++++++++++++++++++- src/containers/value_grid.rs | 113 ----------------------------- src/containers/window.rs | 20 ++++++ 5 files changed, 171 insertions(+), 141 deletions(-) diff --git a/src/containers/char_grid.rs b/src/containers/char_grid.rs index 07df8a9..bc53751 100644 --- a/src/containers/char_grid.rs +++ b/src/containers/char_grid.rs @@ -154,33 +154,6 @@ impl From for Vec { #[cfg(test)] mod test { use super::*; - use crate::{CharGridExt, SetValueSeriesError}; - - #[test] - fn col_str() { - let mut grid = CharGrid::new(2, 3); - assert_eq!(grid.get_col_str(2), None); - assert_eq!(grid.get_col_str(1), Some(String::from("\0\0\0"))); - assert_eq!(grid.set_col_str(1, "abc"), Ok(())); - assert_eq!(grid.get_col_str(1), Some(String::from("abc"))); - } - - #[test] - fn row_str() { - let mut grid = CharGrid::new(2, 3); - assert_eq!(grid.get_row_str(3), None); - assert_eq!(grid.get_row_str(1), Some(String::from("\0\0"))); - assert_eq!( - grid.set_row_str(1, "abc"), - Err(SetValueSeriesError::InvalidLength { - expected: 2, - actual: 3 - }) - ); - assert_eq!(grid.set_row_str(1, "ab"), Ok(())); - assert_eq!(grid.get_row_str(1), Some(String::from("ab"))); - } - #[test] fn str_to_char_grid() { // conversion with .to_string() covers one more line diff --git a/src/containers/char_grid_ext.rs b/src/containers/char_grid_ext.rs index 6b76881..02d2f08 100644 --- a/src/containers/char_grid_ext.rs +++ b/src/containers/char_grid_ext.rs @@ -143,3 +143,33 @@ impl> CharGridMutExt for G { Ok(()) } } + +#[cfg(test)] +mod test { + use crate::{CharGrid, CharGridExt, CharGridMutExt, SetValueSeriesError}; + + #[test] + fn col_str() { + let mut grid = CharGrid::new(2, 3); + assert_eq!(grid.get_col_str(2), None); + assert_eq!(grid.get_col_str(1), Some(String::from("\0\0\0"))); + assert_eq!(grid.set_col_str(1, "abc"), Ok(())); + assert_eq!(grid.get_col_str(1), Some(String::from("abc"))); + } + + #[test] + fn row_str() { + let mut grid = CharGrid::new(2, 3); + assert_eq!(grid.get_row_str(3), None); + assert_eq!(grid.get_row_str(1), Some(String::from("\0\0"))); + assert_eq!( + grid.set_row_str(1, "abc"), + Err(SetValueSeriesError::InvalidLength { + expected: 2, + actual: 3 + }) + ); + assert_eq!(grid.set_row_str(1, "ab"), Ok(())); + assert_eq!(grid.get_row_str(1), Some(String::from("ab"))); + } +} diff --git a/src/containers/grid.rs b/src/containers/grid.rs index bcdd04b..f2391d1 100644 --- a/src/containers/grid.rs +++ b/src/containers/grid.rs @@ -1,3 +1,5 @@ +use crate::SetValueSeriesError; + /// A two-dimensional readonly grid of `T` pub trait Grid { /// Get the current value at the specified position @@ -90,7 +92,7 @@ pub trait Grid { } /// A two-dimensional mutable grid of `T` -pub trait GridMut: Grid { +pub trait GridMut: Grid { /// Sets the value at the specified position /// /// # Arguments @@ -150,4 +152,122 @@ pub trait GridMut: Grid { } } } + + /// Overwrites a column in the grid. + /// + /// Returns [Err] if x is out of bounds or `col` is not of the correct size. + fn set_col( + &mut self, + x: usize, + col: &[T], + ) -> Result<(), SetValueSeriesError> { + let height = self.height(); + if col.len() != height { + return Err(SetValueSeriesError::InvalidLength { + expected: height, + actual: col.len(), + }); + } + + if x >= self.width() { + return Err(SetValueSeriesError::OutOfBounds { + size: self.width(), + index: x, + }); + } + + for (y, item) in col.iter().enumerate().take(height) { + self.set(x, y, item.clone()); + } + + Ok(()) + } + + /// Overwrites a row in the grid. + /// + /// Returns [Err] if y is out of bounds or `row` is not of the correct size. + fn set_row( + &mut self, + y: usize, + row: &[T], + ) -> Result<(), SetValueSeriesError> { + let width = self.width(); + if row.len() != width { + return Err(SetValueSeriesError::InvalidLength { + expected: width, + actual: row.len(), + }); + } + + if y >= self.height() { + return Err(SetValueSeriesError::OutOfBounds { + size: self.height(), + index: y, + }); + } + + for (x, item) in row.iter().enumerate().take(width) { + self.set(x, y, item.clone()); + } + + Ok(()) + } } + +#[cfg(test)] +mod test { + use crate::{DataRef, Grid, GridMut, SetValueSeriesError, ValueGrid}; + + #[test] + fn optional() { + let mut grid = ValueGrid::load(2, 2, &[0, 1, 2, 3]).unwrap(); + assert!(grid.set_optional(0, 0, 5)); + assert!(!grid.set_optional(0, 8, 42)); + assert_eq!(grid.data_ref(), [5, 1, 2, 3]); + + assert_eq!(grid.get_optional(0, 0), Some(5)); + assert_eq!(grid.get_optional(0, 8), None); + } + + #[test] + fn col() { + let mut grid = ValueGrid::load(2, 3, &[0, 1, 2, 3, 4, 5]).unwrap(); + assert_eq!(grid.get_col(0), Some(vec![0, 2, 4])); + assert_eq!(grid.get_col(1), Some(vec![1, 3, 5])); + assert_eq!(grid.get_col(2), None); + assert_eq!(grid.set_col(0, &[5, 7, 9]), Ok(())); + assert_eq!( + grid.set_col(2, &[5, 7, 9]), + Err(SetValueSeriesError::OutOfBounds { size: 2, index: 2 }) + ); + assert_eq!( + grid.set_col(0, &[5, 7]), + Err(SetValueSeriesError::InvalidLength { + expected: 3, + actual: 2 + }) + ); + assert_eq!(grid.get_col(0), Some(vec![5, 7, 9])); + } + + #[test] + fn row() { + let mut grid = ValueGrid::load(2, 3, &[0, 1, 2, 3, 4, 5]).unwrap(); + assert_eq!(grid.get_row(0), Some(vec![0, 1])); + assert_eq!(grid.get_row(2), Some(vec![4, 5])); + assert_eq!(grid.get_row(3), None); + assert_eq!(grid.set_row(0, &[5, 7]), Ok(())); + assert_eq!(grid.get_row(0), Some(vec![5, 7])); + assert_eq!( + grid.set_row(3, &[5, 7]), + Err(SetValueSeriesError::OutOfBounds { size: 3, index: 3 }) + ); + assert_eq!( + grid.set_row(2, &[5, 7, 3]), + Err(SetValueSeriesError::InvalidLength { + expected: 2, + actual: 3 + }) + ); + } +} \ No newline at end of file diff --git a/src/containers/value_grid.rs b/src/containers/value_grid.rs index 591a999..6d7ebdc 100644 --- a/src/containers/value_grid.rs +++ b/src/containers/value_grid.rs @@ -224,66 +224,6 @@ impl ValueGrid { } } - /// Overwrites a column in the grid. - /// - /// Returns [Err] if x is out of bounds or `col` is not of the correct size. - pub fn set_col( - &mut self, - x: usize, - col: &[T], - ) -> Result<(), SetValueSeriesError> { - if col.len() != self.height() { - return Err(SetValueSeriesError::InvalidLength { - expected: self.height(), - actual: col.len(), - }); - } - let width = self.width(); - if self - .data - .chunks_exact_mut(width) - .zip(col.iter()) - .map(|(row, column_value)| { - row.get_mut(x).map(move |cell| *cell = *column_value) - }) - .all(|cell| cell.is_some()) - { - Ok(()) - } else { - Err(SetValueSeriesError::OutOfBounds { - index: x, - size: width, - }) - } - } - - /// Overwrites a row in the grid. - /// - /// Returns [Err] if y is out of bounds or `row` is not of the correct size. - pub fn set_row( - &mut self, - y: usize, - row: &[T], - ) -> Result<(), SetValueSeriesError> { - let width = self.width(); - if row.len() != width { - return Err(SetValueSeriesError::InvalidLength { - expected: width, - actual: row.len(), - }); - } - - let Some(chunk) = self.data.chunks_exact_mut(width).nth(y) else { - return Err(SetValueSeriesError::OutOfBounds { - size: self.height(), - index: y, - }); - }; - - chunk.copy_from_slice(row); - Ok(()) - } - /// Enumerates all values in the grid. pub fn enumerate( &self, @@ -587,59 +527,6 @@ mod tests { assert_eq!(Some(&mut 8), vec.get_ref_mut_optional(2, 2)); } - #[test] - fn optional() { - let mut grid = ValueGrid::load(2, 2, &[0, 1, 2, 3]).unwrap(); - assert!(grid.set_optional(0, 0, 5)); - assert!(!grid.set_optional(0, 8, 42)); - assert_eq!(grid.data, [5, 1, 2, 3]); - - assert_eq!(grid.get_optional(0, 0), Some(5)); - assert_eq!(grid.get_optional(0, 8), None); - } - - #[test] - fn col() { - let mut grid = ValueGrid::load(2, 3, &[0, 1, 2, 3, 4, 5]).unwrap(); - assert_eq!(grid.get_col(0), Some(vec![0, 2, 4])); - assert_eq!(grid.get_col(1), Some(vec![1, 3, 5])); - assert_eq!(grid.get_col(2), None); - assert_eq!(grid.set_col(0, &[5, 7, 9]), Ok(())); - assert_eq!( - grid.set_col(2, &[5, 7, 9]), - Err(SetValueSeriesError::OutOfBounds { size: 2, index: 2 }) - ); - assert_eq!( - grid.set_col(0, &[5, 7]), - Err(SetValueSeriesError::InvalidLength { - expected: 3, - actual: 2 - }) - ); - assert_eq!(grid.get_col(0), Some(vec![5, 7, 9])); - } - - #[test] - fn row() { - let mut grid = ValueGrid::load(2, 3, &[0, 1, 2, 3, 4, 5]).unwrap(); - assert_eq!(grid.get_row(0), Some(vec![0, 1])); - assert_eq!(grid.get_row(2), Some(vec![4, 5])); - assert_eq!(grid.get_row(3), None); - assert_eq!(grid.set_row(0, &[5, 7]), Ok(())); - assert_eq!(grid.get_row(0), Some(vec![5, 7])); - assert_eq!( - grid.set_row(3, &[5, 7]), - Err(SetValueSeriesError::OutOfBounds { size: 3, index: 3 }) - ); - assert_eq!( - grid.set_row(2, &[5, 7, 3]), - Err(SetValueSeriesError::InvalidLength { - expected: 2, - actual: 3 - }) - ); - } - #[test] fn wrap() { let grid = ValueGrid::from_vec(2, vec![0, 1, 2, 3, 4, 5]).unwrap(); diff --git a/src/containers/window.rs b/src/containers/window.rs index 0aeab0b..ee9a5cf 100644 --- a/src/containers/window.rs +++ b/src/containers/window.rs @@ -56,6 +56,11 @@ macro_rules! define_window { Window::new(self.grid, xs, ys) } + /// Splits the window horizontally, returning windows to the left and right parts. + /// + /// The right window fills the remaining width, which may be zero. + /// + /// Returns None for out-of-bounds. #[must_use] pub fn split_horizontal( &'t self, @@ -79,6 +84,11 @@ macro_rules! define_window { Some((left, right)) } + /// Splits the window vertically, returning windows to the top and bottom parts. + /// + /// The bottom window fills the remaining height, which may be zero. + /// + /// Returns None for out-of-bounds. #[must_use] pub fn split_vertical( &'t self, @@ -164,6 +174,11 @@ impl> WindowMut<'_, TElement, TGrid> { WindowMut::new(self.grid, xs, ys) } + /// Splits the window horizontally, returning windows to the left and right parts. + /// + /// The right window fills the remaining width, which may be zero. + /// + /// Returns None for out-of-bounds. #[must_use] pub fn split_horizontal_mut<'t>( &'t mut self, @@ -183,6 +198,11 @@ impl> WindowMut<'_, TElement, TGrid> { Some((left, right)) } + /// Splits the window vertically, returning windows to the top and bottom parts. + /// + /// The bottom window fills the remaining height, which may be zero. + /// + /// Returns None for out-of-bounds. #[must_use] pub fn split_vertical_mut<'t>( &'t mut self,