allow parsing packet that does not contain full header
This commit is contained in:
parent
0117478751
commit
b8dc57b1aa
3 changed files with 68 additions and 60 deletions
50
src/packet/header.rs
Normal file
50
src/packet/header.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/// 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.
|
||||
///
|
||||
/// The contained values are in platform endian-ness and may need to be converted before sending.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Default, Hash)]
|
||||
#[repr(C)]
|
||||
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,
|
||||
}
|
||||
|
||||
impl Header {
|
||||
pub fn read_from(value: &[u8]) -> Option<(Header, usize)> {
|
||||
const NULL_U16_SLICE: &[u8] = &[0, 0];
|
||||
|
||||
fn convert(slice: &[u8]) -> u16 {
|
||||
debug_assert_eq!(slice.len(), size_of::<u16>());
|
||||
u16::from_be_bytes([slice[0], slice[1]])
|
||||
}
|
||||
|
||||
let command_code = value.get(0..=1).map(convert)?;
|
||||
let a = value.get(2..=3).map(convert);
|
||||
let b = value.get(4..=5).map(convert);
|
||||
let c = value.get(6..=7).map(convert);
|
||||
let d = value.get(8..=9).map(convert);
|
||||
|
||||
let read_size = 2 + 2 * [a, b, c, d].iter().flatten().count();
|
||||
let header = Header {
|
||||
command_code,
|
||||
a: a.unwrap_or(0),
|
||||
b: b.unwrap_or(0),
|
||||
c: c.unwrap_or(0),
|
||||
d: d.unwrap_or(0),
|
||||
};
|
||||
|
||||
Some((header, read_size))
|
||||
}
|
||||
}
|
||||
10
src/packet/mod.rs
Normal file
10
src/packet/mod.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
mod header;
|
||||
mod packet;
|
||||
|
||||
pub use self::header::Header;
|
||||
pub use self::packet::Packet;
|
||||
|
||||
/// The raw payload.
|
||||
///
|
||||
/// Should probably only be used directly to use features not exposed by the library.
|
||||
pub type Payload = Vec<u8>;
|
||||
|
|
@ -1,36 +1,6 @@
|
|||
use crate::{command_code::CommandCode, Grid, Origin, Tiles};
|
||||
use crate::{command_code::CommandCode, Grid, Header, Origin, Payload, Tiles};
|
||||
use log::trace;
|
||||
use std::{mem::size_of, num::TryFromIntError};
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// The contained values are in platform endian-ness and may need to be converted before sending.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Default, Hash)]
|
||||
#[repr(C)]
|
||||
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,
|
||||
}
|
||||
|
||||
pub const HEADER_SIZE: usize = size_of::<Header>();
|
||||
|
||||
/// The raw payload.
|
||||
///
|
||||
/// Should probably only be used directly to use features not exposed by the library.
|
||||
pub type Payload = Vec<u8>;
|
||||
use std::num::TryFromIntError;
|
||||
|
||||
/// The raw packet.
|
||||
///
|
||||
|
|
@ -71,29 +41,14 @@ impl TryFrom<&[u8]> for 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() < HEADER_SIZE {
|
||||
return Err(SliceSmallerThanHeader);
|
||||
}
|
||||
let (header, read_bytes) =
|
||||
Header::read_from(value).ok_or(SliceSmallerThanHeader)?;
|
||||
|
||||
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 = if value.len() <= HEADER_SIZE {
|
||||
let payload = &value[read_bytes..];
|
||||
let payload = if payload.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(value[HEADER_SIZE..].to_vec())
|
||||
Some(payload.to_vec())
|
||||
};
|
||||
|
||||
trace!("loaded packet {header:?}");
|
||||
|
|
@ -147,14 +102,7 @@ impl Packet {
|
|||
/// Returns the amount of bytes this packet takes up when serialized.
|
||||
#[must_use]
|
||||
pub fn size(&self) -> usize {
|
||||
HEADER_SIZE + self.payload.as_ref().map_or(0, Vec::len)
|
||||
}
|
||||
|
||||
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)
|
||||
size_of::<Header>() + self.payload.as_ref().map_or(0, Vec::len)
|
||||
}
|
||||
|
||||
pub(crate) fn origin_grid_to_packet<T>(
|
||||
Loading…
Add table
Add a link
Reference in a new issue