use crate::{
errors::{DecodeError, InsufficientCapacity},
packet::{Header, Packet},
utils,
};
#[cfg(not(feature = "std"))]
use arrayvec::ArrayVec;
use core::ops::Range;
#[cfg(feature = "std")]
use std::io::{self, Write};
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Decoder {
#[cfg(feature = "std")]
buffer: Vec<u8>,
#[cfg(not(feature = "std"))]
buffer: ArrayVec<[u8; Decoder::DEFAULT_DECODER_BUFFER_SIZE]>,
}
impl Decoder {
pub const DEFAULT_DECODER_BUFFER_SIZE: usize = 512;
pub fn new() -> Decoder { Decoder::default() }
#[cfg(feature = "std")]
pub fn with_capacity(capacity: usize) -> Decoder {
Decoder {
buffer: Vec::with_capacity(capacity),
}
}
pub fn bytes_in_buffer(&self) -> usize { self.buffer.len() }
#[inline]
pub fn remaining_capacity(&self) -> usize { self._remaining_capacity() }
#[cfg(feature = "std")]
fn _remaining_capacity(&self) -> usize {
usize::max_value()
}
#[cfg(not(feature = "std"))]
fn _remaining_capacity(&self) -> usize {
self.buffer.capacity() - self.buffer.len()
}
pub fn clear(&mut self) { self.buffer.clear(); }
pub fn push_data(
&mut self,
data: &[u8],
) -> Result<(), InsufficientCapacity> {
self._push_data(data)
}
#[cfg(feature = "std")]
fn _push_data(&mut self, data: &[u8]) -> Result<(), InsufficientCapacity> {
self.buffer.extend_from_slice(data);
Ok(())
}
#[cfg(not(feature = "std"))]
fn _push_data(&mut self, data: &[u8]) -> Result<(), InsufficientCapacity> {
if self.remaining_capacity() < data.len() {
return Err(InsufficientCapacity {
required: data.len(),
actual: self.remaining_capacity(),
});
}
self.buffer.extend(data.iter().cloned());
Ok(())
}
pub fn decode(&mut self) -> Result<Packet, DecodeError> {
let pkt = find_potential_packet(&self.buffer)?;
let result = if pkt.crc_is_valid(&self.buffer) {
Ok(Packet::with_data(pkt.header.id, pkt.slice(&self.buffer))
.expect("Already validated"))
} else {
Err(DecodeError::InvalidCRC)
};
self.remove(pkt.contents.end);
result
}
fn remove(&mut self, amount: usize) { let _ = self.buffer.drain(..amount); }
}
#[cfg(feature = "std")]
impl Write for Decoder {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
match self.push_data(data) {
Ok(_) => Ok(data.len()),
Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
}
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
fn valid_header_locations<'a>(
data: &'a [u8],
) -> impl Iterator<Item = usize> + 'a {
data.windows(Header::LEN)
.enumerate()
.filter(|&(_, window)| Header::is_valid(window))
.map(|(i, _window)| i)
}
fn find_potential_packet(
buffer: &[u8],
) -> Result<PotentialPacket, DecodeError> {
let header_ix = valid_header_locations(buffer)
.next()
.ok_or(DecodeError::RequiresMoreData)?;
let header =
Header::from_bytes(&buffer[header_ix..]).expect("Already verified");
let content_start = header_ix + Header::LEN;
let content_end = content_start + header.len as usize;
if content_end > buffer.len() {
Err(DecodeError::RequiresMoreData)
} else {
Ok(PotentialPacket {
header,
contents: content_start..content_end,
})
}
}
#[derive(Debug, Clone, PartialEq)]
struct PotentialPacket {
header: Header,
contents: Range<usize>,
}
impl PotentialPacket {
fn crc_is_valid(&self, original_buffer: &[u8]) -> bool {
utils::calculate_crc16(self.slice(original_buffer)) == self.header.crc
}
fn slice<'a>(&self, buffer: &'a [u8]) -> &'a [u8] {
&buffer[self.contents.clone()]
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::prelude::v1::*;
#[test]
fn fill_the_decoder_buffer() {
let mut decoder = Decoder::new();
assert_eq!(decoder.bytes_in_buffer(), 0);
let random_data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
decoder.push_data(random_data).unwrap();
assert_eq!(decoder.bytes_in_buffer(), random_data.len());
assert_eq!(&decoder.buffer[..], random_data);
if cfg!(not(feature = "std")) {
let got = decoder.remaining_capacity();
let should_be =
Decoder::DEFAULT_DECODER_BUFFER_SIZE - random_data.len();
assert_eq!(got, should_be);
}
}
#[test]
#[cfg(not(feature = "std"))]
fn overflow_the_buffer() {
let mut decoder = Decoder::new();
let data = [0; Decoder::DEFAULT_DECODER_BUFFER_SIZE + 1];
let should_be = InsufficientCapacity {
required: data.len(),
actual: Decoder::DEFAULT_DECODER_BUFFER_SIZE,
};
let err = decoder.push_data(&data).unwrap_err();
assert_eq!(err, should_be);
}
fn write_packet_to_decoder(decoder: &mut Decoder, pkt: &Packet) {
let mut buffer = vec![0; pkt.total_length()];
pkt.write_to_buffer(&mut buffer).unwrap();
decoder.push_data(&buffer).unwrap();
}
#[test]
fn round_trip_a_packet() {
let mut decoder = Decoder::new();
let pkt =
Packet::with_data(42, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]).unwrap();
write_packet_to_decoder(&mut decoder, &pkt);
let got = decoder.decode().unwrap();
assert_eq!(got, pkt);
assert_eq!(decoder.bytes_in_buffer(), 0);
}
fn generate_garbage(size: usize) -> Vec<u8> {
let mut buffer = Vec::with_capacity(size);
let mut counter: usize = 123;
while buffer.len() < size {
let byte = counter * counter % 256 + buffer.len();
counter += byte;
buffer.push(byte as u8);
}
buffer
}
#[test]
fn find_all_valid_headers() {
let should_be = vec![0, 25, 73, 188, 222];
let mut buffer = generate_garbage(512);
for &ix in &should_be {
let body_length = ix % 15 + 1;
let body = generate_garbage(body_length);
let pkt = Packet::with_data(ix as u8, &body).unwrap();
pkt.write_to_buffer(&mut buffer[ix..]).unwrap();
}
let got: Vec<usize> = valid_header_locations(&buffer).collect();
assert_eq!(got, should_be);
}
#[test]
fn find_a_potential_packet() {
let start = 123;
let pkt = Packet::with_data(42, &[1, 2, 3, 4, 5, 6]).unwrap();
let mut buffer = generate_garbage(512);
pkt.write_to_buffer(&mut buffer[start..]).unwrap();
let should_be = PotentialPacket {
header: pkt.header(),
contents: start + Header::LEN..start + Header::LEN + pkt.len(),
};
let got = find_potential_packet(&buffer).unwrap();
assert_eq!(got, should_be);
}
}