diff --git a/Cargo.toml b/Cargo.toml index a8e0809..cda21d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,6 @@ version = "0.10.0" [workspace.lints.rust] missing-docs = "warn" + +[workspace.dependencies] +thiserror = "1.0.69" diff --git a/crates/servicepoint/Cargo.toml b/crates/servicepoint/Cargo.toml index f3d828d..3497c6c 100644 --- a/crates/servicepoint/Cargo.toml +++ b/crates/servicepoint/Cargo.toml @@ -22,6 +22,7 @@ rust-lzma = { version = "0.6.0", optional = true } rand = { version = "0.8", optional = true } tungstenite = { version = "0.24.0", optional = true } once_cell = { version = "1.20.2", optional = true } +thiserror.workspace = true [features] default = ["compression_lzma", "protocol_udp", "cp437"] diff --git a/crates/servicepoint/src/char_grid.rs b/crates/servicepoint/src/char_grid.rs index 274a5dd..225474e 100644 --- a/crates/servicepoint/src/char_grid.rs +++ b/crates/servicepoint/src/char_grid.rs @@ -1,3 +1,4 @@ +use crate::primitive_grid::SeriesError; use crate::PrimitiveGrid; /// A grid containing UTF-8 characters. @@ -20,15 +21,23 @@ impl CharGrid { /// Overwrites a row in the grid with a str. /// - /// Returns [None] if y is out of bounds or `row` is not of the correct size. - pub fn set_row_str(&mut self, y: usize, value: &str) -> Option<()> { + /// Returns [SeriesError] if y is out of bounds or `row` is not of the correct size. + pub fn set_row_str( + &mut self, + y: usize, + value: &str, + ) -> Result<(), SeriesError> { self.set_row(y, value.chars().collect::>().as_ref()) } /// Overwrites a column in the grid with a str. /// - /// Returns [None] if y is out of bounds or `row` is not of the correct size. - pub fn set_col_str(&mut self, x: usize, value: &str) -> Option<()> { + /// Returns [SeriesError] if y is out of bounds or `row` is not of the correct size. + pub fn set_col_str( + &mut self, + x: usize, + value: &str, + ) -> Result<(), SeriesError> { self.set_col(x, value.chars().collect::>().as_ref()) } } @@ -41,7 +50,7 @@ mod test { 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"), Some(())); + assert_eq!(grid.set_col_str(1, "abc"), Ok(())); assert_eq!(grid.get_col_str(1), Some(String::from("abc"))); } @@ -50,8 +59,14 @@ mod test { 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"), None); - assert_eq!(grid.set_row_str(1, "ab"), Some(())); + assert_eq!( + grid.set_row_str(1, "abc"), + Err(SeriesError::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/crates/servicepoint/src/lib.rs b/crates/servicepoint/src/lib.rs index aee3bc3..46478e1 100644 --- a/crates/servicepoint/src/lib.rs +++ b/crates/servicepoint/src/lib.rs @@ -49,7 +49,7 @@ pub use crate::cp437::Cp437Grid; pub use crate::data_ref::DataRef; pub use crate::grid::Grid; pub use crate::origin::{Origin, Pixels, Tiles}; -pub use crate::primitive_grid::PrimitiveGrid; +pub use crate::primitive_grid::{PrimitiveGrid, SeriesError}; /// An alias for the specific type of [bitvec::prelude::BitVec] used. pub type BitVec = bitvec::prelude::BitVec; diff --git a/crates/servicepoint/src/primitive_grid.rs b/crates/servicepoint/src/primitive_grid.rs index 72bcfc0..93c4249 100644 --- a/crates/servicepoint/src/primitive_grid.rs +++ b/crates/servicepoint/src/primitive_grid.rs @@ -13,6 +13,14 @@ pub struct PrimitiveGrid { data: Vec, } +#[derive(thiserror::Error, Debug, PartialEq)] +pub enum SeriesError { + #[error("The index {index} was out of bounds for size {size}")] + OutOfBounds { index: usize, size: usize }, + #[error("The provided series was expected to have a length of {expected}, but was {actual}")] + InvalidLength { actual: usize, expected: usize }, +} + impl PrimitiveGrid { /// Creates a new [PrimitiveGrid] with the specified dimensions. /// @@ -155,16 +163,19 @@ impl PrimitiveGrid { pub fn get_col(&self, x: usize) -> Option> { self.data .chunks_exact(self.width()) - .map(|row| row.get(x).map(move |x| *x)) + .map(|row| row.get(x).copied()) .collect() } /// Overwrites a column in the grid. /// - /// Returns [None] if x is out of bounds or `col` is not of the correct size. - pub fn set_col(&mut self, x: usize, col: &[T]) -> Option<()> { + /// 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<(), SeriesError> { if col.len() != self.height() { - return None; + return Err(SeriesError::InvalidLength { + expected: self.height(), + actual: col.len(), + }); } let width = self.width(); if self @@ -176,25 +187,36 @@ impl PrimitiveGrid { }) .all(|cell| cell.is_some()) { - Some(()) + Ok(()) } else { - None + Err(SeriesError::OutOfBounds {index: x, size: width}) } } /// Overwrites a row in the grid. /// - /// Returns [None] if y is out of bounds or `row` is not of the correct size. - pub fn set_row(&mut self, y: usize, row: &[T]) -> Option<()> { + /// 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<(), SeriesError> { let width = self.width(); - self.data.chunks_exact_mut(width).nth(y).and_then(|chunk| { - if chunk.len() == row.len() { - chunk.copy_from_slice(row); - Some(()) - } else { - None + if row.len() != width { + return Err(SeriesError::InvalidLength { + expected: width, + actual: row.len(), + }); + } + + let chunk = match self.data.chunks_exact_mut(width).nth(y) { + Some(row) => row, + None => { + return Err(SeriesError::OutOfBounds { + size: self.height(), + index: y, + }) } - }) + }; + + chunk.copy_from_slice(row); + Ok(()) } } @@ -283,7 +305,7 @@ impl<'t, T: PrimitiveGridType> Iterator for IterRows<'t, T> { #[cfg(test)] mod tests { - use crate::{DataRef, Grid, PrimitiveGrid}; + use crate::{DataRef, Grid, PrimitiveGrid, SeriesError}; #[test] fn fill() { @@ -412,9 +434,18 @@ mod tests { 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]), Some(())); - assert_eq!(grid.set_col(2, &[5, 7, 9]), None); - assert_eq!(grid.set_col(0, &[5, 7]), None); + assert_eq!(grid.set_col(0, &[5, 7, 9]), Ok(())); + assert_eq!( + grid.set_col(2, &[5, 7, 9]), + Err(SeriesError::OutOfBounds { size: 2, index: 2 }) + ); + assert_eq!( + grid.set_col(0, &[5, 7]), + Err(SeriesError::InvalidLength { + expected: 3, + actual: 2 + }) + ); assert_eq!(grid.get_col(0), Some(vec![5, 7, 9])); } @@ -424,9 +455,18 @@ mod tests { 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]), Some(())); + 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]), None); - assert_eq!(grid.set_row(2, &[5, 7, 3]), None); + assert_eq!( + grid.set_row(3, &[5, 7]), + Err(SeriesError::OutOfBounds { size: 3, index: 3 }) + ); + assert_eq!( + grid.set_row(2, &[5, 7, 3]), + Err(SeriesError::InvalidLength { + expected: 2, + actual: 3 + }) + ); } }