mirror of
https://github.com/cccb/servicepoint.git
synced 2025-01-18 02:00:12 +01:00
add ValueGrid::wrap and CharGrid::wrap_str, more examples
add examples
This commit is contained in:
parent
2a6005fff9
commit
04cda144ed
|
@ -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…
Reference in a new issue