use crate::{cobs, DecodeError, DELIMITER};
#[cfg(feature = "alloc")]
use crate::cobsr;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[must_use]
pub fn frame(packet: &[u8], dst: &mut [u8]) -> usize {
let n = cobs::encode(packet, dst);
dst[n] = DELIMITER;
n + 1
}
#[derive(Debug)]
pub struct StreamDecoder<'a> {
dst: &'a mut [u8],
write_index: usize,
remaining: u8,
code: u8,
sentinel: u8,
reduced: bool,
}
impl<'a> StreamDecoder<'a> {
#[must_use]
pub fn new(dst: &'a mut [u8]) -> Self {
Self {
dst,
write_index: 0,
remaining: 0,
code: 0,
sentinel: DELIMITER,
reduced: false,
}
}
#[must_use]
pub fn reduced(mut self, reduced: bool) -> Self {
self.reduced = reduced;
self
}
#[must_use]
pub fn sentinel(mut self, sentinel: u8) -> Self {
self.sentinel = sentinel;
self
}
pub fn feed(&mut self, byte: u8) -> Result<Option<usize>, DecodeError> {
if byte == self.sentinel {
if self.remaining > 0 {
if self.reduced {
self.put(self.code)?;
} else {
let index = self.write_index;
self.reset();
return Err(DecodeError::Truncated { index });
}
}
let len = self.write_index;
self.reset();
return Ok(Some(len));
}
let value = byte ^ self.sentinel;
if self.remaining == 0 {
if self.code != 0 && self.code < 0xFF {
self.put(0)?;
}
self.code = value;
self.remaining = value - 1;
} else {
self.put(value)?;
self.remaining -= 1;
}
Ok(None)
}
pub fn push(&mut self, chunk: &[u8], mut on_frame: impl FnMut(Result<&[u8], DecodeError>)) {
for &byte in chunk {
match self.feed(byte) {
Ok(Some(len)) => on_frame(Ok(&self.dst[..len])),
Ok(None) => {}
Err(err) => on_frame(Err(err)),
}
}
}
#[must_use]
pub fn decoded(&self) -> &[u8] {
&self.dst[..self.write_index]
}
pub fn reset(&mut self) {
self.write_index = 0;
self.remaining = 0;
self.code = 0;
}
fn put(&mut self, byte: u8) -> Result<(), DecodeError> {
*self
.dst
.get_mut(self.write_index)
.ok_or(DecodeError::OutputTooSmall)? = byte;
self.write_index += 1;
Ok(())
}
}
#[cfg(feature = "alloc")]
#[must_use]
pub fn frame_to_vec(packet: &[u8]) -> Vec<u8> {
let mut v = cobs::encode_to_vec(packet);
v.push(DELIMITER);
v
}
#[cfg(feature = "alloc")]
#[must_use]
pub fn frame_reduced_to_vec(packet: &[u8]) -> Vec<u8> {
let mut v = cobsr::encode_to_vec(packet);
v.push(DELIMITER);
v
}
#[cfg(feature = "alloc")]
#[derive(Debug, Clone, Default)]
pub struct FrameDecoder {
buf: Vec<u8>,
reduced: bool,
skip_empty: bool,
max_frame_len: usize,
}
#[cfg(feature = "alloc")]
impl FrameDecoder {
#[must_use]
pub fn new() -> Self {
Self {
buf: Vec::new(),
reduced: false,
skip_empty: true,
max_frame_len: 0,
}
}
#[must_use]
pub fn reduced(mut self, reduced: bool) -> Self {
self.reduced = reduced;
self
}
#[must_use]
pub fn skip_empty(mut self, skip_empty: bool) -> Self {
self.skip_empty = skip_empty;
self
}
#[must_use]
pub fn max_frame_len(mut self, max_frame_len: usize) -> Self {
self.max_frame_len = max_frame_len;
self
}
pub fn push(&mut self, chunk: &[u8], mut on_frame: impl FnMut(Result<Vec<u8>, DecodeError>)) {
let mut start = 0;
for (i, &b) in chunk.iter().enumerate() {
if b != DELIMITER {
continue;
}
self.buf.extend_from_slice(&chunk[start..i]);
start = i + 1;
let frame = core::mem::take(&mut self.buf);
if frame.is_empty() {
if !self.skip_empty {
on_frame(Ok(Vec::new()));
}
continue;
}
let decoded = if self.reduced {
cobsr::decode_to_vec(&frame)
} else {
cobs::decode_to_vec(&frame)
};
on_frame(decoded);
}
if start < chunk.len() {
self.buf.extend_from_slice(&chunk[start..]);
if self.max_frame_len != 0 && self.buf.len() > self.max_frame_len {
let len = self.buf.len();
self.buf.clear();
on_frame(Err(DecodeError::FrameTooLong { len }));
}
}
}
pub fn reset(&mut self) {
self.buf.clear();
}
}