add function to load Cp437Grid from str

This commit is contained in:
Vinzenz Schroeter 2024-10-11 21:38:12 +02:00
parent 21cc7e3f12
commit 03f7495695
4 changed files with 113 additions and 13 deletions

View file

@ -4,18 +4,13 @@ use crate::{
command_code::CommandCode,
compression::into_decompressed,
packet::{Header, Packet},
Brightness, BrightnessGrid, CompressionCode, Origin, PixelGrid, Pixels,
PrimitiveGrid, SpBitVec, Tiles, TILE_SIZE,
Brightness, BrightnessGrid, CompressionCode, Cp437Grid, Origin, PixelGrid,
Pixels, PrimitiveGrid, SpBitVec, Tiles, TILE_SIZE,
};
/// Type alias for documenting the meaning of the u16 in enum values
pub type Offset = usize;
/// A grid containing codepage 437 characters.
///
/// The encoding is currently not enforced.
pub type Cp437Grid = PrimitiveGrid<u8>;
/// A low-level display command.
///
/// This struct and associated functions implement the UDP protocol for the display.
@ -92,9 +87,8 @@ pub enum Command {
///
/// ```rust
/// # use servicepoint::{Command, Connection, Cp437Grid, Origin};
/// # let connection = Connection::open("127.0.0.1:2342").unwrap();
/// let chars = ['H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd'].map(move |c| c as u8);
/// let grid = Cp437Grid::load(5, 2, &chars);
/// # let connection = Connection::Fake;
/// let grid = Cp437Grid::load_ascii("Hello\nWorld", 5, false).unwrap();
/// connection.send(Command::Cp437Data(Origin::new(2, 2), grid)).unwrap();
/// ```
Cp437Data(Origin<Tiles>, Cp437Grid),

View file

@ -0,0 +1,100 @@
use crate::cp437::Cp437LoadError::InvalidChar;
use crate::{Grid, PrimitiveGrid};
/// A grid containing codepage 437 characters.
///
/// The encoding is currently not enforced.
pub type Cp437Grid = PrimitiveGrid<u8>;
#[derive(Debug)]
pub enum Cp437LoadError {
InvalidChar { index: usize, char: char },
}
impl Cp437Grid {
/// Load an ASCII-only [&str] into a [Cp437Grid] of specified width.
///
/// # Panics
///
/// - for width == 0
/// - on empty strings
pub fn load_ascii(
value: &str,
width: usize,
wrap: bool,
) -> Result<Self, Cp437LoadError> {
assert!(width > 0);
assert!(!value.is_empty());
let mut chars = {
let mut x = 0;
let mut y = 0;
for (index, char) in value.chars().enumerate() {
if !char.is_ascii() {
return Err(InvalidChar { index, char });
}
let is_lf = char == '\n';
if is_lf || (wrap && x == width) {
y += 1;
x = 0;
if is_lf {
continue;
}
}
x += 1;
}
Cp437Grid::new(width, y + 1)
};
let mut x = 0;
let mut y = 0;
for char in value.chars().map(move |c| c as u8) {
let is_lf = char == b'\n';
if is_lf || (wrap && x == width) {
y += 1;
x = 0;
if is_lf {
continue;
}
}
if wrap || x < width {
chars.set(x, y, char);
}
x += 1;
}
Ok(chars)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn load_ascii_nowrap() {
let chars = ['H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd']
.map(move |c| c as u8);
let expected = Cp437Grid::load(5, 2, &chars);
let actual = Cp437Grid::load_ascii("Hello,\nWorld!", 5, false).unwrap();
// comma will be removed because line is too long and wrap is off
assert_eq!(actual, expected);
}
#[test]
fn load_ascii_wrap() {
let chars = ['H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd']
.map(move |c| c as u8);
let expected = Cp437Grid::load(5, 2, &chars);
let actual = Cp437Grid::load_ascii("HelloWorld", 5, true).unwrap();
// line break will be added
assert_eq!(actual, expected);
}
}

View file

@ -41,9 +41,10 @@ pub use bitvec;
use bitvec::prelude::{BitVec, Msb0};
pub use crate::brightness::{Brightness, BrightnessGrid};
pub use crate::command::{Command, Cp437Grid, Offset};
pub use crate::command::{Command, Offset};
pub use crate::compression_code::CompressionCode;
pub use crate::connection::Connection;
pub use crate::cp437::Cp437Grid;
pub use crate::data_ref::DataRef;
pub use crate::grid::Grid;
pub use crate::origin::{Origin, Pixels, Tiles};
@ -58,6 +59,7 @@ mod command_code;
mod compression;
mod compression_code;
mod connection;
mod cp437;
mod data_ref;
mod grid;
mod origin;

View file

@ -40,7 +40,9 @@ pub unsafe extern "C" fn sp_cp437_grid_new(
width: usize,
height: usize,
) -> *mut SPCp437Grid {
Box::into_raw(Box::new(SPCp437Grid(servicepoint::Cp437Grid::new(width, height))))
Box::into_raw(Box::new(SPCp437Grid(servicepoint::Cp437Grid::new(
width, height,
))))
}
/// Loads a `SPCp437Grid` with the specified dimensions from the provided data.
@ -67,7 +69,9 @@ pub unsafe extern "C" fn sp_cp437_grid_load(
data_length: usize,
) -> *mut SPCp437Grid {
let data = std::slice::from_raw_parts(data, data_length);
Box::into_raw(Box::new(SPCp437Grid(servicepoint::Cp437Grid::load(width, height, data))))
Box::into_raw(Box::new(SPCp437Grid(servicepoint::Cp437Grid::load(
width, height, data,
))))
}
/// Clones a `SPCp437Grid`.