a bunch of minor changes combined:
- From instead of Into - unsafe_data_ref for other payloads - CByteSlice for returning memory spans - send Packet instead of Into<Packet> - expose packet layer to C/C#
This commit is contained in:
parent
5803b71f3a
commit
1dad113ca1
33 changed files with 462 additions and 733 deletions
|
@ -71,14 +71,17 @@ impl BitVec {
|
|||
self.data.fill(byte);
|
||||
}
|
||||
|
||||
/// Gets the length in bits
|
||||
pub fn len(&self) -> usize {
|
||||
self.data.len() * 8
|
||||
}
|
||||
|
||||
pub fn data_ref(&self) -> &[u8] {
|
||||
&*self.data
|
||||
/// Get the underlying bits in their raw packed bytes form
|
||||
pub fn mut_data_ref(&mut self) -> &mut [u8] {
|
||||
self.data.as_mut_slice()
|
||||
}
|
||||
|
||||
/// Calculates the byte index and bitmask for a specific bit in the vector
|
||||
fn get_indexes(&self, index: usize) -> (usize, u8) {
|
||||
let byte_index = index / 8;
|
||||
let bit_in_byte_index = 7 - index % 8;
|
||||
|
@ -87,13 +90,15 @@ impl BitVec {
|
|||
}
|
||||
}
|
||||
|
||||
impl Into<Vec<u8>> for BitVec {
|
||||
fn into(self) -> Vec<u8> {
|
||||
self.data
|
||||
impl From<BitVec> for Vec<u8> {
|
||||
/// Turns the `BitVec` into the underlying `Vec<u8>`
|
||||
fn from(value: BitVec) -> Self {
|
||||
value.data
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8]> for BitVec {
|
||||
/// Interpret the data as a series of bits and load then into a new `BitVec` instance.
|
||||
fn from(value: &[u8]) -> Self {
|
||||
Self {
|
||||
data: Vec::from(value),
|
||||
|
@ -102,6 +107,7 @@ impl From<&[u8]> for BitVec {
|
|||
}
|
||||
|
||||
impl std::fmt::Debug for BitVec {
|
||||
/// Formats a `BitVec` for debug. The manual implementation includes the length of the instance.
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fmt.debug_struct("BitVec")
|
||||
.field("len", &self.len())
|
||||
|
@ -112,7 +118,7 @@ impl std::fmt::Debug for BitVec {
|
|||
|
||||
#[cfg(feature = "c-api")]
|
||||
pub mod c_api {
|
||||
use crate::BitVec;
|
||||
use crate::{BitVec, CByteSlice};
|
||||
|
||||
/// Creates a new `BitVec` instance.
|
||||
/// The returned instance has to be freed with `bit_vec_dealloc`.
|
||||
|
@ -167,4 +173,22 @@ pub mod c_api {
|
|||
pub unsafe extern "C" fn sp2_bit_vec_len(this: *const BitVec) -> usize {
|
||||
(*this).len()
|
||||
}
|
||||
|
||||
/// Gets an unsafe reference to the data of the `BitVec` instance.
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// The caller has to make sure to never access the returned memory after the `BitVec`
|
||||
/// instance has been consumed or manually deallocated.
|
||||
///
|
||||
/// Reading and writing concurrently to either the original instance or the returned data will
|
||||
/// result in undefined behavior.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp2_bit_vec_unsafe_data_ref(this: *mut BitVec) -> CByteSlice {
|
||||
let data = (*this).mut_data_ref();
|
||||
CByteSlice {
|
||||
start: data.as_mut_ptr_range().start,
|
||||
length: data.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
/// A grid of bytes
|
||||
/// A 2D grid of bytes
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ByteGrid {
|
||||
/// Size in the x-axis
|
||||
pub width: usize,
|
||||
/// Size in the y-axis
|
||||
pub height: usize,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
@ -50,18 +52,24 @@ impl ByteGrid {
|
|||
pub fn fill(&mut self, value: u8) {
|
||||
self.data.fill(value)
|
||||
}
|
||||
|
||||
/// Get the underlying byte rows
|
||||
pub fn mut_data_ref(&mut self) -> &mut [u8] {
|
||||
self.data.as_mut_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Vec<u8>> for ByteGrid {
|
||||
fn into(self) -> Vec<u8> {
|
||||
self.data
|
||||
impl From<ByteGrid> for Vec<u8> {
|
||||
/// Turn into the underlying `Vec<u8>` containing the rows of bytes.
|
||||
fn from(value: ByteGrid) -> Self {
|
||||
value.data
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "c-api")]
|
||||
pub mod c_api
|
||||
{
|
||||
use crate::ByteGrid;
|
||||
use crate::{ByteGrid, CByteSlice};
|
||||
|
||||
/// Creates a new `ByteGrid` instance.
|
||||
/// The returned instance has to be freed with `byte_grid_dealloc`.
|
||||
|
@ -122,4 +130,22 @@ pub mod c_api
|
|||
pub unsafe extern "C" fn sp2_byte_grid_height(this: *const ByteGrid) -> usize {
|
||||
(*this).height
|
||||
}
|
||||
|
||||
/// Gets an unsafe reference to the data of the `ByteGrid` instance.
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// The caller has to make sure to never access the returned memory after the `ByteGrid`
|
||||
/// instance has been consumed or manually deallocated.
|
||||
///
|
||||
/// Reading and writing concurrently to either the original instance or the returned data will
|
||||
/// result in undefined behavior.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp2_byte_grid_unsafe_data_ref(this: *mut ByteGrid) -> CByteSlice {
|
||||
let data = (*this).mut_data_ref();
|
||||
CByteSlice {
|
||||
start: data.as_mut_ptr_range().start,
|
||||
length: data.len(),
|
||||
}
|
||||
}
|
||||
}
|
11
servicepoint2/src/c_slice.rs
Normal file
11
servicepoint2/src/c_slice.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
#[cfg(feature = "c-api")]
|
||||
#[repr(C)]
|
||||
/// Represents a span of memory (`&mut [u8]` ) as a struct usable by C code.
|
||||
///
|
||||
/// Usage of this type is inherently unsafe.
|
||||
pub struct CByteSlice {
|
||||
/// The start address of the memory
|
||||
pub start: *mut u8,
|
||||
/// The amount of memory in bytes
|
||||
pub length: usize,
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
use crate::{
|
||||
BitVec, ByteGrid, CommandCode, CompressionCode, Header, Packet, PixelGrid,
|
||||
BitVec, ByteGrid, CompressionCode, Header, Packet, PixelGrid,
|
||||
TILE_SIZE,
|
||||
};
|
||||
use crate::command_code::CommandCode;
|
||||
use crate::compression::{into_compressed, into_decompressed};
|
||||
|
||||
/// An origin marks the top left position of a window sent to the display.
|
||||
|
@ -18,8 +19,10 @@ impl Origin {
|
|||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Size(pub u16, pub u16);
|
||||
|
||||
/// Type alias for documenting the meaning of the u16 in enum values
|
||||
pub type Offset = u16;
|
||||
|
||||
/// Type alias for documenting the meaning of the u16 in enum values
|
||||
pub type Brightness = u8;
|
||||
|
||||
/// A command to send to the display.
|
||||
|
@ -29,12 +32,14 @@ pub enum Command {
|
|||
Clear,
|
||||
/// Kills the udp daemon, usually results in a reboot of the display.
|
||||
HardReset,
|
||||
/// Slowly decrease brightness until off? Untested.
|
||||
FadeOut,
|
||||
/// Set the brightness of tiles
|
||||
CharBrightness(Origin, ByteGrid),
|
||||
/// Set the brightness of all tiles
|
||||
Brightness(Brightness),
|
||||
#[deprecated]
|
||||
/// Legacy command code, gets ignored by the real display.
|
||||
BitmapLegacy,
|
||||
/// Set pixel data starting at the offset.
|
||||
/// The contained BitVec is always uncompressed.
|
||||
|
@ -54,9 +59,10 @@ pub enum Command {
|
|||
BitmapLinearWin(Origin, PixelGrid),
|
||||
}
|
||||
|
||||
impl Into<Packet> for Command {
|
||||
fn into(self) -> Packet {
|
||||
match self {
|
||||
impl From<Command> for Packet {
|
||||
/// Move the `Command` into a `Packet` instance for sending.
|
||||
fn from(value: Command) -> Self {
|
||||
match value {
|
||||
Command::Clear => command_code_only(CommandCode::Clear),
|
||||
Command::FadeOut => command_code_only(CommandCode::FadeOut),
|
||||
Command::HardReset => command_code_only(CommandCode::HardReset),
|
||||
|
@ -64,10 +70,9 @@ impl Into<Packet> for Command {
|
|||
Command::BitmapLegacy => {
|
||||
command_code_only(CommandCode::BitmapLegacy)
|
||||
}
|
||||
Command::CharBrightness(origin, grid) => origin_size_payload(
|
||||
CommandCode::CharBrightness,
|
||||
origin,
|
||||
Size(grid.width as u16, grid.height as u16),
|
||||
Command::CharBrightness(Origin(x, y), grid) => Packet(
|
||||
Header(CommandCode::CharBrightness.into(),
|
||||
x, y, grid.width as u16, grid.height as u16),
|
||||
grid.into(),
|
||||
),
|
||||
Command::Brightness(brightness) => Packet(
|
||||
|
@ -126,10 +131,8 @@ impl Into<Packet> for Command {
|
|||
bits.into(),
|
||||
)
|
||||
}
|
||||
Command::Cp437Data(origin, grid) => origin_size_payload(
|
||||
CommandCode::Cp437Data,
|
||||
origin,
|
||||
Size(grid.width as u16, grid.height as u16),
|
||||
Command::Cp437Data(Origin(x, y), grid) => Packet(
|
||||
Header(CommandCode::Cp437Data.into(), x, y, grid.width as u16, grid.height as u16),
|
||||
grid.into(),
|
||||
),
|
||||
}
|
||||
|
@ -137,6 +140,7 @@ impl Into<Packet> for Command {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Err values for `Command::try_from`.
|
||||
pub enum TryFromPacketError {
|
||||
/// the contained command code does not correspond to a known command
|
||||
InvalidCommand(u16),
|
||||
|
@ -155,6 +159,7 @@ pub enum TryFromPacketError {
|
|||
impl TryFrom<Packet> for Command {
|
||||
type Error = TryFromPacketError;
|
||||
|
||||
/// Try to interpret the `Packet` as one containing a `Command`
|
||||
fn try_from(value: Packet) -> Result<Self, Self::Error> {
|
||||
let Packet(Header(command_u16, a, b, c, d), _) = value;
|
||||
let command_code = match CommandCode::try_from(command_u16) {
|
||||
|
@ -178,9 +183,11 @@ impl TryFrom<Packet> for Command {
|
|||
));
|
||||
}
|
||||
|
||||
match check_empty_header(header) {
|
||||
Some(err) => Err(err),
|
||||
None => Ok(Command::Brightness(payload[0])),
|
||||
let Header(_, a, b, c, d) = header;
|
||||
if a != 0 || b != 0 || c != 0 || d != 0 {
|
||||
Err(TryFromPacketError::ExtraneousHeaderValues)
|
||||
} else {
|
||||
Ok(Command::Brightness(payload[0]))
|
||||
}
|
||||
}
|
||||
CommandCode::HardReset => match check_command_only(value) {
|
||||
|
@ -238,6 +245,7 @@ impl TryFrom<Packet> for Command {
|
|||
}
|
||||
}
|
||||
|
||||
/// Helper method for BitMapLinear*-Commands into Packet
|
||||
fn bitmap_linear_into_packet(
|
||||
command: CommandCode,
|
||||
offset: Offset,
|
||||
|
@ -257,30 +265,12 @@ fn bitmap_linear_into_packet(
|
|||
)
|
||||
}
|
||||
|
||||
fn origin_size_payload(
|
||||
command: CommandCode,
|
||||
origin: Origin,
|
||||
size: Size,
|
||||
payload: Vec<u8>,
|
||||
) -> Packet {
|
||||
let Origin(x, y) = origin;
|
||||
let Size(w, h) = size;
|
||||
Packet(Header(command.into(), x, y, w, h), payload.into())
|
||||
}
|
||||
|
||||
/// 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![])
|
||||
}
|
||||
|
||||
fn check_empty_header(header: Header) -> Option<TryFromPacketError> {
|
||||
let Header(_, a, b, c, d) = header;
|
||||
if a != 0 || b != 0 || c != 0 || d != 0 {
|
||||
Some(TryFromPacketError::ExtraneousHeaderValues)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper method for checking that a packet is empty and only contains a command code
|
||||
fn check_command_only(packet: Packet) -> Option<TryFromPacketError> {
|
||||
let Packet(Header(_, a, b, c, d), payload) = packet;
|
||||
if payload.len() != 0 {
|
||||
|
@ -292,6 +282,7 @@ fn check_command_only(packet: Packet) -> Option<TryFromPacketError> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Helper method for Packets into BitMapLinear*-Commands
|
||||
fn packet_into_linear_bitmap(
|
||||
packet: Packet,
|
||||
) -> Result<(BitVec, CompressionCode), TryFromPacketError> {
|
||||
|
@ -323,21 +314,17 @@ pub mod c_api
|
|||
|
||||
use crate::{BitVec, Brightness, ByteGrid, Command, CompressionCode, Offset, Origin, Packet, PixelGrid};
|
||||
|
||||
/// Tries to load a `Command` from the passed array with the specified length.
|
||||
|
||||
/// Tries to turn a `Packet` into a `Command`. The packet is gets deallocated in the process.
|
||||
///
|
||||
/// returns: NULL in case of an error, pointer to the allocated command otherwise
|
||||
/// Returns: pointer to command or NULL
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp2_command_try_load(data: *const u8, length: usize) -> *mut Command {
|
||||
let data = std::slice::from_raw_parts(data, length);
|
||||
let packet = match Packet::try_from(data) {
|
||||
pub unsafe extern "C" fn sp2_command_try_from_packet(packet: *mut Packet) -> *mut Command {
|
||||
let packet = *Box::from_raw(packet);
|
||||
match Command::try_from(packet) {
|
||||
Err(_) => return null_mut(),
|
||||
Ok(packet) => packet
|
||||
};
|
||||
let command = match Command::try_from(packet) {
|
||||
Err(_) => return null_mut(),
|
||||
Ok(command) => command,
|
||||
};
|
||||
Box::into_raw(Box::new(command))
|
||||
Ok(command) => Box::into_raw(Box::new(command)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Clones a `Command` instance
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
use CommandCode::*;
|
||||
|
||||
/// The codes used for the commands. See the documentation on the corresponding commands.
|
||||
/// The u16 command codes used for the `Commands`.
|
||||
#[repr(u16)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum CommandCode {
|
||||
pub(crate) enum CommandCode {
|
||||
Clear = 0x0002,
|
||||
Cp437Data = 0x0003,
|
||||
CharBrightness = 0x0005,
|
||||
|
@ -19,16 +17,20 @@ pub enum CommandCode {
|
|||
BitmapLinearXor = 0x0016,
|
||||
}
|
||||
|
||||
impl Into<u16> for CommandCode {
|
||||
fn into(self) -> u16 {
|
||||
self as u16
|
||||
impl From<CommandCode> for u16 {
|
||||
/// returns the u16 command code corresponding to the enum value
|
||||
fn from(value: CommandCode) -> Self {
|
||||
value as u16
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u16> for CommandCode {
|
||||
type Error = ();
|
||||
|
||||
/// Returns the enum value for the specified `u16` or `Error` if the code is unknown.
|
||||
fn try_from(value: u16) -> Result<Self, Self::Error> {
|
||||
use CommandCode::*;
|
||||
|
||||
match value {
|
||||
value if value == Clear as u16 => Ok(Clear),
|
||||
value if value == Cp437Data as u16 => Ok(Cp437Data),
|
||||
|
|
|
@ -15,9 +15,9 @@ pub enum CompressionCode {
|
|||
Zs = 0x7a73,
|
||||
}
|
||||
|
||||
impl Into<u16> for CompressionCode {
|
||||
fn into(self) -> u16 {
|
||||
self as u16
|
||||
impl From<CompressionCode> for u16 {
|
||||
fn from(value: CompressionCode) -> Self {
|
||||
value as u16
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ impl Connection {
|
|||
/// .expect("connection failed");
|
||||
///
|
||||
/// // turn off all pixels
|
||||
/// connection.send(servicepoint2::Command::Clear)
|
||||
/// connection.send(servicepoint2::Command::Clear.into())
|
||||
/// .expect("send failed");
|
||||
///
|
||||
/// // turn on all pixels
|
||||
|
@ -50,12 +50,12 @@ impl Connection {
|
|||
/// pixels.fill(true);
|
||||
///
|
||||
/// // send pixels to display
|
||||
/// connection.send(servicepoint2::Command::BitmapLinearWin(servicepoint2::Origin::top_left(), pixels))
|
||||
/// connection.send(servicepoint2::Command::BitmapLinearWin(servicepoint2::Origin::top_left(), pixels).into())
|
||||
/// .expect("send failed");
|
||||
/// ```
|
||||
pub fn send(
|
||||
&self,
|
||||
packet: impl Into<Packet> + Debug,
|
||||
packet: Packet,
|
||||
) -> Result<(), std::io::Error> {
|
||||
debug!("sending {packet:?}");
|
||||
let packet: Packet = packet.into();
|
||||
|
@ -71,7 +71,7 @@ pub mod c_api
|
|||
use std::ffi::{c_char, CStr};
|
||||
use std::ptr::null_mut;
|
||||
|
||||
use crate::{Command, Connection};
|
||||
use crate::{Connection, Packet};
|
||||
|
||||
/// Creates a new instance of Connection.
|
||||
/// The returned instance has to be deallocated with `connection_dealloc`.
|
||||
|
@ -87,15 +87,14 @@ pub mod c_api
|
|||
Ok(value) => value
|
||||
};
|
||||
|
||||
let boxed = Box::new(connection);
|
||||
Box::into_raw(boxed)
|
||||
Box::into_raw(Box::new(connection))
|
||||
}
|
||||
|
||||
/// Sends the command instance. The instance is consumed / destroyed and cannot be used after this call.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp2_connection_send(connection: *const Connection, command_ptr: *mut Command) -> bool{
|
||||
let command = Box::from_raw(command_ptr);
|
||||
(*connection).send(*command).is_ok()
|
||||
pub unsafe extern "C" fn sp2_connection_send(connection: *const Connection, command_ptr: *mut Packet) -> bool{
|
||||
let packet = Box::from_raw(command_ptr);
|
||||
(*connection).send(*packet).is_ok()
|
||||
}
|
||||
|
||||
/// Closes and deallocates a connection instance
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
pub use crate::bit_vec::BitVec;
|
||||
pub use crate::byte_grid::ByteGrid;
|
||||
pub use crate::command::{Brightness, Command, Offset, Origin, Size};
|
||||
pub use crate::command_code::CommandCode;
|
||||
pub use crate::compression_code::CompressionCode;
|
||||
pub use crate::connection::Connection;
|
||||
pub use crate::packet::{Header, Packet, Payload};
|
||||
pub use crate::pixel_grid::PixelGrid;
|
||||
|
||||
#[cfg(feature = "c-api")]
|
||||
pub use crate::c_slice::CByteSlice;
|
||||
|
||||
mod bit_vec;
|
||||
mod byte_grid;
|
||||
mod command;
|
||||
|
@ -16,6 +18,7 @@ mod compression_code;
|
|||
mod connection;
|
||||
mod packet;
|
||||
mod pixel_grid;
|
||||
mod c_slice;
|
||||
|
||||
/// size of a single tile in one dimension
|
||||
pub const TILE_SIZE: u16 = 8;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::mem::size_of;
|
||||
|
||||
/// A raw header. Should probably not be used directly.
|
||||
#[derive(Debug)]
|
||||
pub struct Header(pub u16, pub u16, pub u16, pub u16, pub u16);
|
||||
|
@ -9,12 +11,13 @@ pub type Payload = Vec<u8>;
|
|||
#[derive(Debug)]
|
||||
pub struct Packet(pub Header, pub Payload);
|
||||
|
||||
impl Into<Payload> for Packet {
|
||||
fn into(self) -> Vec<u8> {
|
||||
let Packet(Header(mode, a, b, c, d), payload) = self;
|
||||
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 mut packet = vec![0u8; 10 + payload.len()];
|
||||
packet[0..=1].copy_from_slice(&u16::to_be_bytes(mode));
|
||||
packet[0..=1].copy_from_slice(&u16::to_be_bytes(mode.into()));
|
||||
packet[2..=3].copy_from_slice(&u16::to_be_bytes(a));
|
||||
packet[4..=5].copy_from_slice(&u16::to_be_bytes(b));
|
||||
packet[6..=7].copy_from_slice(&u16::to_be_bytes(c));
|
||||
|
@ -33,8 +36,17 @@ fn u16_from_be_slice(slice: &[u8]) -> u16 {
|
|||
u16::from_be_bytes(bytes)
|
||||
}
|
||||
|
||||
impl From<Payload> for Packet {
|
||||
fn from(value: Vec<u8>) -> Self {
|
||||
impl TryFrom<&[u8]> for Packet {
|
||||
type Error = ();
|
||||
|
||||
/// Tries to interpret the bytes as a `Packet`.
|
||||
///
|
||||
/// returns: `Error` if slice is not long enough to be a `Packet`
|
||||
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
|
||||
if value.len() < size_of::<Header>() {
|
||||
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]);
|
||||
|
@ -42,19 +54,42 @@ impl From<Payload> for Packet {
|
|||
let d = u16_from_be_slice(&value[8..=9]);
|
||||
let payload = value[10..].to_vec();
|
||||
|
||||
Packet(Header(mode, a, b, c, d), payload)
|
||||
Ok(Packet(Header(mode, a, b, c, d), payload))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8]> for Packet {
|
||||
fn from(value: &[u8]) -> Self {
|
||||
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 payload = value[10..].to_vec();
|
||||
#[cfg(feature = "c-api")]
|
||||
mod c_api {
|
||||
use std::ptr::null_mut;
|
||||
|
||||
Packet(Header(mode, a, b, c, d), payload)
|
||||
use crate::{Command, Packet};
|
||||
|
||||
/// Turns a `Command` into a `Packet`. The command gets deallocated in the process.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp2_packet_from_command(command: *mut Command) -> *mut Packet {
|
||||
let command = *Box::from_raw(command);
|
||||
let packet = command.into();
|
||||
Box::into_raw(Box::new(packet))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Tries to load a `Packet` from the passed array with the specified length.
|
||||
///
|
||||
/// returns: NULL in case of an error, pointer to the allocated packet otherwise
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp2_packet_try_load(data: *const u8, length: usize) -> *mut Packet {
|
||||
let data = std::slice::from_raw_parts(data, length);
|
||||
match Packet::try_from(data) {
|
||||
Err(_) => null_mut(),
|
||||
Ok(packet) => Box::into_raw(Box::new(packet))
|
||||
}
|
||||
}
|
||||
|
||||
/// Deallocates a `Packet`.
|
||||
///
|
||||
/// Note: do not call this if the instance has been consumed in another way, e.g. by sending it.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp2_packet_dealloc(this: *mut Packet) {
|
||||
_ = Box::from_raw(this)
|
||||
}
|
||||
}
|
|
@ -77,20 +77,22 @@ impl PixelGrid {
|
|||
self.bit_vec.fill(value);
|
||||
}
|
||||
|
||||
pub fn data_ref(&self) -> &[u8] {
|
||||
self.bit_vec.data_ref()
|
||||
pub fn mut_data_ref(&mut self) -> &mut [u8] {
|
||||
self.bit_vec.mut_data_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Vec<u8>> for PixelGrid {
|
||||
fn into(self) -> Vec<u8> {
|
||||
self.bit_vec.into()
|
||||
impl From<PixelGrid> for Vec<u8> {
|
||||
/// Turns a `PixelGrid` into the underlying `Vec<u8>`.
|
||||
fn from(value: PixelGrid) -> Self {
|
||||
value.bit_vec.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "c-api")]
|
||||
pub mod c_api
|
||||
{
|
||||
use crate::c_slice::CByteSlice;
|
||||
use crate::PixelGrid;
|
||||
|
||||
/// Creates a new `PixelGrid` instance.
|
||||
|
@ -153,10 +155,21 @@ pub mod c_api
|
|||
(*this).height
|
||||
}
|
||||
|
||||
/// Gets a reference to the data of the `PixelGrid` instance.
|
||||
/// Gets an unsafe reference to the data of the `PixelGrid` instance.
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// The caller has to make sure to never access the returned memory after the `PixelGrid`
|
||||
/// instance has been consumed or manually deallocated.
|
||||
///
|
||||
/// Reading and writing concurrently to either the original instance or the returned data will
|
||||
/// result in undefined behavior.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sp2_pixel_grid_data_ref(this: *const PixelGrid) -> *const u8 {
|
||||
// TODO: also return length
|
||||
(*this).data_ref().as_ptr_range().start
|
||||
pub unsafe extern "C" fn sp2_pixel_grid_unsafe_data_ref(this: *mut PixelGrid) -> CByteSlice {
|
||||
let data = (*this).mut_data_ref();
|
||||
CByteSlice {
|
||||
start: data.as_mut_ptr_range().start,
|
||||
length: data.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue