named fields instead of tuple for Packet, doc adjustments

This commit is contained in:
Vinzenz Schroeter 2024-09-07 11:44:42 +02:00
parent e54891e662
commit e97418b51b
5 changed files with 529 additions and 135 deletions

View file

@ -190,10 +190,17 @@ impl TryFrom<Packet> for Command {
/// Try to interpret the `Packet` as one containing a `Command`
fn try_from(packet: Packet) -> Result<Self, Self::Error> {
let Packet(Header(command_u16, a, _, _, _), _) = packet;
let command_code = match CommandCode::try_from(command_u16) {
let Packet {
header: Header {
command_code,
a,
..
},
..
} = packet;
let command_code = match CommandCode::try_from(command_code) {
Err(()) => {
return Err(TryFromPacketError::InvalidCommand(command_u16));
return Err(TryFromPacketError::InvalidCommand(command_code));
}
Ok(value) => value,
};
@ -266,8 +273,16 @@ impl Command {
packet: Packet,
compression: CompressionCode,
) -> Result<Command, TryFromPacketError> {
let Packet(Header(_, tiles_x, pixels_y, tile_w, pixel_h), payload) =
packet;
let Packet {
header: Header {
command_code: _,
a: tiles_x,
b: pixels_y,
c: tile_w,
d: pixel_h,
},
payload,
} = packet;
let payload = match into_decompressed(compression, payload) {
None => return Err(TryFromPacketError::DecompressionFailed),
@ -290,7 +305,16 @@ impl Command {
packet: Packet,
command: Command,
) -> Result<Command, TryFromPacketError> {
let Packet(Header(_, a, b, c, d), payload) = packet;
let Packet {
header: Header {
command_code: _,
a,
b,
c,
d,
},
payload,
} = packet;
if !payload.is_empty() {
Err(TryFromPacketError::UnexpectedPayloadSize(0, payload.len()))
} else if a != 0 || b != 0 || c != 0 || d != 0 {
@ -304,7 +328,15 @@ impl Command {
fn packet_into_linear_bitmap(
packet: Packet,
) -> Result<(SpBitVec, CompressionCode), TryFromPacketError> {
let Packet(Header(_, _, length, sub, reserved), payload) = packet;
let Packet {
header: Header {
b: length,
c: sub,
d: reserved,
..
},
payload,
} = packet;
if reserved != 0 {
return Err(TryFromPacketError::ExtraneousHeaderValues);
}
@ -330,7 +362,16 @@ impl Command {
fn packet_into_char_brightness(
packet: &Packet,
) -> Result<Command, TryFromPacketError> {
let Packet(Header(_, x, y, width, height), payload) = packet;
let Packet {
header: Header {
command_code: _,
a: x,
b: y,
c: width,
d: height,
},
payload,
} = packet;
let grid =
PrimitiveGrid::load(*width as usize, *height as usize, payload);
@ -348,7 +389,16 @@ impl Command {
fn packet_into_brightness(
packet: &Packet,
) -> Result<Command, TryFromPacketError> {
let Packet(Header(_, a, b, c, d), payload) = packet;
let Packet {
header: Header {
command_code: _,
a,
b,
c,
d,
},
payload,
} = packet;
if payload.len() != 1 {
return Err(TryFromPacketError::UnexpectedPayloadSize(
1,
@ -369,7 +419,16 @@ impl Command {
fn packet_into_cp437(
packet: &Packet,
) -> Result<Command, TryFromPacketError> {
let Packet(Header(_, a, b, c, d), payload) = packet;
let Packet {
header: Header {
command_code: _,
a,
b,
c,
d,
},
payload,
} = packet;
Ok(Command::Cp437Data(
Origin::new(*a as usize, *b as usize),
Cp437Grid::load(*c as usize, *d as usize, payload),
@ -483,7 +542,16 @@ mod tests {
#[test]
fn error_invalid_command() {
let p = Packet(Header(0xFF, 0x00, 0x00, 0x00, 0x00), vec![]);
let p = Packet {
header: Header {
command_code: 0xFF,
a: 0x00,
b: 0x00,
c: 0x00,
d: 0x00,
},
payload: vec![],
};
let result = Command::try_from(p);
assert!(matches!(
result,
@ -493,10 +561,16 @@ mod tests {
#[test]
fn error_extraneous_header_values_clear() {
let p = Packet(
Header(CommandCode::Clear.into(), 0x05, 0x00, 0x00, 0x00),
vec![],
);
let p = Packet {
header: Header {
command_code: CommandCode::Clear.into(),
a: 0x05,
b: 0x00,
c: 0x00,
d: 0x00,
},
payload: vec![],
};
let result = Command::try_from(p);
assert!(matches!(
result,
@ -506,10 +580,16 @@ mod tests {
#[test]
fn error_extraneous_header_values_brightness() {
let p = Packet(
Header(CommandCode::Brightness.into(), 0x00, 0x13, 0x37, 0x00),
vec![5],
);
let p = Packet {
header: Header {
command_code: CommandCode::Brightness.into(),
a: 0x00,
b: 0x13,
c: 0x37,
d: 0x00,
},
payload: vec![5],
};
let result = Command::try_from(p);
assert!(matches!(
result,
@ -519,10 +599,16 @@ mod tests {
#[test]
fn error_extraneous_header_hard_reset() {
let p = Packet(
Header(CommandCode::HardReset.into(), 0x00, 0x00, 0x00, 0x01),
vec![],
);
let p = Packet {
header: Header {
command_code: CommandCode::HardReset.into(),
a: 0x00,
b: 0x00,
c: 0x00,
d: 0x01,
},
payload: vec![],
};
let result = Command::try_from(p);
assert!(matches!(
result,
@ -532,10 +618,16 @@ mod tests {
#[test]
fn error_extraneous_header_fade_out() {
let p = Packet(
Header(CommandCode::FadeOut.into(), 0x10, 0x00, 0x00, 0x01),
vec![],
);
let p = Packet {
header: Header {
command_code: CommandCode::FadeOut.into(),
a: 0x10,
b: 0x00,
c: 0x00,
d: 0x01,
},
payload: vec![],
};
let result = Command::try_from(p);
assert!(matches!(
result,
@ -545,10 +637,16 @@ mod tests {
#[test]
fn error_unexpected_payload() {
let p = Packet(
Header(CommandCode::FadeOut.into(), 0x00, 0x00, 0x00, 0x00),
vec![5, 7],
);
let p = Packet {
header: Header {
command_code: CommandCode::FadeOut.into(),
a: 0x00,
b: 0x00,
c: 0x00,
d: 0x00,
},
payload: vec![5, 7],
};
let result = Command::try_from(p);
assert!(matches!(
result,
@ -564,15 +662,19 @@ mod tests {
PixelGrid::new(8, 8),
compression,
)
.into();
let Packet(header, mut payload) = p;
.into();
let Packet {
header,
mut payload,
} = p;
// mangle it
for byte in payload.iter_mut() {
*byte -= *byte / 2;
}
let p = Packet(header, payload);
let p = Packet { header, payload };
let result = Command::try_from(p);
if compression != CompressionCode::Uncompressed {
assert_eq!(result, Err(TryFromPacketError::DecompressionFailed))
@ -590,15 +692,18 @@ mod tests {
BitVec::repeat(false, 8),
compression,
)
.into();
let Packet(header, mut payload) = p;
.into();
let Packet {
header,
mut payload,
} = p;
// mangle it
for byte in payload.iter_mut() {
*byte -= *byte / 2;
}
let p = Packet(header, payload);
let p = Packet { header, payload };
let result = Command::try_from(p);
if compression != CompressionCode::Uncompressed {
assert_eq!(result, Err(TryFromPacketError::DecompressionFailed))
@ -612,32 +717,59 @@ mod tests {
#[test]
fn unexpected_payload_size_brightness() {
assert_eq!(
Command::try_from(Packet(
Header(CommandCode::Brightness.into(), 0, 0, 0, 0),
vec!(),
)),
Command::try_from(Packet {
header: Header {
command_code: CommandCode::Brightness.into(),
a: 0,
b: 0,
c: 0,
d: 0,
},
payload: vec!()
}),
Err(TryFromPacketError::UnexpectedPayloadSize(1, 0))
);
assert_eq!(
Command::try_from(Packet(
Header(CommandCode::Brightness.into(), 0, 0, 0, 0),
vec!(0, 0),
)),
Command::try_from(Packet {
header: Header {
command_code: CommandCode::Brightness.into(),
a: 0,
b: 0,
c: 0,
d: 0,
},
payload: vec!(0, 0)
}),
Err(TryFromPacketError::UnexpectedPayloadSize(1, 2))
);
}
#[test]
fn error_reserved_used() {
let Packet(header, payload) = Command::BitmapLinear(
let Packet { header, payload } = Command::BitmapLinear(
0,
BitVec::repeat(false, 8),
CompressionCode::Uncompressed,
)
.into();
let Header(command, offset, length, sub, _reserved) = header;
let p = Packet(Header(command, offset, length, sub, 69), payload);
.into();
let Header {
command_code: command,
a: offset,
b: length,
c: sub,
d: _reserved,
} = header;
let p = Packet {
header: Header {
command_code: command,
a: offset,
b: length,
c: sub,
d: 69,
},
payload,
};
assert_eq!(
Command::try_from(p),
Err(TryFromPacketError::ExtraneousHeaderValues)
@ -646,14 +778,29 @@ mod tests {
#[test]
fn error_invalid_compression() {
let Packet(header, payload) = Command::BitmapLinear(
let Packet { header, payload } = Command::BitmapLinear(
0,
BitVec::repeat(false, 8),
CompressionCode::Uncompressed,
)
.into();
let Header(command, offset, length, _sub, reserved) = header;
let p = Packet(Header(command, offset, length, 42, reserved), payload);
.into();
let Header {
command_code: command,
a: offset,
b: length,
c: _sub,
d: reserved,
} = header;
let p = Packet {
header: Header {
command_code: command,
a: offset,
b: length,
c: 42,
d: reserved,
},
payload,
};
assert_eq!(
Command::try_from(p),
Err(TryFromPacketError::InvalidCompressionCode(42))
@ -662,17 +809,29 @@ mod tests {
#[test]
fn error_unexpected_size() {
let Packet(header, payload) = Command::BitmapLinear(
let Packet { header, payload } = Command::BitmapLinear(
0,
BitVec::repeat(false, 8),
CompressionCode::Uncompressed,
)
.into();
let Header(command, offset, length, compression, reserved) = header;
let p = Packet(
Header(command, offset, 420, compression, reserved),
.into();
let Header {
command_code: command,
a: offset,
b: length,
c: compression,
d: reserved,
} = header;
let p = Packet {
header: Header {
command_code: command,
a: offset,
b: 420,
c: compression,
d: reserved,
},
payload,
);
};
assert_eq!(
Command::try_from(p),
Err(TryFromPacketError::UnexpectedPayloadSize(

View file

@ -71,7 +71,7 @@ impl Connection {
Connection::Udp(socket) => {
socket
.send(&data)
.map_err(move |io_err| SendError::IoError(io_err))
.map_err(SendError::IoError)
.map(move |_| ()) // ignore Ok value
}
Connection::Fake => Ok(()),

View file

@ -3,25 +3,84 @@ use std::mem::size_of;
use crate::command_code::CommandCode;
use crate::compression::into_compressed;
use crate::{
Command, CompressionCode, Grid, Offset, Origin, PixelGrid, Pixels,
Command, CompressionCode, Grid, Offset, Origin, PixelGrid, Pixels, Tiles,
TILE_SIZE,
};
/// A raw header. Should probably not be used directly.
/// A raw header.
///
/// The header specifies the kind of command, the size of the payload and where to display the
/// payload, where applicable.
///
/// Because the meaning of most fields depend on the command, there are no speaking names for them.
///
/// Should probably only be used directly to use features not exposed by the library.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Header(pub u16, pub u16, pub u16, pub u16, pub u16);
pub struct Header {
/// The first two bytes specify which command this packet represents.
pub command_code: u16,
/// First command-specific value
pub a: u16,
/// Second command-specific value
pub b: u16,
/// Third command-specific value
pub c: u16,
/// Fourth command-specific value
pub d: u16,
}
/// The raw payload. Should probably not be used directly.
/// The raw payload.
///
/// Should probably only be used directly to use features not exposed by the library.
pub type Payload = Vec<u8>;
/// The raw packet. Should probably not be used directly.
/// The raw packet.
///
/// Contents should probably only be used directly to use features not exposed by the library.
///
/// # Examples
///
/// Converting a packet to a command and back:
///
/// ```rust
/// # use servicepoint::{Command, Packet};
/// # let command = Command::Clear;
/// let packet: Packet = command.into();
/// let command: Command = Command::try_from(packet).expect("could not read packet");
/// ```
///
/// Converting a packet to bytes and back:
///
/// ```rust
/// # use servicepoint::{Command, Packet};
/// # let command = Command::Clear;
/// # let packet: Packet = command.into();
/// let bytes: Vec<u8> = packet.into();
/// let packet = Packet::try_from(bytes).expect("could not read packet from bytes");
/// ```
///
#[derive(Clone, Debug, PartialEq)]
pub struct Packet(pub Header, pub Payload);
pub struct Packet {
/// Meta-information for the packed command
pub header: Header,
/// The data for the packed command
pub payload: Payload,
}
impl From<Packet> for Vec<u8> {
/// Turn the packet into raw bytes ready to send
fn from(value: Packet) -> Self {
let Packet(Header(mode, a, b, c, d), payload) = value;
let Packet {
header:
Header {
command_code: mode,
a,
b,
c,
d,
},
payload,
} = value;
let mut packet = vec![0u8; 10 + payload.len()];
packet[0..=1].copy_from_slice(&u16::to_be_bytes(mode));
@ -36,13 +95,6 @@ impl From<Packet> for Vec<u8> {
}
}
fn u16_from_be_slice(slice: &[u8]) -> u16 {
let mut bytes = [0u8; 2];
bytes[0] = slice[0];
bytes[1] = slice[1];
u16::from_be_bytes(bytes)
}
impl TryFrom<&[u8]> for Packet {
type Error = ();
@ -54,14 +106,31 @@ impl TryFrom<&[u8]> for Packet {
return Err(());
}
let mode = u16_from_be_slice(&value[0..=1]);
let a = u16_from_be_slice(&value[2..=3]);
let b = u16_from_be_slice(&value[4..=5]);
let c = u16_from_be_slice(&value[6..=7]);
let d = u16_from_be_slice(&value[8..=9]);
let header = {
let command_code = Self::u16_from_be_slice(&value[0..=1]);
let a = Self::u16_from_be_slice(&value[2..=3]);
let b = Self::u16_from_be_slice(&value[4..=5]);
let c = Self::u16_from_be_slice(&value[6..=7]);
let d = Self::u16_from_be_slice(&value[8..=9]);
Header {
command_code,
a,
b,
c,
d,
}
};
let payload = value[10..].to_vec();
Ok(Packet(Header(mode, a, b, c, d), payload))
Ok(Packet { header, payload })
}
}
impl TryFrom<Vec<u8>> for Packet {
type Error = ();
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(value.as_slice())
}
}
@ -79,26 +148,23 @@ impl From<Command> for Packet {
Command::BitmapLegacy => {
Self::command_code_only(CommandCode::BitmapLegacy)
}
Command::CharBrightness(origin, grid) => Packet(
Header(
CommandCode::CharBrightness.into(),
origin.x as u16,
origin.y as u16,
grid.width() as u16,
grid.height() as u16,
),
grid.into(),
),
Command::Brightness(brightness) => Packet(
Header(
CommandCode::Brightness.into(),
0x00000,
0x0000,
0x0000,
0x0000,
),
vec![brightness.into()],
),
Command::CharBrightness(origin, grid) => {
Self::origin_grid_to_packet(
origin,
grid,
CommandCode::CharBrightness,
)
}
Command::Brightness(brightness) => Packet {
header: Header {
command_code: CommandCode::Brightness.into(),
a: 0x00000,
b: 0x0000,
c: 0x0000,
d: 0x0000,
},
payload: vec![brightness.into()],
},
Command::BitmapLinearWin(origin, pixels, compression) => {
Self::bitmap_win_into_packet(origin, pixels, compression)
}
@ -134,15 +200,10 @@ impl From<Command> for Packet {
bits.into(),
)
}
Command::Cp437Data(origin, grid) => Packet(
Header(
CommandCode::Cp437Data.into(),
origin.x as u16,
origin.y as u16,
grid.width() as u16,
grid.height() as u16,
),
grid.into(),
Command::Cp437Data(origin, grid) => Self::origin_grid_to_packet(
origin,
grid,
CommandCode::Cp437Data,
),
}
}
@ -159,16 +220,16 @@ impl Packet {
) -> Packet {
let length = payload.len() as u16;
let payload = into_compressed(compression, payload);
Packet(
Header(
command.into(),
offset as u16,
length,
compression.into(),
0,
),
Packet {
header: Header {
command_code: command.into(),
a: offset as u16,
b: length,
c: compression.into(),
d: 0,
},
payload,
)
}
}
#[allow(clippy::cast_possible_truncation)]
@ -198,15 +259,54 @@ impl Packet {
CompressionCode::Zstd => CommandCode::BitmapLinearWinZstd,
};
Packet(
Header(command.into(), tile_x, origin.y as u16, tile_w, pixel_h),
Packet {
header: Header {
command_code: command.into(),
a: tile_x,
b: origin.y as u16,
c: tile_w,
d: pixel_h,
},
payload,
)
}
}
/// Helper method for creating empty packets only containing the command code
fn command_code_only(code: CommandCode) -> Packet {
Packet(Header(code.into(), 0x0000, 0x0000, 0x0000, 0x0000), vec![])
Packet {
header: Header {
command_code: code.into(),
a: 0x0000,
b: 0x0000,
c: 0x0000,
d: 0x0000,
},
payload: vec![],
}
}
fn u16_from_be_slice(slice: &[u8]) -> u16 {
let mut bytes = [0u8; 2];
bytes[0] = slice[0];
bytes[1] = slice[1];
u16::from_be_bytes(bytes)
}
fn origin_grid_to_packet<T>(
origin: Origin<Tiles>,
grid: impl Grid<T> + Into<Payload>,
command_code: CommandCode,
) -> Packet {
Packet {
header: Header {
command_code: command_code.into(),
a: origin.x as u16,
b: origin.y as u16,
c: grid.width() as u16,
d: grid.height() as u16,
},
payload: grid.into(),
}
}
}
@ -216,10 +316,31 @@ mod tests {
#[test]
fn round_trip() {
let p = Packet(Header(0, 1, 2, 3, 4), vec![42u8; 23]);
let p = Packet {
header: Header {
command_code: 0,
a: 1,
b: 2,
c: 3,
d: 4,
},
payload: vec![42u8; 23],
};
let data: Vec<u8> = p.into();
let p = Packet::try_from(&*data).unwrap();
assert_eq!(p, Packet(Header(0, 1, 2, 3, 4), vec![42u8; 23]));
assert_eq!(
p,
Packet {
header: Header {
command_code: 0,
a: 1,
b: 2,
c: 3,
d: 4
},
payload: vec![42u8; 23]
}
);
}
#[test]

View file

@ -105,7 +105,7 @@ typedef struct SPBrightnessGrid SPBrightnessGrid;
*
* This struct and associated functions implement the UDP protocol for the display.
*
* To send a `CCommand`, use a `CConnection`.
* To send a `SPCommand`, use a `SPConnection`.
*
* # Examples
*
@ -539,6 +539,13 @@ size_t sp_brightness_grid_width(const struct SPBrightnessGrid *this_);
* Allocates a new `Command::BitmapLinear` instance.
* The passed `BitVec` gets consumed.
*
* Set pixel data starting at the pixel offset on screen.
*
* The screen will continuously overwrite more pixel data without regarding the offset, meaning
* once the starting row is full, overwriting will continue on column 0.
*
* The contained `BitVec` is always uncompressed.
*
* # Safety
*
* The caller has to make sure that:
@ -557,6 +564,13 @@ struct SPCommand *sp_command_bitmap_linear(SPOffset offset,
* Allocates a new `Command::BitmapLinearAnd` instance.
* The passed `BitVec` gets consumed.
*
* Set pixel data according to an and-mask starting at the offset.
*
* The screen will continuously overwrite more pixel data without regarding the offset, meaning
* once the starting row is full, overwriting will continue on column 0.
*
* The contained `BitVec` is always uncompressed.
*
* # Safety
*
* The caller has to make sure that:
@ -575,6 +589,13 @@ struct SPCommand *sp_command_bitmap_linear_and(SPOffset offset,
* Allocates a new `Command::BitmapLinearOr` instance.
* The passed `BitVec` gets consumed.
*
* Set pixel data according to an or-mask starting at the offset.
*
* The screen will continuously overwrite more pixel data without regarding the offset, meaning
* once the starting row is full, overwriting will continue on column 0.
*
* The contained `BitVec` is always uncompressed.
*
* # Safety
*
* The caller has to make sure that:
@ -593,6 +614,8 @@ struct SPCommand *sp_command_bitmap_linear_or(SPOffset offset,
* Allocates a new `Command::BitmapLinearWin` instance.
* The passed `PixelGrid` gets consumed.
*
* Sets a window of pixels to the specified values
*
* # Safety
*
* The caller has to make sure that:
@ -612,6 +635,13 @@ struct SPCommand *sp_command_bitmap_linear_win(size_t x,
* Allocates a new `Command::BitmapLinearXor` instance.
* The passed `BitVec` gets consumed.
*
* Set pixel data according to a xor-mask starting at the offset.
*
* The screen will continuously overwrite more pixel data without regarding the offset, meaning
* once the starting row is full, overwriting will continue on column 0.
*
* The contained `BitVec` is always uncompressed.
*
* # Safety
*
* The caller has to make sure that:
@ -647,6 +677,8 @@ struct SPCommand *sp_command_brightness(uint8_t brightness);
* Allocates a new `Command::CharBrightness` instance.
* The passed `SPBrightnessGrid` gets consumed.
*
* Set the brightness of individual tiles in a rectangular area of the display.
*
* # Safety
*
* The caller has to make sure that:
@ -663,6 +695,14 @@ struct SPCommand *sp_command_char_brightness(size_t x,
/**
* Allocates a new `Command::Clear` instance.
*
* Set all pixels to the off state. Does not affect brightness.
*
* # Examples
*
* ```C
* sp_connection_send(connection, sp_command_clear());
* ```
*
* # Safety
*
* The caller has to make sure that:
@ -673,7 +713,7 @@ struct SPCommand *sp_command_char_brightness(size_t x,
struct SPCommand *sp_command_clear(void);
/**
* Clones a `Command` instance.
* Clones a `SPCommand` instance.
*
* # Safety
*
@ -690,6 +730,13 @@ struct SPCommand *sp_command_clone(const struct SPCommand *original);
* Allocates a new `Command::Cp437Data` instance.
* The passed `ByteGrid` gets consumed.
*
* Show text on the screen.
*
* <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>
*
* # Safety
*
* The caller has to make sure that:
@ -706,6 +753,13 @@ struct SPCommand *sp_command_cp437_data(size_t x,
/**
* Deallocates a `Command`.
*
* # Examples
*
* ```C
* SPCommand c = sp_command_clear();
* sp_command_dealloc(c);
* ```
*
* # Safety
*
* The caller has to make sure that:
@ -731,6 +785,9 @@ struct SPCommand *sp_command_fade_out(void);
/**
* Allocates a new `Command::HardReset` instance.
*
* Kills the udp daemon on the display, which usually results in a restart.
* Please do not send this in your normal program flow.
*
* # Safety
*
* The caller has to make sure that:
@ -741,18 +798,18 @@ struct SPCommand *sp_command_fade_out(void);
struct SPCommand *sp_command_hard_reset(void);
/**
* Tries to turn a `Packet` into a `Command`. The packet is deallocated in the process.
* Tries to turn a `SPPacket` into a `SPCommand`. The packet is deallocated in the process.
*
* Returns: pointer to new `Command` instance or NULL
* Returns: pointer to new `SPCommand` instance or NULL
*
* # Safety
*
* The caller has to make sure that:
*
* - `packet` points to a valid instance of `Packet`
* - `packet` points to a valid instance of `SPPacket`
* - `packet` is not used concurrently or after this call
* - the result is checked for NULL
* - the returned `Command` instance is freed in some way, either by using a consuming function or
* - the returned `SPCommand` instance is freed in some way, either by using a consuming function or
* by explicitly calling `sp_command_dealloc`.
*/
struct SPCommand *sp_command_try_from_packet(struct SPPacket *packet);

View file

@ -546,25 +546,25 @@ namespace ServicePoint.BindGen
public static extern ByteSlice sp_cp437_grid_unsafe_data_ref(Cp437Grid* @this);
/// <summary>
/// Tries to turn a `Packet` into a `Command`. The packet is deallocated in the process.
/// Tries to turn a `SPPacket` into a `SPCommand`. The packet is deallocated in the process.
///
/// Returns: pointer to new `Command` instance or NULL
/// Returns: pointer to new `SPCommand` instance or NULL
///
/// # Safety
///
/// The caller has to make sure that:
///
/// - `packet` points to a valid instance of `Packet`
/// - `packet` points to a valid instance of `SPPacket`
/// - `packet` is not used concurrently or after this call
/// - the result is checked for NULL
/// - the returned `Command` instance is freed in some way, either by using a consuming function or
/// - the returned `SPCommand` 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_try_from_packet", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
public static extern Command* sp_command_try_from_packet(Packet* packet);
/// <summary>
/// Clones a `Command` instance.
/// Clones a `SPCommand` instance.
///
/// # Safety
///
@ -581,6 +581,14 @@ namespace ServicePoint.BindGen
/// <summary>
/// Allocates a new `Command::Clear` instance.
///
/// Set all pixels to the off state. Does not affect brightness.
///
/// # Examples
///
/// ```C
/// sp_connection_send(connection, sp_command_clear());
/// ```
///
/// # Safety
///
/// The caller has to make sure that:
@ -594,6 +602,9 @@ namespace ServicePoint.BindGen
/// <summary>
/// Allocates a new `Command::HardReset` instance.
///
/// Kills the udp daemon on the display, which usually results in a restart.
/// Please do not send this in your normal program flow.
///
/// # Safety
///
/// The caller has to make sure that:
@ -639,6 +650,8 @@ namespace ServicePoint.BindGen
/// Allocates a new `Command::CharBrightness` instance.
/// The passed `SPBrightnessGrid` gets consumed.
///
/// Set the brightness of individual tiles in a rectangular area of the display.
///
/// # Safety
///
/// The caller has to make sure that:
@ -655,6 +668,13 @@ namespace ServicePoint.BindGen
/// Allocates a new `Command::BitmapLinear` instance.
/// The passed `BitVec` gets consumed.
///
/// Set pixel data starting at the pixel offset on screen.
///
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
/// once the starting row is full, overwriting will continue on column 0.
///
/// The contained `BitVec` is always uncompressed.
///
/// # Safety
///
/// The caller has to make sure that:
@ -672,6 +692,13 @@ namespace ServicePoint.BindGen
/// Allocates a new `Command::BitmapLinearAnd` instance.
/// The passed `BitVec` gets consumed.
///
/// Set pixel data according to an and-mask starting at the offset.
///
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
/// once the starting row is full, overwriting will continue on column 0.
///
/// The contained `BitVec` is always uncompressed.
///
/// # Safety
///
/// The caller has to make sure that:
@ -689,6 +716,13 @@ namespace ServicePoint.BindGen
/// Allocates a new `Command::BitmapLinearOr` instance.
/// The passed `BitVec` gets consumed.
///
/// Set pixel data according to an or-mask starting at the offset.
///
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
/// once the starting row is full, overwriting will continue on column 0.
///
/// The contained `BitVec` is always uncompressed.
///
/// # Safety
///
/// The caller has to make sure that:
@ -706,6 +740,13 @@ namespace ServicePoint.BindGen
/// Allocates a new `Command::BitmapLinearXor` instance.
/// The passed `BitVec` gets consumed.
///
/// Set pixel data according to a xor-mask starting at the offset.
///
/// The screen will continuously overwrite more pixel data without regarding the offset, meaning
/// once the starting row is full, overwriting will continue on column 0.
///
/// The contained `BitVec` is always uncompressed.
///
/// # Safety
///
/// The caller has to make sure that:
@ -723,6 +764,13 @@ namespace ServicePoint.BindGen
/// Allocates a new `Command::Cp437Data` instance.
/// The passed `ByteGrid` gets consumed.
///
/// Show text on the screen.
///
/// &lt;div class="warning"&gt;
/// 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.
/// &lt;/div&gt;
///
/// # Safety
///
/// The caller has to make sure that:
@ -739,6 +787,8 @@ namespace ServicePoint.BindGen
/// Allocates a new `Command::BitmapLinearWin` instance.
/// The passed `PixelGrid` gets consumed.
///
/// Sets a window of pixels to the specified values
///
/// # Safety
///
/// The caller has to make sure that:
@ -755,6 +805,13 @@ namespace ServicePoint.BindGen
/// <summary>
/// Deallocates a `Command`.
///
/// # Examples
///
/// ```C
/// SPCommand c = sp_command_clear();
/// sp_command_dealloc(c);
/// ```
///
/// # Safety
///
/// The caller has to make sure that: