use crate::{cobs, DELIMITER};
#[cfg(feature = "alloc")]
use crate::{cobsr, DecodeError};
#[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
}
#[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();
}
}