encode origin unit in type

This commit is contained in:
Vinzenz Schroeter 2024-06-23 13:38:46 +02:00
parent 672b5e0581
commit e0647bacd6
10 changed files with 120 additions and 76 deletions

View file

@ -44,6 +44,6 @@ fn main() {
}
connection
.send(Command::Cp437Data(Origin(0, 0), chars))
.send(Command::Cp437Data(Origin::new(0, 0), chars))
.expect("sending text failed");
}

View file

@ -21,7 +21,7 @@ fn main() {
connection
.send(BitmapLinearWin(
Origin(0, 0),
Origin::new(0, 0),
pixels,
CompressionCode::Uncompressed,
))
@ -33,6 +33,6 @@ fn main() {
}
connection
.send(Command::CharBrightness(Origin(0, 0), brightnesses))
.send(Command::CharBrightness(Origin::new(0, 0), brightnesses))
.expect("send failed");
}

View file

@ -25,7 +25,7 @@ fn main() {
loop {
connection
.send(Command::BitmapLinearWin(
Origin(0, 0),
Origin::new(0, 0),
field.clone(),
CompressionCode::Lzma,
))

View file

@ -25,7 +25,7 @@ fn main() {
}
connection
.send(Command::BitmapLinearWin(
Origin(0, 0),
Origin::new(0, 0),
pixels.clone(),
CompressionCode::Lzma,
))

View file

@ -1,26 +1,12 @@
use bitvec::prelude::BitVec;
use crate::command_code::CommandCode;
use crate::compression::{into_compressed, into_decompressed};
use crate::{
Brightness, ByteGrid, CompressionCode, Grid, Header, Packet, PixelGrid,
SpBitVec, TILE_SIZE,
command_code::CommandCode,
compression::{into_compressed, into_decompressed},
Brightness, ByteGrid, CompressionCode, Grid, Header, Origin, Packet,
PixelGrid, Pixels, SpBitVec, Tiles, TILE_SIZE,
};
/// An origin marks the top left position of a window sent to the display.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Origin(pub usize, pub usize);
impl std::ops::Add<Origin> for Origin {
type Output = Origin;
fn add(self, rhs: Origin) -> Self::Output {
let Origin(x1, y1) = self;
let Origin(x2, y2) = rhs;
Origin(x1 + x2, y1 + y2)
}
}
/// Type alias for documenting the meaning of the u16 in enum values
pub type Offset = usize;
@ -32,24 +18,20 @@ pub enum Command {
/// Show text on the screen.
///
/// The origin is in tiles.
///
/// <div class="warning">
/// The library does not currently convert between UTF-8 and CP-437.
/// Because Rust expects UTF-8 strings, it might be necessary to only send ASCII for now.
/// </div>
Cp437Data(Origin, ByteGrid),
Cp437Data(Origin<Tiles>, ByteGrid),
/// Sets a window of pixels to the specified values
BitmapLinearWin(Origin, PixelGrid, CompressionCode),
BitmapLinearWin(Origin<Pixels>, PixelGrid, CompressionCode),
/// Set the brightness of all tiles to the same value.
Brightness(Brightness),
/// Set the brightness of individual tiles in a rectangular area of the display.
///
/// The origin is in tiles.
CharBrightness(Origin, ByteGrid),
CharBrightness(Origin<Tiles>, ByteGrid),
/// Set pixel data starting at the pixel offset on screen.
///
@ -116,11 +98,11 @@ impl From<Command> for Packet {
Command::BitmapLegacy => {
Command::command_code_only(CommandCode::BitmapLegacy)
}
Command::CharBrightness(Origin(x, y), grid) => Packet(
Command::CharBrightness(origin, grid) => Packet(
Header(
CommandCode::CharBrightness.into(),
x as u16,
y as u16,
origin.x as u16,
origin.y as u16,
grid.width() as u16,
grid.height() as u16,
),
@ -171,11 +153,11 @@ impl From<Command> for Packet {
bits.into(),
)
}
Command::Cp437Data(Origin(x, y), grid) => Packet(
Command::Cp437Data(origin, grid) => Packet(
Header(
CommandCode::Cp437Data.into(),
x as u16,
y as u16,
origin.x as u16,
origin.y as u16,
grid.width() as u16,
grid.height() as u16,
),
@ -187,15 +169,14 @@ impl From<Command> for Packet {
#[allow(clippy::cast_possible_truncation)]
fn bitmap_win_into_packet(
origin: Origin,
origin: Origin<Pixels>,
pixels: PixelGrid,
compression: CompressionCode,
) -> Packet {
let Origin(pixel_x, pixel_y) = origin;
debug_assert_eq!(pixel_x % 8, 0);
debug_assert_eq!(origin.x % 8, 0);
debug_assert_eq!(pixels.width() % 8, 0);
let tile_x = (pixel_x / TILE_SIZE) as u16;
let tile_x = (origin.x / TILE_SIZE) as u16;
let tile_w = (pixels.width() / TILE_SIZE) as u16;
let pixel_h = pixels.height() as u16;
let payload = into_compressed(compression, pixels.into());
@ -214,7 +195,7 @@ fn bitmap_win_into_packet(
};
Packet(
Header(command.into(), tile_x, pixel_y as u16, tile_w, pixel_h),
Header(command.into(), tile_x, origin.y as u16, tile_w, pixel_h),
payload,
)
}
@ -289,14 +270,14 @@ impl TryFrom<Packet> for Command {
CommandCode::Cp437Data => {
let Packet(_, payload) = packet;
Ok(Command::Cp437Data(
Origin(a as usize, b as usize),
Origin::new(a as usize, b as usize),
ByteGrid::load(c as usize, d as usize, &payload),
))
}
CommandCode::CharBrightness => {
let Packet(_, payload) = packet;
Ok(Command::CharBrightness(
Origin(a as usize, b as usize),
Origin::new(a as usize, b as usize),
ByteGrid::load(c as usize, d as usize, &payload),
))
}
@ -362,7 +343,7 @@ impl Command {
};
Ok(Command::BitmapLinearWin(
Origin(tiles_x as usize * TILE_SIZE, pixels_y as usize),
Origin::new(tiles_x as usize * TILE_SIZE, pixels_y as usize),
PixelGrid::load(
tile_w as usize * TILE_SIZE,
pixel_h as usize,
@ -441,13 +422,10 @@ impl Command {
#[cfg(test)]
mod tests {
use bitvec::prelude::BitVec;
use crate::command::TryFromPacketError;
use crate::command_code::CommandCode;
use crate::{
Brightness, ByteGrid, Command, CompressionCode, Header, Origin, Packet,
PixelGrid,
bitvec::prelude::BitVec, command::TryFromPacketError,
command_code::CommandCode, origin::Pixels, Brightness, ByteGrid,
Command, CompressionCode, Header, Origin, Packet, PixelGrid,
};
fn round_trip(original: Command) {
@ -501,12 +479,15 @@ mod tests {
#[test]
fn round_trip_char_brightness() {
round_trip(Command::CharBrightness(Origin(5, 2), ByteGrid::new(7, 5)));
round_trip(Command::CharBrightness(
Origin::new(5, 2),
ByteGrid::new(7, 5),
));
}
#[test]
fn round_trip_cp437_data() {
round_trip(Command::Cp437Data(Origin(5, 2), ByteGrid::new(7, 5)));
round_trip(Command::Cp437Data(Origin::new(5, 2), ByteGrid::new(7, 5)));
}
#[test]
@ -533,7 +514,7 @@ mod tests {
compression,
));
round_trip(Command::BitmapLinearWin(
Origin(0, 0),
Origin::new(0, 0),
PixelGrid::max_sized(),
compression,
));
@ -619,7 +600,7 @@ mod tests {
fn error_decompression_failed_win() {
for compression in all_compressions().to_owned() {
let p: Packet = Command::BitmapLinearWin(
Origin(16, 8),
Origin::new(16, 8),
PixelGrid::new(8, 8),
compression,
)
@ -743,6 +724,9 @@ mod tests {
#[test]
fn origin_add() {
assert_eq!(Origin(4, 2), Origin(1, 0) + Origin(3, 2));
assert_eq!(
Origin::<Pixels>::new(4, 2),
Origin::new(1, 0) + Origin::new(3, 2)
);
}
}

View file

@ -46,20 +46,27 @@ impl Connection {
/// # Examples
///
/// ```rust
/// use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
/// let connection = servicepoint::Connection::open("172.23.42.29:2342")
/// .expect("connection failed");
/// # use servicepoint::{Command, CompressionCode, Grid, PixelGrid};
/// # let connection = servicepoint::Connection::open("172.23.42.29:2342")
/// # .expect("connection failed");
///
/// // turn off all pixels
/// // turn off all pixels on display
/// connection.send(Command::Clear)
/// .expect("send failed");
///
/// // turn on all pixels
/// // turn on all pixels in a grid
/// let mut pixels = PixelGrid::max_sized();
/// pixels.fill(true);
///
/// // send pixels to display
/// connection.send(Command::BitmapLinearWin(servicepoint::Origin(0, 0), pixels, CompressionCode::Uncompressed))
/// // create command to send pixels
/// let command = Command::BitmapLinearWin(
/// servicepoint::Origin::new(0, 0),
/// pixels,
/// CompressionCode::Uncompressed
/// );
///
/// // send command to display
/// connection.send(command)
/// .expect("send failed");
/// ```
pub fn send(

View file

@ -7,11 +7,12 @@ use bitvec::prelude::{BitVec, Msb0};
pub use crate::brightness::Brightness;
pub use crate::byte_grid::ByteGrid;
pub use crate::command::{Command, Offset, Origin};
pub use crate::command::{Command, Offset};
pub use crate::compression_code::CompressionCode;
pub use crate::connection::Connection;
pub use crate::data_ref::DataRef;
pub use crate::grid::Grid;
pub use crate::origin::{Origin, Pixels, Tiles};
pub use crate::packet::{Header, Packet, Payload};
pub use crate::pixel_grid::PixelGrid;
@ -26,6 +27,7 @@ mod compression_code;
mod connection;
mod data_ref;
mod grid;
mod origin;
mod packet;
mod pixel_grid;

View file

@ -0,0 +1,48 @@
use std::marker::PhantomData;
/// An origin marks the top left position of a window sent to the display.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Origin<Unit: DisplayUnit> {
/// position in the width direction
pub x: usize,
/// position in the height direction
pub y: usize,
phantom_data: PhantomData<Unit>,
}
impl<Unit: DisplayUnit> Origin<Unit> {
/// Create a new `Origin` instance for the provided position.
pub fn new(x: usize, y: usize) -> Self {
Self {
x,
y,
phantom_data: PhantomData::default(),
}
}
}
impl<T: DisplayUnit> std::ops::Add<Origin<T>> for Origin<T> {
type Output = Origin<T>;
fn add(self, rhs: Origin<T>) -> Self::Output {
Origin {
x: self.x + rhs.x,
y: self.y + rhs.y,
phantom_data: PhantomData::default(),
}
}
}
pub trait DisplayUnit {}
/// Marks something to be measured in number of pixels.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Pixels();
/// Marks something to be measured in number of iles.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Tiles();
impl DisplayUnit for Pixels {}
impl DisplayUnit for Tiles {}

View file

@ -105,9 +105,9 @@ pub unsafe extern "C" fn sp_command_fade_out() -> *mut Command {
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
/// by explicitly calling `sp_command_dealloc`.
#[no_mangle]
pub unsafe extern "C" fn sp_command_brightness(
brightness: Brightness,
) -> *mut Command {
pub unsafe extern "C" fn sp_command_brightness(brightness: u8) -> *mut Command {
let brightness =
Brightness::try_from(brightness).expect("invalid brightness");
Box::into_raw(Box::new(Command::Brightness(brightness)))
}
@ -129,7 +129,10 @@ pub unsafe extern "C" fn sp_command_char_brightness(
byte_grid: *mut ByteGrid,
) -> *mut Command {
let byte_grid = *Box::from_raw(byte_grid);
Box::into_raw(Box::new(Command::CharBrightness(Origin(x, y), byte_grid)))
Box::into_raw(Box::new(Command::CharBrightness(
Origin::new(x, y),
byte_grid,
)))
}
/// Allocates a new `Command::BitmapLinear` instance.
@ -254,7 +257,7 @@ pub unsafe extern "C" fn sp_command_cp437_data(
byte_grid: *mut ByteGrid,
) -> *mut Command {
let byte_grid = *Box::from_raw(byte_grid);
Box::into_raw(Box::new(Command::Cp437Data(Origin(x, y), byte_grid)))
Box::into_raw(Box::new(Command::Cp437Data(Origin::new(x, y), byte_grid)))
}
/// Allocates a new `Command::BitmapLinearWin` instance.
@ -278,7 +281,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_win(
) -> *mut Command {
let byte_grid = *Box::from_raw(pixel_grid);
Box::into_raw(Box::new(Command::BitmapLinearWin(
Origin(x, y),
Origin::new(x, y),
byte_grid,
compression_code,
)))

View file

@ -121,7 +121,7 @@ namespace ServicePoint.BindGen
[DllImport(__DllName, EntryPoint = "sp_command_fade_out", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_fade_out();
/// <summary>Allocates a new `Command::Brightness` instance. # Safety The caller has to make sure that: - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
/// <summary>Allocates a new `Command::Brightness` instance for setting the brightness of all tiles to the same value. # Panics - When the provided brightness value is out of range (0-11). # Safety The caller has to make sure that: - the returned `Command` instance is freed in some way, either by using a consuming function or by explicitly calling `sp_command_dealloc`.</summary>
[DllImport(__DllName, EntryPoint = "sp_command_brightness", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_brightness(byte brightness);
@ -262,17 +262,17 @@ namespace ServicePoint.BindGen
public enum Command
{
Clear,
HardReset,
FadeOut,
CharBrightness,
Cp437Data,
BitmapLinearWin,
Brightness,
BitmapLegacy,
CharBrightness,
BitmapLinear,
BitmapLinearAnd,
BitmapLinearOr,
BitmapLinearXor,
Cp437Data,
BitmapLinearWin,
HardReset,
FadeOut,
BitmapLegacy,
}
public enum CompressionCode : ushort