servicepoint/src/commands/char_grid.rs
Vinzenz Schroeter de8a1a2fe8
All checks were successful
Rust / build (pull_request) Successful in 2m6s
remove connections
2025-05-01 19:43:32 +02:00

148 lines
3.9 KiB
Rust

use crate::{
command_code::CommandCode, commands::check_command_code,
commands::errors::TryFromPacketError, CharGrid, Header, Origin, Packet,
Tiles, TryIntoPacketError, TypedCommand,
};
/// 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::*;
/// # let connection = FakeConnection;
/// let grid = CharGrid::from("Hello,\nWorld!");
/// connection.send_command(CharGridCommand { origin: Origin::ZERO, grid }).expect("send failed");
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CharGridCommand {
/// the text to send to the display
pub grid: CharGrid,
/// which tile the text should start on
pub origin: Origin<Tiles>,
}
impl TryFrom<CharGridCommand> for Packet {
type Error = TryIntoPacketError;
fn try_from(value: CharGridCommand) -> Result<Self, Self::Error> {
Ok(Packet::origin_grid_to_packet(
value.origin,
value.grid,
CommandCode::Utf8Data,
)?)
}
}
impl TryFrom<Packet> for CharGridCommand {
type Error = TryFromPacketError;
fn try_from(packet: Packet) -> Result<Self, Self::Error> {
let Packet {
header:
Header {
command_code,
a: origin_x,
b: origin_y,
c: width,
d: height,
},
payload,
} = packet;
check_command_code(command_code, CommandCode::Utf8Data)?;
let payload: Vec<_> =
String::from_utf8(payload.clone())?.chars().collect();
let expected = width as usize * height as usize;
if payload.len() != expected {
return Err(TryFromPacketError::UnexpectedPayloadSize {
expected,
actual: payload.len(),
});
}
Ok(Self {
origin: Origin::new(origin_x as usize, origin_y as usize),
grid: CharGrid::from_raw_parts_unchecked(
width as usize,
height as usize,
payload,
),
})
}
}
impl From<CharGridCommand> for TypedCommand {
fn from(command: CharGridCommand) -> Self {
Self::CharGrid(command)
}
}
impl From<CharGrid> for CharGridCommand {
fn from(grid: CharGrid) -> Self {
Self {
grid,
origin: Origin::default(),
}
}
}
#[cfg(test)]
mod tests {
use crate::{
commands::tests::{round_trip, TestImplementsCommand},
CharGrid, CharGridCommand, Origin, Packet, TryFromPacketError,
};
impl TestImplementsCommand for CharGridCommand {}
#[test]
fn round_trip_utf8_data() {
round_trip(
CharGridCommand {
origin: Origin::new(5, 2),
grid: CharGrid::new(7, 5),
}
.into(),
);
}
#[test]
#[cfg(feature = "cp437")]
fn into_command() {
let mut grid = CharGrid::new(2, 3);
grid.iter_mut().enumerate().for_each(|(index, value)| {
*value = crate::cp437::cp437_to_char(index as u8)
});
assert_eq!(
CharGridCommand::from(grid.clone()),
CharGridCommand {
grid,
origin: Origin::default(),
},
)
}
#[test]
fn invalid_size() {
let command: CharGridCommand = CharGrid::new(2, 3).into();
let packet: Packet = command.try_into().unwrap();
let packet = Packet {
header: packet.header,
payload: packet.payload[..5].to_vec(),
};
assert_eq!(
Err(TryFromPacketError::UnexpectedPayloadSize {
actual: 5,
expected: 6
}),
CharGridCommand::try_from(packet)
);
}
}