add ValueGrid::wrap and CharGrid::wrap_str, more examples
add examples
This commit is contained in:
		
							parent
							
								
									2a6005fff9
								
							
						
					
					
						commit
						04cda144ed
					
				
					 6 changed files with 160 additions and 26 deletions
				
			
		|  | @ -40,20 +40,8 @@ fn main() { | |||
|             .expect("sending clear failed"); | ||||
|     } | ||||
| 
 | ||||
|     let text = cli | ||||
|         .text | ||||
|         .iter() | ||||
|         .flat_map(move |x| { | ||||
|             x.chars() | ||||
|                 .collect::<Vec<_>>() | ||||
|                 .chunks(TILE_WIDTH) | ||||
|                 .map(|c| String::from_iter(c)) | ||||
|                 .collect::<Vec<_>>() | ||||
|         }) | ||||
|         .collect::<Vec<_>>() | ||||
|         .join("\n"); | ||||
| 
 | ||||
|     let grid = CharGrid::from(text); | ||||
|     let text = cli.text.join("\n"); | ||||
|     let grid = CharGrid::wrap_str(TILE_WIDTH, &text); | ||||
|     connection | ||||
|         .send(Command::Utf8Data(Origin::ZERO, grid)) | ||||
|         .expect("sending text failed"); | ||||
|  |  | |||
|  | @ -9,12 +9,13 @@ use ::bitvec::slice::IterMut; | |||
| ///
 | ||||
| /// The values are stored in packed bytes (8 values per byte) in the same order as used by the display for storing pixels.
 | ||||
| /// This means that no conversion is necessary for sending the data to the display.
 | ||||
| /// The downside is that the width has to be a multiple of 8.
 | ||||
| ///
 | ||||
| /// # Examples
 | ||||
| ///
 | ||||
| /// ```rust
 | ||||
| /// use servicepoint::Bitmap;
 | ||||
| /// let mut bitmap = Bitmap::new(4, 2);
 | ||||
| /// let mut bitmap = Bitmap::new(8, 2);
 | ||||
| ///
 | ||||
| /// ```
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
|  | @ -192,12 +193,18 @@ impl From<Bitmap> for Vec<u8> { | |||
| } | ||||
| 
 | ||||
