Skip to content

Commit

Permalink
add ValueGrid::wrap and CharGrid::wrap_str, more examples
Browse files Browse the repository at this point in the history
add examples
  • Loading branch information
kaesaecracker committed Jan 12, 2025
1 parent 66f2663 commit 6377b8c
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 26 deletions.
16 changes: 2 additions & 14 deletions crates/servicepoint/examples/announce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
10 changes: 9 additions & 1 deletion crates/servicepoint/src/bitmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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()) {
Expand All @@ -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()) {
Expand Down
111 changes: 107 additions & 4 deletions crates/servicepoint/src/char_grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
///
Expand All @@ -20,23 +20,82 @@ 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)?))
}

/// 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)?))
}

/// 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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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()
Expand All @@ -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)
}
Expand Down Expand Up @@ -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));
}
}
12 changes: 9 additions & 3 deletions crates/servicepoint/src/cp437_grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -99,7 +105,7 @@ mod feature_cp437 {

impl From<CharGrid> for Cp437Grid {
fn from(value: CharGrid) -> Self {
Cp437Grid::from(&value)
Self::from(&value)
}
}
}
Expand Down Expand Up @@ -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);
}
}
32 changes: 31 additions & 1 deletion crates/servicepoint/src/value_grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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].
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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));
}
}
5 changes: 2 additions & 3 deletions crates/servicepoint_binding_c/examples/lang_c/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@
#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;

SPBitmap *pixels = sp_bitmap_new(SP_PIXEL_WIDTH, SP_PIXEL_HEIGHT);
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;
}

0 comments on commit 6377b8c

Please sign in to comment.