use core::convert::TryInto;
use crate::{Error, Result};
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct EspPdu<'a> {
buffer: &'a [u8],
}
#[derive(Debug, Copy, Clone)]
pub enum Esp<'a> {
Raw(&'a [u8]),
}
impl<'a> EspPdu<'a> {
pub fn new(buffer: &'a [u8]) -> Result<Self> {
if buffer.len() < 8 {
return Err(Error::Truncated);
}
Ok(EspPdu { buffer })
}
pub fn buffer(&'a self) -> &'a [u8] {
self.buffer
}
pub fn into_buffer(self) -> &'a [u8] {
self.buffer
}
pub fn as_bytes(&'a self) -> &'a [u8] {
(*self).into_bytes()
}
pub fn into_bytes(self) -> &'a [u8] {
&self.buffer[0..8]
}
pub fn inner(&'a self) -> Result<Esp<'a>> {
(*self).into_inner()
}
pub fn into_inner(self) -> Result<Esp<'a>> {
let rest = &self.buffer[self.computed_data_offset()..];
Ok(Esp::Raw(rest))
}
pub fn computed_data_offset(&'a self) -> usize {
8
}
pub fn spi(&'a self) -> u32 {
u32::from_be_bytes(self.buffer[0..4].try_into().unwrap())
}
pub fn sequence_number(&'a self) -> u32 {
u32::from_be_bytes(self.buffer[4..8].try_into().unwrap())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_esp_parse_basic() {
let buffer: [u8; 16] = [
0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x01, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe,
];
let esp = EspPdu::new(&buffer).unwrap();
assert_eq!(esp.spi(), 0x12345678);
assert_eq!(esp.sequence_number(), 1);
assert_eq!(esp.computed_data_offset(), 8);
assert_eq!(esp.as_bytes(), &buffer[0..8]);
let Esp::Raw(payload) = esp.inner().unwrap();
assert_eq!(payload, &[0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe]);
}
#[test]
fn test_esp_truncated() {
let buffer: [u8; 7] = [0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00];
assert_eq!(EspPdu::new(&buffer), Err(Error::Truncated));
}
#[test]
fn test_esp_minimum_valid() {
let buffer: [u8; 8] = [
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, ];
let esp = EspPdu::new(&buffer).unwrap();
assert_eq!(esp.spi(), 1);
assert_eq!(esp.sequence_number(), 2);
let Esp::Raw(payload) = esp.inner().unwrap();
assert!(payload.is_empty());
}
#[test]
fn test_esp_max_values() {
let buffer: [u8; 8] = [
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ];
let esp = EspPdu::new(&buffer).unwrap();
assert_eq!(esp.spi(), u32::MAX);
assert_eq!(esp.sequence_number(), u32::MAX);
}
}