| impl From<Bitmap> for BitVec { | ||||
|     /// Turns a [Bitmap] into the underlying [BitVec].
 | ||||
|     fn from(value: Bitmap) -> Self { | ||||
|         value.bit_vec | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<&ValueGrid<bool>> for Bitmap { | ||||
|     /// Converts a grid of [bool]s into a [Bitmap].
 | ||||
|     /// 
 | ||||
|     /// # Panics
 | ||||
|     ///
 | ||||
|     /// - when the width of `value` is not dividable by 8
 | ||||
|     fn from(value: &ValueGrid<bool>) -> Self { | ||||
|         let mut result = Self::new(value.width(), value.height()); | ||||
|         for (mut to, from) in result.iter_mut().zip(value.iter()) { | ||||
|  | @ -208,6 +215,7 @@ impl From<&ValueGrid<bool>> for Bitmap { | |||
| } | ||||
| 
 | ||||
| impl From<&Bitmap> for ValueGrid<bool> { | ||||
|     /// Converts a [Bitmap] into a grid of [bool]s.
 | ||||
|     fn from(value: &Bitmap) -> Self { | ||||
|         let mut result = Self::new(value.width(), value.height()); | ||||
|         for (to, from) in result.iter_mut().zip(value.iter()) { | ||||
|  |  | |||
|  | @ -3,9 +3,9 @@ use std::string::FromUtf8Error; | |||
| 
 | ||||
| /// A grid containing UTF-8 characters.
 | ||||
| ///
 | ||||
| /// To send a CharGrid to the display, use [crate::Command::Utf8Data].
 | ||||
| /// To send a CharGrid to the display, use [Command::Utf8Data](crate::Command::Utf8Data).
 | ||||
| ///
 | ||||
| /// Also see [crate::ValueGrid] for the non-specialized operations and examples.
 | ||||
| /// Also see [ValueGrid] for the non-specialized operations and examples.
 | ||||
| ///
 | ||||
| /// # Examples
 | ||||
| ///
 | ||||
|  | @ -20,9 +20,52 @@ use std::string::FromUtf8Error; | |||
| pub type CharGrid = ValueGrid<char>; | ||||
| 
 | ||||
| impl CharGrid { | ||||
|     /// Loads a [CharGrid] with the specified width from the provided text, wrapping to as many rows as needed.
 | ||||
|     ///
 | ||||
|     /// The passed rows are extended with '\0' if needed.
 | ||||
|     ///
 | ||||
|     /// returns: [CharGrid] that contains a copy of the provided data.
 | ||||
|     ///
 | ||||
|     /// # Examples
 | ||||
|     ///
 | ||||
|     /// ```
 | ||||
|     /// # use servicepoint::CharGrid;
 | ||||
|     /// let grid = CharGrid::wrap_str(2, "abc\ndef");
 | ||||
|     /// ```
 | ||||
|     pub fn wrap_str(width: usize, text: &str) -> Self { | ||||
|         let lines = text | ||||
|             .split('\n') | ||||
|             .flat_map(move |x| { | ||||
|                 x.chars() | ||||
|                     .collect::<Vec<char>>() | ||||
|                     .chunks(width) | ||||
|                     .map(|c| { | ||||
|                         let mut s = String::from_iter(c); | ||||
|                         s.push_str(&"\0".repeat(width - s.chars().count())); | ||||
|                         s | ||||
|                     }) | ||||
|                     .collect::<Vec<String>>() | ||||
|             }) | ||||
|             .collect::<Vec<String>>(); | ||||
|         let height = lines.len(); | ||||
|         let mut result = Self::new(width, height); | ||||
|         for (row, text_line) in lines.iter().enumerate() { | ||||
|             result.set_row_str(row, text_line).unwrap() | ||||
|         } | ||||
|         result | ||||
|     } | ||||
| 
 | ||||
|     /// Copies a column from the grid as a String.
 | ||||
|     ///
 | ||||
|     /// Returns [None] if x is out of bounds.
 | ||||
|     ///
 | ||||
|     /// # Examples
 | ||||
|     ///
 | ||||
|     /// ```
 | ||||
|     /// # use servicepoint::CharGrid;
 | ||||
|     /// let grid = CharGrid::from("ab\ncd");
 | ||||
|     /// let col = grid.get_col_str(0).unwrap(); // "ac"
 | ||||
|     /// ```
 | ||||
|     pub fn get_col_str(&self, x: usize) -> Option<String> { | ||||
|         Some(String::from_iter(self.get_col(x)?)) | ||||
|     } | ||||
|  | @ -30,6 +73,14 @@ impl CharGrid { | |||
|     /// Copies a row from the grid as a String.
 | ||||
|     ///
 | ||||
|     /// Returns [None] if y is out of bounds.
 | ||||
|     ///
 | ||||
|     /// # Examples
 | ||||
|     ///
 | ||||
|     /// ```
 | ||||
|     /// # use servicepoint::CharGrid;
 | ||||
|     /// let grid = CharGrid::from("ab\ncd");
 | ||||
|     /// let row = grid.get_row_str(0).unwrap(); // "ab"
 | ||||
|     /// ```
 | ||||
|     pub fn get_row_str(&self, y: usize) -> Option<String> { | ||||
|         Some(String::from_iter(self.get_row(y)?)) | ||||
|     } | ||||
|  | @ -37,6 +88,14 @@ impl CharGrid { | |||
|     /// Overwrites a row in the grid with a str.
 | ||||
|     ///
 | ||||
|     /// Returns [SetValueSeriesError] if y is out of bounds or `row` is not of the correct size.
 | ||||
|     ///
 | ||||
|     /// # Examples
 | ||||
|     ///
 | ||||
|     /// ```
 | ||||
|     /// # use servicepoint::CharGrid;
 | ||||
|     /// let mut grid = CharGrid::from("ab\ncd");
 | ||||
|     /// grid.set_row_str(0, "ef").unwrap();
 | ||||
|     /// ```
 | ||||
|     pub fn set_row_str( | ||||
|         &mut self, | ||||
|         y: usize, | ||||
|  | @ -48,6 +107,14 @@ impl CharGrid { | |||
|     /// Overwrites a column in the grid with a str.
 | ||||
|     ///
 | ||||
|     /// Returns [SetValueSeriesError] if y is out of bounds or `row` is not of the correct size.
 | ||||
|     ///
 | ||||
|     /// # Examples
 | ||||
|     ///
 | ||||
|     /// ```
 | ||||
|     /// # use servicepoint::CharGrid;
 | ||||
|     /// let mut grid = CharGrid::from("ab\ncd");
 | ||||
|     /// grid.set_col_str(0, "ef").unwrap();
 | ||||
|     /// ```
 | ||||
|     pub fn set_col_str( | ||||
|         &mut self, | ||||
|         x: usize, | ||||
|  | @ -60,9 +127,12 @@ impl CharGrid { | |||
|     ///
 | ||||
|     /// returns: [CharGrid] that contains the provided data, or [FromUtf8Error] if the data is invalid.
 | ||||
|     ///
 | ||||
|     /// # Panics
 | ||||
|     /// # Examples
 | ||||
|     ///
 | ||||
|     /// - when the dimensions and data size do not match exactly.
 | ||||
|     /// ```
 | ||||
|     /// # use servicepoint::CharGrid;
 | ||||
|     /// let grid = CharGrid::load_utf8(2, 2, [97u8, 98, 99, 100].to_vec());
 | ||||
|     /// ```
 | ||||
|     pub fn load_utf8( | ||||
|         width: usize, | ||||
|         height: usize, | ||||
|  | @ -117,6 +187,18 @@ impl From<CharGrid> for String { | |||
| } | ||||
| 
 | ||||
| impl From<&CharGrid> for String { | ||||
|     /// Converts a [CharGrid] into a [String].
 | ||||
|     ///
 | ||||
|     /// Rows are separated by '\n'.
 | ||||
|     ///
 | ||||
|     /// # Examples
 | ||||
|     ///
 | ||||
|     /// ```rust
 | ||||
|     /// # use servicepoint::CharGrid;
 | ||||
|     /// let grid = CharGrid::from("ab\ncd");
 | ||||
|     /// let string = String::from(grid);
 | ||||
|     /// let grid = CharGrid::from(string);
 | ||||
|     /// ```
 | ||||
|     fn from(value: &CharGrid) -> Self { | ||||
|         value | ||||
|             .iter_rows() | ||||
|  | @ -127,12 +209,26 @@ impl From<&CharGrid> for String { | |||
| } | ||||
| 
 | ||||
| impl From<&CharGrid> for Vec<u8> { | ||||
|     /// Converts a [CharGrid] into a [`Vec<u8>`].
 | ||||
|     ///
 | ||||
|     /// Rows are not separated.
 | ||||
|     ///
 | ||||
|     /// # Examples
 | ||||
|     ///
 | ||||
|     /// ```rust
 | ||||
|     /// # use servicepoint::{CharGrid, Grid};
 | ||||
|     /// let grid = CharGrid::from("ab\ncd");
 | ||||
|     /// let height = grid.height();
 | ||||
|     /// let width = grid.width();
 | ||||
|     /// let grid = CharGrid::load_utf8(width, height, grid.into());
 | ||||
|     /// ```
 | ||||
|     fn from(value: &CharGrid) -> Self { | ||||
|         String::from_iter(value.iter()).into_bytes() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<CharGrid> for Vec<u8> { | ||||
|     /// See [`From<&CharGrid>::from`].
 | ||||
|     fn from(value: CharGrid) -> Self { | ||||
|         Self::from(&value) | ||||
|     } | ||||
|  | @ -192,4 +288,11 @@ mod test { | |||
|         let copy = CharGrid::from(str); | ||||
|         assert_eq!(grid, copy); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn wrap_str() { | ||||
|         let grid = CharGrid::wrap_str(2, "abc\ndef"); | ||||
|         assert_eq!(4, grid.height()); | ||||
|         assert_eq!("ab\nc\0\nde\nf\0", String::from(grid)); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -90,6 +90,12 @@ mod feature_cp437 { | |||
|             value.map(Cp437Converter::cp437_to_char) | ||||
|         } | ||||
|     } | ||||
|     
 | ||||
|     impl From<Cp437Grid> for CharGrid { | ||||
|         fn from(value: Cp437Grid) -> Self { | ||||
|             Self::from(&value) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     impl From<&CharGrid> for Cp437Grid { | ||||
|         fn from(value: &CharGrid) -> Self { | ||||
|  | @ -99,7 +105,7 @@ mod feature_cp437 { | |||
| 
 | ||||
|     impl From<CharGrid> for Cp437Grid { | ||||
|         fn from(value: CharGrid) -> Self { | ||||
|             Cp437Grid::from(&value) | ||||
|             Self::from(&value) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -150,8 +156,8 @@ mod tests_feature_cp437 { | |||
|     #[test] | ||||
|     fn round_trip_cp437() { | ||||
|         let utf8 = CharGrid::load(2, 2, &['Ä', 'x', '\n', '$']); | ||||
|         let cp437 = Cp437Grid::from(&utf8); | ||||
|         let actual = CharGrid::from(&cp437); | ||||
|         let cp437 = Cp437Grid::from(utf8.clone()); | ||||
|         let actual = CharGrid::from(cp437); | ||||
|         assert_eq!(actual, utf8); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -79,6 +79,27 @@ impl<T: Value> ValueGrid<T> { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Loads a [ValueGrid] with the specified width from the provided data, wrapping to as many rows as needed.
 | ||||
|     ///
 | ||||
|     /// returns: [ValueGrid] that contains a copy of the provided data or [TryLoadValueGridError].
 | ||||
|     ///
 | ||||
|     /// # Examples
 | ||||
|     ///
 | ||||
|     /// ```
 | ||||
|     /// # use servicepoint::ValueGrid;
 | ||||
|     /// let grid = ValueGrid::wrap(2, &[0, 1, 2, 3, 4, 5]).unwrap();
 | ||||
|     /// ```
 | ||||
|     pub fn wrap( | ||||
|         width: usize, | ||||
|         data: &[T], | ||||
|     ) -> Result<Self, TryLoadValueGridError> { | ||||
|         let len = data.len(); | ||||
|         if len % width != 0 { | ||||
|             return Err(TryLoadValueGridError::InvalidDimensions); | ||||
|         } | ||||
|         Ok(Self::load(width, len / width, data)) | ||||
|     } | ||||
| 
 | ||||
|     /// Loads a [ValueGrid] with the specified dimensions from the provided data.
 | ||||
|     ///
 | ||||
|     /// returns: [ValueGrid] that contains a copy of the provided data or [TryLoadValueGridError].
 | ||||
|  | @ -277,7 +298,7 @@ impl<T: Value> ValueGrid<T> { | |||
| } | ||||
| 
 | ||||
| /// Errors that can occur when loading a grid
 | ||||
| #[derive(Debug, thiserror::Error)] | ||||
| #[derive(Debug, thiserror::Error, PartialEq)] | ||||
| pub enum TryLoadValueGridError { | ||||
|     #[error("The provided dimensions do not match with the data size")] | ||||
|     /// The provided dimensions do not match with the data size
 | ||||
|  | @ -537,4 +558,13 @@ mod tests { | |||
|             }) | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn wrap() { | ||||
|         let grid = ValueGrid::wrap(2, &[0, 1, 2, 3, 4, 5]).unwrap(); | ||||
|         assert_eq!(grid.height(), 3); | ||||
| 
 | ||||
|         let grid = ValueGrid::wrap(4, &[0, 1, 2, 3, 4, 5]); | ||||
|         assert_eq!(grid.err(), Some(TryLoadValueGridError::InvalidDimensions)); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| #include "servicepoint.h" | ||||
| 
 | ||||
| int main(void) { | ||||
|     SPConnection *connection = sp_connection_open("172.23.42.29:2342"); | ||||
|     SPConnection *connection = sp_connection_open("localhost:2342"); | ||||
|     if (connection == NULL) | ||||
|         return 1; | ||||
| 
 | ||||
|  | @ -10,9 +10,8 @@ int main(void) { | |||
|     sp_bitmap_fill(pixels, true); | ||||
| 
 | ||||
|     SPCommand *command = sp_command_bitmap_linear_win(0, 0, pixels, SP_COMPRESSION_CODE_UNCOMPRESSED); | ||||
|     while (sp_connection_send_command(connection, sp_command_clone(command))); | ||||
|     sp_connection_send_command(connection, command); | ||||
| 
 | ||||
|     sp_command_free(command); | ||||
|     sp_connection_free(connection); | ||||
|     return 0; | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vinzenz Schroeter
						Vinzenz Schroeter