servicepoint/containers/
char_grid_ext.rs

1use crate::{Grid, GridMut, SetValueSeriesError};
2
3/// Extension methods for any [`Grid<char>`]
4pub trait CharGridExt {
5    /// Copies a column from the grid as a String.
6    ///
7    /// Returns [None] if x is out of bounds.
8    ///
9    /// # Examples
10    ///
11    /// ```
12    /// # use servicepoint::{CharGrid, CharGridExt};
13    /// let grid = CharGrid::from("ab\ncd");
14    /// let col = grid.get_col_str(0).unwrap(); // "ac"
15    /// ```
16    #[must_use]
17    fn get_col_str(&self, x: usize) -> Option<String>;
18
19    /// Copies a row from the grid as a String.
20    ///
21    /// Returns [None] if y is out of bounds.
22    ///
23    /// # Examples
24    ///
25    /// ```
26    /// # use servicepoint::{CharGrid, CharGridExt};
27    /// let grid = CharGrid::from("ab\ncd");
28    /// let row = grid.get_row_str(0).unwrap(); // "ab"
29    /// ```
30    #[must_use]
31    fn get_row_str(&self, y: usize) -> Option<String>;
32}
33
34/// Extension methods for any [`GridMut<char>`].
35pub trait CharGridMutExt {
36    /// Overwrites a row in the grid with a str.
37    ///
38    /// Returns [`SetValueSeriesError`] if y is out of bounds or `row` is not of the correct size.
39    ///
40    /// # Examples
41    ///
42    /// ```
43    /// # use servicepoint::{CharGrid, CharGridMutExt};
44    /// let mut grid = CharGrid::from("ab\ncd");
45    /// grid.set_row_str(0, "ef").unwrap();
46    /// ```
47    fn set_row_str(
48        &mut self,
49        y: usize,
50        value: &str,
51    ) -> Result<(), SetValueSeriesError>;
52
53    /// Overwrites a column in the grid with a str.
54    ///
55    /// Returns [`SetValueSeriesError`] if y is out of bounds or `row` is not of the correct size.
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// # use servicepoint::{CharGrid, CharGridMutExt};
61    /// let mut grid = CharGrid::from("ab\ncd");
62    /// grid.set_col_str(0, "ef").unwrap();
63    /// ```
64    fn set_col_str(
65        &mut self,
66        x: usize,
67        value: &str,
68    ) -> Result<(), SetValueSeriesError>;
69}
70
71impl<G: Grid<char>> CharGridExt for G {
72    fn get_col_str(&self, x: usize) -> Option<String> {
73        Some(String::from_iter(self.get_col(x)?))
74    }
75
76    fn get_row_str(&self, y: usize) -> Option<String> {
77        Some(String::from_iter(self.get_row(y)?))
78    }
79}
80
81impl<G: GridMut<char>> CharGridMutExt for G {
82    fn set_row_str(
83        &mut self,
84        y: usize,
85        value: &str,
86    ) -> Result<(), SetValueSeriesError> {
87        let width = self.width();
88
89        let len = value.len();
90        if len > width {
91            return Err(SetValueSeriesError::InvalidLength {
92                actual: len,
93                expected: width,
94            });
95        }
96
97        let height = self.height();
98        if y >= height {
99            return Err(SetValueSeriesError::OutOfBounds {
100                index: y,
101                size: height,
102            });
103        }
104
105        let chars = value.chars().take(width);
106        for (x, c) in chars.enumerate() {
107            self.set(x, y, c);
108        }
109
110        Ok(())
111    }
112
113    fn set_col_str(
114        &mut self,
115        x: usize,
116        value: &str,
117    ) -> Result<(), SetValueSeriesError> {
118        let height = self.height();
119
120        let len = value.len();
121        if len > height {
122            return Err(SetValueSeriesError::InvalidLength {
123                actual: len,
124                expected: height,
125            });
126        }
127
128        let width = self.width();
129        if x >= width {
130            return Err(SetValueSeriesError::OutOfBounds {
131                index: x,
132                size: width,
133            });
134        }
135
136        let chars = value.chars().take(height);
137        for (y, c) in chars.enumerate() {
138            self.set(x, y, c);
139        }
140
141        Ok(())
142    }
143}
144
145#[cfg(test)]
146mod test {
147    use crate::{CharGrid, CharGridExt, CharGridMutExt, SetValueSeriesError};
148
149    #[test]
150    fn col_str() {
151        let mut grid = CharGrid::new(2, 3);
152        assert_eq!(grid.get_col_str(2), None);
153        assert_eq!(grid.get_col_str(1), Some(String::from("\0\0\0")));
154        assert_eq!(grid.set_col_str(1, "abc"), Ok(()));
155        assert_eq!(grid.get_col_str(1), Some(String::from("abc")));
156    }
157
158    #[test]
159    fn row_str() {
160        let mut grid = CharGrid::new(2, 3);
161        assert_eq!(grid.get_row_str(3), None);
162        assert_eq!(grid.get_row_str(1), Some(String::from("\0\0")));
163        assert_eq!(
164            grid.set_row_str(1, "abc"),
165            Err(SetValueSeriesError::InvalidLength {
166                expected: 2,
167                actual: 3
168            })
169        );
170        assert_eq!(grid.set_row_str(1, "ab"), Ok(()));
171        assert_eq!(grid.get_row_str(1), Some(String::from("ab")));
172    }
173}