use canadensis_core::OutOfMemoryError;
pub fn escape_from_iter<I>(source: I, destination: &mut [u8]) -> Result<usize, OutOfMemoryError>
where
I: IntoIterator<Item = u8>,
{
let mut dest_current = 1usize;
let mut dest_code = 0usize;
let mut code: u8 = 0x1;
for byte in source {
if byte == 0 {
let code_entry = destination.get_mut(dest_code).ok_or(OutOfMemoryError)?;
*code_entry = code;
code = 0x1;
dest_code = dest_current;
dest_current += 1;
} else {
if code == 0xff {
let entry = destination.get_mut(dest_code).ok_or(OutOfMemoryError)?;
*entry = code;
code = 0x1;
dest_code = dest_current;
dest_current += 1;
}
let entry = destination.get_mut(dest_current).ok_or(OutOfMemoryError)?;
*entry = byte;
dest_current += 1;
code += 1;
}
}
let code_entry = destination.get_mut(dest_code).ok_or(OutOfMemoryError)?;
*code_entry = code;
Ok(dest_current)
}
pub struct Unescaper {
bytes_to_copy: u8,
pending_zero: bool,
}
impl Unescaper {
pub fn new() -> Self {
Unescaper {
bytes_to_copy: 0,
pending_zero: false,
}
}
pub fn accept(&mut self, byte: u8) -> Result<Option<u8>, DecodeZeroError> {
if byte == 0 {
Err(DecodeZeroError)
} else if self.bytes_to_copy == 0 {
self.bytes_to_copy = byte - 1;
let result = if self.pending_zero { Some(0) } else { None };
self.pending_zero = byte < 0xff;
Ok(result)
} else {
self.bytes_to_copy -= 1;
Ok(Some(byte))
}
}
}
pub fn escaped_size(raw_size: usize) -> usize {
if raw_size == 0 {
1
} else {
let overhead = raw_size.div_ceil(254);
raw_size + overhead
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct DecodeZeroError;
#[cfg(test)]
mod tests {
use crate::cobs::{escape_from_iter, Unescaper};
use canadensis_core::OutOfMemoryError;
fn escape(source: &[u8], destination: &mut [u8]) -> Result<usize, OutOfMemoryError> {
escape_from_iter(source.iter().copied(), destination)
}
#[derive(Debug)]
struct DecodeError;
#[cfg(test)]
fn unescape(source: &[u8], destination: &mut [u8]) -> Result<usize, DecodeError> {
println!("Decode {:?}", source);
let dest_len = destination.len();
let mut src_iter = source.iter();
let mut dest_iter = destination.iter_mut();
while let Some(&code) = src_iter.next() {
if code == 0 {
return Err(DecodeError);
}
let copy_count = usize::from(code - 1);
let src_sub = src_iter.as_slice();
if src_sub.len() < copy_count {
println!(
"src_sub.len() {} < copy_count {}",
src_sub.len(),
copy_count
);
return Err(DecodeError);
}
let (src_read, src_others) = src_sub.split_at(copy_count);
src_iter = src_others.iter();
let dst_sub = dest_iter.into_slice();
if dst_sub.len() < copy_count {
println!(
"dst_sub.len() {} < copy_count {}",
dst_sub.len(),
copy_count
);
return Err(DecodeError);
}
let (dst_write, dst_others) = dst_sub.split_at_mut(copy_count);
dest_iter = dst_others.iter_mut();
dst_write.copy_from_slice(src_read);
if code < 0xff {
if let Some(entry) = dest_iter.next() {
*entry = 0x0;
}
}
}
Ok(dest_len - dest_iter.as_slice().len())
}
const TEST_CASES: &[(&[u8], &[u8])] = &[
(&[], &[1]),
(&[1], &[2, 1]),
(&[1, 2], &[3, 1, 2]),
(&[1, 0], &[2, 1, 1]),
(
&[
0x45, 0x00, 0x00, 0x2c, 0x4c, 0x79, 0x00, 0x00, 0x40, 0x06, 0x4f, 0x37,
],
&[
0x02, 0x45, 0x01, 0x04, 0x2c, 0x4c, 0x79, 0x01, 0x05, 0x40, 0x06, 0x4f, 0x37,
],
),
(
&[1; 254],
&[
255, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1,
],
),
];
#[test]
fn test_encode() {
for &(input, expected) in TEST_CASES {
let mut buffer = vec![0u8; expected.len()];
let encoded_bytes = escape(input, &mut buffer).unwrap();
assert_eq!(encoded_bytes, expected.len());
let buffer_used = &buffer[..expected.len()];
assert_eq!(buffer_used, expected);
}
}
#[test]
fn test_decode() {
for &(expected, input) in TEST_CASES {
let mut buffer = vec![0u8; expected.len()];
let decoded_bytes = unescape(input, &mut buffer).unwrap();
assert_eq!(decoded_bytes, expected.len());
let buffer_used = &buffer[..decoded_bytes];
assert_eq!(expected, buffer_used);
}
}
#[test]
fn test_streaming_decode() {
for &(expected, input) in TEST_CASES {
let mut buffer = Vec::new();
let mut unescaper = Unescaper::new();
for &byte in input {
if let Some(byte_out) = unescaper.accept(byte).unwrap() {
buffer.push(byte_out);
}
}
assert_eq!(expected, buffer);
}
}
}