mirror of
https://github.com/cccb/servicepoint.git
synced 2025-01-18 02:00:12 +01:00
first CMD_UTF8_DATA implementation
UTF8 now works
This commit is contained in:
parent
38316169e9
commit
efaa52faa1
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,3 +4,4 @@ out
|
|||
.direnv
|
||||
.envrc
|
||||
result
|
||||
mutants.*
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use clap::Parser;
|
||||
|
||||
use servicepoint::{CharGrid, Command, Connection, Cp437Grid, Origin};
|
||||
use servicepoint::{CharGrid, Command, Connection, Origin, TILE_WIDTH};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
struct Cli {
|
||||
|
@ -41,11 +41,21 @@ fn main() {
|
|||
.expect("sending clear failed");
|
||||
}
|
||||
|
||||
let text = cli.text.join("\n");
|
||||
let grid = CharGrid::from(text);
|
||||
let grid = Cp437Grid::from(grid);
|
||||
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);
|
||||
connection
|
||||
.send(Command::Cp437Data(Origin::ZERO, grid))
|
||||
.send(Command::Utf8Data(Origin::ZERO, grid))
|
||||
.expect("sending text failed");
|
||||
}
|
||||
|
|
|
@ -31,11 +31,8 @@ fn main() {
|
|||
let mut filled_grid = Bitmap::max_sized();
|
||||
filled_grid.fill(true);
|
||||
|
||||
let command = BitmapLinearWin(
|
||||
Origin::ZERO,
|
||||
filled_grid,
|
||||
CompressionCode::Lzma,
|
||||
);
|
||||
let command =
|
||||
BitmapLinearWin(Origin::ZERO, filled_grid, CompressionCode::Lzma);
|
||||
connection.send(command).expect("send failed");
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,11 @@ fn main() {
|
|||
}
|
||||
|
||||
connection
|
||||
.send(Command::BitmapLinearWin(Origin::ZERO, enabled_pixels.clone(), CompressionCode::Lzma))
|
||||
.send(Command::BitmapLinearWin(
|
||||
Origin::ZERO,
|
||||
enabled_pixels.clone(),
|
||||
CompressionCode::Lzma,
|
||||
))
|
||||
.expect("could not send command to display");
|
||||
thread::sleep(sleep_duration);
|
||||
}
|
||||
|
|
|
@ -203,7 +203,7 @@ impl<'t> Iterator for IterRows<'t> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{Bitmap, DataRef, Grid};
|
||||
use crate::{BitVec, Bitmap, DataRef, Grid};
|
||||
|
||||
#[test]
|
||||
fn fill() {
|
||||
|
@ -295,4 +295,12 @@ mod tests {
|
|||
data[1] = 0x0F;
|
||||
assert!(grid.get(7, 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_bitvec() {
|
||||
let mut grid = Bitmap::new(8, 2);
|
||||
grid.set(0, 0, true);
|
||||
let bitvec: BitVec = grid.into();
|
||||
assert_eq!(bitvec.as_raw_slice(), [0x80, 0x00]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{Grid, PrimitiveGrid};
|
||||
|
||||
use crate::primitive_grid::PrimitiveGrid;
|
||||
use crate::{ByteGrid, Grid};
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{
|
||||
distributions::{Distribution, Standard},
|
||||
|
@ -40,7 +40,8 @@ pub type BrightnessGrid = PrimitiveGrid<Brightness>;
|
|||
impl BrightnessGrid {
|
||||
/// Like [Self::load], but ignoring any out-of-range brightness values
|
||||
pub fn saturating_load(width: usize, height: usize, data: &[u8]) -> Self {
|
||||
PrimitiveGrid::load(width, height, data).map(Brightness::saturating_from)
|
||||
PrimitiveGrid::load(width, height, data)
|
||||
.map(Brightness::saturating_from)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +102,7 @@ impl From<BrightnessGrid> for Vec<u8> {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<&BrightnessGrid> for PrimitiveGrid<u8> {
|
||||
impl From<&BrightnessGrid> for ByteGrid {
|
||||
fn from(value: &PrimitiveGrid<Brightness>) -> Self {
|
||||
let u8s = value
|
||||
.iter()
|
||||
|
@ -111,10 +112,10 @@ impl From<&BrightnessGrid> for PrimitiveGrid<u8> {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryFrom<PrimitiveGrid<u8>> for BrightnessGrid {
|
||||
impl TryFrom<ByteGrid> for BrightnessGrid {
|
||||
type Error = u8;
|
||||
|
||||
fn try_from(value: PrimitiveGrid<u8>) -> Result<Self, Self::Error> {
|
||||
fn try_from(value: ByteGrid) -> Result<Self, Self::Error> {
|
||||
let brightnesses = value
|
||||
.iter()
|
||||
.map(|b| Brightness::try_from(*b))
|
||||
|
@ -171,7 +172,18 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn saturating_load() {
|
||||
assert_eq!(BrightnessGrid::load(2,2, &[Brightness::MAX, Brightness::MAX, Brightness::MIN, Brightness::MAX]),
|
||||
BrightnessGrid::saturating_load(2,2, &[255u8, 23, 0, 42]));
|
||||
assert_eq!(
|
||||
BrightnessGrid::load(
|
||||
2,
|
||||
2,
|
||||
&[
|
||||
Brightness::MAX,
|
||||
Brightness::MAX,
|
||||
Brightness::MIN,
|
||||
Brightness::MAX
|
||||
]
|
||||
),
|
||||
BrightnessGrid::saturating_load(2, 2, &[255u8, 23, 0, 42])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use crate::primitive_grid::SeriesError;
|
||||
use crate::{Grid, PrimitiveGrid};
|
||||
use crate::primitive_grid::{
|
||||
PrimitiveGrid, SeriesError, TryLoadPrimitiveGridError,
|
||||
};
|
||||
use crate::Grid;
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
/// A grid containing UTF-8 characters.
|
||||
pub type CharGrid = PrimitiveGrid<char>;
|
||||
|
@ -40,17 +43,39 @@ impl CharGrid {
|
|||
) -> Result<(), SeriesError> {
|
||||
self.set_col(x, value.chars().collect::<Vec<_>>().as_ref())
|
||||
}
|
||||
|
||||
/// Loads a [CharGrid] with the specified dimensions from the provided UTF-8 bytes.
|
||||
///
|
||||
/// returns: [CharGrid] that contains the provided data, or [FromUtf8Error] if the data is invalid.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - when the dimensions and data size do not match exactly.
|
||||
pub fn load_utf8(
|
||||
width: usize,
|
||||
height: usize,
|
||||
bytes: Vec<u8>,
|
||||
) -> Result<CharGrid, LoadUtf8Error> {
|
||||
let s: Vec<char> = String::from_utf8(bytes)?.chars().collect();
|
||||
Ok(CharGrid::try_load(width, height, s)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum LoadUtf8Error {
|
||||
#[error(transparent)]
|
||||
FromUtf8Error(#[from] FromUtf8Error),
|
||||
#[error(transparent)]
|
||||
TryLoadError(#[from] TryLoadPrimitiveGridError),
|
||||
}
|
||||
|
||||
impl From<&str> for CharGrid {
|
||||
fn from(value: &str) -> Self {
|
||||
let value = value.replace("\r\n", "\n");
|
||||
let mut lines = value
|
||||
.split('\n')
|
||||
.map(move |line| line.trim_end())
|
||||
.collect::<Vec<_>>();
|
||||
let width =
|
||||
lines.iter().fold(0, move |a, x| std::cmp::max(a, x.len()));
|
||||
let mut lines = value.split('\n').collect::<Vec<_>>();
|
||||
let width = lines
|
||||
.iter()
|
||||
.fold(0, move |a, x| std::cmp::max(a, x.chars().count()));
|
||||
|
||||
while lines.last().is_some_and(move |line| line.is_empty()) {
|
||||
_ = lines.pop();
|
||||
|
@ -73,22 +98,34 @@ impl From<String> for CharGrid {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<CharGrid> for String {
|
||||
fn from(grid: CharGrid) -> Self {
|
||||
String::from(&grid)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&CharGrid> for String {
|
||||
fn from(value: &CharGrid) -> Self {
|
||||
value
|
||||
.iter_rows()
|
||||
.map(move |chars| {
|
||||
chars
|
||||
.collect::<String>()
|
||||
.replace('\0', " ")
|
||||
.trim_end()
|
||||
.to_string()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.map(String::from_iter)
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&CharGrid> for Vec<u8> {
|
||||
fn from(value: &CharGrid) -> Self {
|
||||
String::from_iter(value.iter()).into_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CharGrid> for Vec<u8> {
|
||||
fn from(value: CharGrid) -> Self {
|
||||
Self::from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -120,10 +157,28 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn str_to_char_grid() {
|
||||
let original = "Hello\r\nWorld!\n...\n";
|
||||
// conversion with .to_string() covers one more line
|
||||
let original = "Hello\r\nWorld!\n...\n".to_string();
|
||||
|
||||
let grid = CharGrid::from(original);
|
||||
assert_eq!(3, grid.height());
|
||||
let actual = String::from(&grid);
|
||||
assert_eq!("Hello\nWorld!\n...", actual);
|
||||
assert_eq!("Hello\0\nWorld!\n...\0\0\0", String::from(grid));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_bytes() {
|
||||
let grid = CharGrid::from("Hello\0\nWorld!\n...\0\0\0");
|
||||
let bytes: Vec<u8> = grid.clone().into();
|
||||
let copy =
|
||||
CharGrid::load_utf8(grid.width(), grid.height(), bytes).unwrap();
|
||||
assert_eq!(grid, copy);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_string() {
|
||||
let grid = CharGrid::from("Hello\0\nWorld!\n...\0\0\0");
|
||||
let str: String = grid.clone().into();
|
||||
let copy = CharGrid::from(str);
|
||||
assert_eq!(grid, copy);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::primitive_grid::PrimitiveGrid;
|
||||
use crate::{
|
||||
command_code::CommandCode,
|
||||
compression::into_decompressed,
|
||||
packet::{Header, Packet},
|
||||
Bitmap, Brightness, BrightnessGrid, CompressionCode, Cp437Grid, Origin,
|
||||
Pixels, PrimitiveGrid, BitVec, Tiles, TILE_SIZE,
|
||||
BitVec, Bitmap, Brightness, BrightnessGrid, CharGrid, CompressionCode,
|
||||
Cp437Grid, Origin, Pixels, Tiles, TILE_SIZE,
|
||||
};
|
||||
|
||||
/// Type alias for documenting the meaning of the u16 in enum values
|
||||
|
@ -72,10 +73,27 @@ pub enum Command {
|
|||
/// ```
|
||||
Clear,
|
||||
|
||||
/// Show text on the screen.
|
||||
///
|
||||
/// The text is sent in the form of a 2D grid of UTF-8 encoded characters (the default encoding in rust).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use servicepoint::{Command, Connection, Origin};
|
||||
/// # let connection = Connection::Fake;
|
||||
/// use servicepoint::{CharGrid};
|
||||
/// let grid = CharGrid::from("Hello,\nWorld!");
|
||||
/// connection.send(Command::Utf8Data(Origin::ZERO, grid)).expect("send failed");
|
||||
/// ```
|
||||
Utf8Data(Origin<Tiles>, CharGrid),
|
||||
|
||||
/// Show text on the screen.
|
||||
///
|
||||
/// The text is sent in the form of a 2D grid of [CP-437] encoded characters.
|
||||
///
|
||||
/// <div class="warning">You probably want to use [Command::Utf8Data] instead</div>
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -234,6 +252,8 @@ pub enum TryFromPacketError {
|
|||
/// The given brightness value is out of bounds
|
||||
#[error("The given brightness value {0} is out of bounds.")]
|
||||
InvalidBrightness(u8),
|
||||
#[error(transparent)]
|
||||
InvalidUtf8(#[from] std::string::FromUtf8Error),
|
||||
}
|
||||
|
||||
impl TryFrom<Packet> for Command {
|
||||
|
@ -269,6 +289,7 @@ impl TryFrom<Packet> for Command {
|
|||
CommandCode::CharBrightness => {
|
||||
Self::packet_into_char_brightness(&packet)
|
||||
}
|
||||
CommandCode::Utf8Data => Self::packet_into_utf8(&packet),
|
||||
#[allow(deprecated)]
|
||||
CommandCode::BitmapLegacy => Ok(Command::BitmapLegacy),
|
||||
CommandCode::BitmapLinear => {
|
||||
|
@ -489,6 +510,28 @@ impl Command {
|
|||
Cp437Grid::load(*c as usize, *d as usize, payload),
|
||||
))
|
||||
}
|
||||
|
||||
fn packet_into_utf8(
|
||||
packet: &Packet,
|
||||
) -> Result<Command, TryFromPacketError> {
|
||||
let Packet {
|
||||
header:
|
||||
Header {
|
||||
command_code: _,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
d,
|
||||
},
|
||||
payload,
|
||||
} = packet;
|
||||
let payload: Vec<_> =
|
||||
String::from_utf8(payload.clone())?.chars().collect();
|
||||
Ok(Command::Utf8Data(
|
||||
Origin::new(*a as usize, *b as usize),
|
||||
CharGrid::load(*c as usize, *d as usize, &*payload),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -499,8 +542,8 @@ mod tests {
|
|||
command_code::CommandCode,
|
||||
origin::Pixels,
|
||||
packet::{Header, Packet},
|
||||
Bitmap, Brightness, BrightnessGrid, Command, CompressionCode, Origin,
|
||||
PrimitiveGrid,
|
||||
Bitmap, Brightness, BrightnessGrid, CharGrid, Command, CompressionCode,
|
||||
Cp437Grid, Origin,
|
||||
};
|
||||
|
||||
fn round_trip(original: Command) {
|
||||
|
@ -556,16 +599,18 @@ mod tests {
|
|||
fn round_trip_char_brightness() {
|
||||
round_trip(Command::CharBrightness(
|
||||
Origin::new(5, 2),
|
||||
PrimitiveGrid::new(7, 5),
|
||||
BrightnessGrid::new(7, 5),
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_cp437_data() {
|
||||
round_trip(Command::Cp437Data(
|
||||
Origin::new(5, 2),
|
||||
PrimitiveGrid::new(7, 5),
|
||||
));
|
||||
round_trip(Command::Cp437Data(Origin::new(5, 2), Cp437Grid::new(7, 5)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_utf8_data() {
|
||||
round_trip(Command::Utf8Data(Origin::new(5, 2), CharGrid::new(7, 5)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -21,6 +21,7 @@ pub(crate) enum CommandCode {
|
|||
BitmapLinearWinBzip2 = 0x0018,
|
||||
#[cfg(feature = "compression_lzma")]
|
||||
BitmapLinearWinLzma = 0x0019,
|
||||
Utf8Data = 0x0020,
|
||||
#[cfg(feature = "compression_zstd")]
|
||||
BitmapLinearWinZstd = 0x001A,
|
||||
}
|
||||
|
@ -93,6 +94,9 @@ impl TryFrom<u16> for CommandCode {
|
|||
value if value == CommandCode::BitmapLinearWinBzip2 as u16 => {
|
||||
Ok(CommandCode::BitmapLinearWinBzip2)
|
||||
}
|
||||
value if value == CommandCode::Utf8Data as u16 => {
|
||||
Ok(CommandCode::Utf8Data)
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,9 +107,7 @@ impl Connection {
|
|||
|
||||
let request = ClientRequestBuilder::new(uri).into_client_request()?;
|
||||
let (sock, _) = connect(request)?;
|
||||
Ok(Self::WebSocket(std::sync::Mutex::new(
|
||||
sock,
|
||||
)))
|
||||
Ok(Self::WebSocket(std::sync::Mutex::new(sock)))
|
||||
}
|
||||
|
||||
/// Send something packet-like to the display. Usually this is in the form of a Command.
|
||||
|
@ -159,9 +157,7 @@ impl Drop for Connection {
|
|||
fn drop(&mut self) {
|
||||
#[cfg(feature = "protocol_websocket")]
|
||||
if let Connection::WebSocket(sock) = self {
|
||||
_ = sock
|
||||
.try_lock()
|
||||
.map(move |mut sock| sock.close(None));
|
||||
_ = sock.try_lock().map(move |mut sock| sock.close(None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//!
|
||||
//! Most of the functionality is only available with feature "cp437" enabled.
|
||||
|
||||
use crate::{Grid, PrimitiveGrid};
|
||||
use crate::{Grid, primitive_grid::PrimitiveGrid};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// A grid containing codepage 437 characters.
|
||||
|
@ -12,7 +12,9 @@ pub type Cp437Grid = PrimitiveGrid<u8>;
|
|||
|
||||
/// The error occurring when loading an invalid character
|
||||
#[derive(Debug, PartialEq, thiserror::Error)]
|
||||
#[error("The character {char:?} at position {index} is not a valid CP437 character")]
|
||||
#[error(
|
||||
"The character {char:?} at position {index} is not a valid CP437 character"
|
||||
)]
|
||||
pub struct InvalidCharError {
|
||||
/// invalid character is at this position in input
|
||||
index: usize,
|
||||
|
|
|
@ -49,11 +49,13 @@ pub use crate::cp437::Cp437Grid;
|
|||
pub use crate::data_ref::DataRef;
|
||||
pub use crate::grid::Grid;
|
||||
pub use crate::origin::{Origin, Pixels, Tiles};
|
||||
pub use crate::primitive_grid::{PrimitiveGrid, SeriesError};
|
||||
|
||||
/// An alias for the specific type of [bitvec::prelude::BitVec] used.
|
||||
pub type BitVec = bitvec::prelude::BitVec<u8, bitvec::prelude::Msb0>;
|
||||
|
||||
/// A simple grid of bytes - see [primitive_grid::PrimitiveGrid].
|
||||
pub type ByteGrid = primitive_grid::PrimitiveGrid<u8>;
|
||||
|
||||
mod bitmap;
|
||||
mod brightness;
|
||||
mod char_grid;
|
||||
|
@ -67,7 +69,7 @@ mod data_ref;
|
|||
mod grid;
|
||||
mod origin;
|
||||
pub mod packet;
|
||||
mod primitive_grid;
|
||||
pub mod primitive_grid;
|
||||
|
||||
/// size of a single tile in one dimension
|
||||
pub const TILE_SIZE: usize = 8;
|
||||
|
|
|
@ -209,6 +209,9 @@ impl From<Command> for Packet {
|
|||
grid,
|
||||
CommandCode::Cp437Data,
|
||||
),
|
||||
Command::Utf8Data(origin, grid) => {
|
||||
Self::origin_grid_to_packet(origin, grid, CommandCode::Utf8Data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
//! This module contains the implementation of the [PrimitiveGrid].
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::slice::{Iter, IterMut};
|
||||
|
||||
use crate::{DataRef, Grid};
|
||||
|
||||
pub trait PrimitiveGridType: Sized + Default + Copy + Clone {}
|
||||
impl<T: Sized + Default + Copy + Clone> PrimitiveGridType for T {}
|
||||
/// A type that can be stored in a [PrimitiveGrid], e.g. [char], [u8].
|
||||
pub trait PrimitiveGridType: Sized + Default + Copy + Clone + Debug {}
|
||||
impl<T: Sized + Default + Copy + Clone + Debug> PrimitiveGridType for T {}
|
||||
|
||||
/// A 2D grid of bytes
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -60,7 +64,11 @@ impl<T: PrimitiveGridType> PrimitiveGrid<T> {
|
|||
/// - when the dimensions and data size do not match exactly.
|
||||
#[must_use]
|
||||
pub fn load(width: usize, height: usize, data: &[T]) -> Self {
|
||||
assert_eq!(width * height, data.len());
|
||||
assert_eq!(
|
||||
width * height,
|
||||
data.len(),
|
||||
"dimension mismatch for data {data:?}"
|
||||
);
|
||||
Self {
|
||||
data: Vec::from(data),
|
||||
width,
|
||||
|
@ -68,12 +76,31 @@ impl<T: PrimitiveGridType> PrimitiveGrid<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Loads a [PrimitiveGrid] with the specified dimensions from the provided data.
|
||||
///
|
||||
/// returns: [PrimitiveGrid] that contains a copy of the provided data or [TryLoadPrimitiveGridError].
|
||||
pub fn try_load(
|
||||
width: usize,
|
||||
height: usize,
|
||||
data: Vec<T>,
|
||||
) -> Result<Self, TryLoadPrimitiveGridError> {
|
||||
if width * height != data.len() {
|
||||
return Err(TryLoadPrimitiveGridError::InvalidDimensions);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
data,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
|
||||
/// Iterate over all cells in [PrimitiveGrid].
|
||||
///
|
||||
/// Order is equivalent to the following loop:
|
||||
/// ```
|
||||
/// # use servicepoint::{PrimitiveGrid, Grid};
|
||||
/// # let grid = PrimitiveGrid::<u8>::new(2,2);
|
||||
/// # use servicepoint::{ByteGrid, Grid};
|
||||
/// # let grid = ByteGrid::new(2,2);
|
||||
/// for y in 0..grid.height() {
|
||||
/// for x in 0..grid.width() {
|
||||
/// grid.get(x, y);
|
||||
|
@ -140,9 +167,9 @@ impl<T: PrimitiveGridType> PrimitiveGrid<T> {
|
|||
///
|
||||
/// Use logic written for u8s and then convert to [Brightness] values for sending in a [Command].
|
||||
/// ```
|
||||
/// # fn foo(grid: &mut PrimitiveGrid<u8>) {}
|
||||
/// # use servicepoint::{Brightness, BrightnessGrid, Command, Origin, PrimitiveGrid, TILE_HEIGHT, TILE_WIDTH};
|
||||
/// let mut grid: PrimitiveGrid<u8> = PrimitiveGrid::new(TILE_WIDTH, TILE_HEIGHT);
|
||||
/// # fn foo(grid: &mut ByteGrid) {}
|
||||
/// # use servicepoint::{Brightness, BrightnessGrid, ByteGrid, Command, Origin, TILE_HEIGHT, TILE_WIDTH};
|
||||
/// let mut grid: ByteGrid = ByteGrid::new(TILE_WIDTH, TILE_HEIGHT);
|
||||
/// foo(&mut grid);
|
||||
/// let grid: BrightnessGrid = grid.map(Brightness::saturating_from);
|
||||
/// let command = Command::CharBrightness(Origin::ZERO, grid);
|
||||
|
@ -238,6 +265,12 @@ impl<T: PrimitiveGridType> PrimitiveGrid<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum TryLoadPrimitiveGridError {
|
||||
#[error("The provided dimensions do not match with the data size")]
|
||||
InvalidDimensions,
|
||||
}
|
||||
|
||||
impl<T: PrimitiveGridType> Grid<T> for PrimitiveGrid<T> {
|
||||
/// Sets the value of the cell at the specified position in the `PrimitiveGrid.
|
||||
///
|
||||
|
@ -300,6 +333,7 @@ impl<T: PrimitiveGridType> From<PrimitiveGrid<T>> for Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An iterator iver the rows in a [PrimitiveGrid]
|
||||
pub struct IterRows<'t, T: PrimitiveGridType> {
|
||||
byte_grid: &'t PrimitiveGrid<T>,
|
||||
row: usize,
|
||||
|
@ -323,7 +357,8 @@ impl<'t, T: PrimitiveGridType> Iterator for IterRows<'t, T> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{DataRef, Grid, PrimitiveGrid, SeriesError};
|
||||
use crate::primitive_grid::{PrimitiveGrid, SeriesError};
|
||||
use crate::{DataRef, Grid};
|
||||
|
||||
#[test]
|
||||
fn fill() {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//! prefix `sp_brightness_grid_`
|
||||
|
||||
use crate::SPByteSlice;
|
||||
use servicepoint::{Brightness, DataRef, Grid, PrimitiveGrid};
|
||||
use servicepoint::{Brightness, ByteGrid, DataRef, Grid};
|
||||
use std::convert::Into;
|
||||
use std::intrinsics::transmute;
|
||||
use std::ptr::NonNull;
|
||||
|
@ -80,7 +80,7 @@ pub unsafe extern "C" fn sp_brightness_grid_load(
|
|||
) -> NonNull<SPBrightnessGrid> {
|
||||
assert!(!data.is_null());
|
||||
let data = std::slice::from_raw_parts(data, data_length);
|
||||
let grid = PrimitiveGrid::load(width, height, data);
|
||||
let grid = ByteGrid::load(width, height, data);
|
||||
let grid = servicepoint::BrightnessGrid::try_from(grid)
|
||||
.expect("invalid brightness value");
|
||||
let result = Box::new(SPBrightnessGrid(grid));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use servicepoint::{Grid, SeriesError};
|
||||
use crate::cp437_grid::Cp437Grid;
|
||||
use servicepoint::{Grid, primitive_grid::SeriesError};
|
||||
use std::convert::Into;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use crate::cp437_grid::Cp437Grid;
|
||||
|
||||
#[derive(uniffi::Object)]
|
||||
pub struct CharGrid {
|
||||
|
|
Loading…
Reference in a new issue