#![cfg_attr(not(feature = "use_std"), no_std)]
#[derive(Debug)]
pub struct CobsEncoder<'a> {
dest: &'a mut [u8],
dest_idx: usize,
code_idx: usize,
num_bt_sent: u8,
}
impl<'a> CobsEncoder<'a> {
pub fn new(out_buf: &'a mut [u8]) -> CobsEncoder<'a> {
CobsEncoder {
dest: out_buf,
dest_idx: 1,
code_idx: 0,
num_bt_sent: 1,
}
}
pub fn push(&mut self, data: &[u8]) -> Result<(), ()> {
for x in data {
if *x == 0 {
*self.dest.get_mut(self.code_idx)
.ok_or_else(|| ())? = self.num_bt_sent;
self.num_bt_sent = 1;
self.code_idx = self.dest_idx;
self.dest_idx += 1;
} else {
*self.dest.get_mut(self.dest_idx)
.ok_or_else(|| ())? = *x;
self.num_bt_sent += 1;
self.dest_idx += 1;
if 0xFF == self.num_bt_sent {
*self.dest.get_mut(self.code_idx)
.ok_or_else(|| ())? = self.num_bt_sent;
self.num_bt_sent = 1;
self.code_idx = self.dest_idx;
self.dest_idx += 1;
}
}
}
Ok(())
}
pub fn finalize(self) -> Result<usize, ()> {
if self.dest_idx == 1 {
return Ok(0);
}
if let Some(i) = self.dest.get_mut(self.code_idx) {
*i = self.num_bt_sent;
}
return Ok(self.dest_idx);
}
}
pub fn encode(source: &[u8], dest: &mut[u8]) -> usize {
let mut enc = CobsEncoder::new(dest);
enc.push(source).unwrap();
enc.finalize().unwrap()
}
pub fn encode_with_sentinel(source: &[u8], dest: &mut[u8], sentinel: u8) -> usize {
let encoded_size = encode(source, dest);
for x in &mut dest[..encoded_size] {
*x ^= sentinel;
}
return encoded_size;
}
#[cfg(feature = "use_std")]
pub fn encode_vec(source: &[u8]) -> Vec<u8> {
let mut encoded = vec![0; max_encoding_length(source.len())];
let encoded_len = encode(source, &mut encoded[..]);
encoded.truncate(encoded_len);
return encoded;
}
#[cfg(feature = "use_std")]
pub fn encode_vec_with_sentinel(source: &[u8], sentinel: u8) -> Vec<u8> {
let mut encoded = vec![0; max_encoding_length(source.len())];
let encoded_len = encode_with_sentinel(source, &mut encoded[..], sentinel);
encoded.truncate(encoded_len);
return encoded;
}
#[derive(Debug)]
pub struct CobsDecoder<'a> {
dest: &'a mut [u8],
dest_idx: usize,
state: DecoderState,
}
#[derive(Debug)]
enum DecoderState {
Idle,
Grab(u8),
GrabChain(u8),
ErrOrComplete,
}
fn add(to: &mut [u8], idx: usize, data: u8) -> Result<(), ()> {
*to.get_mut(idx)
.ok_or_else(|| ())? = data;
Ok(())
}
impl<'a> CobsDecoder<'a> {
pub fn new(dest: &'a mut [u8]) -> CobsDecoder<'a> {
CobsDecoder {
dest,
dest_idx: 0,
state: DecoderState::Idle,
}
}
pub fn feed(&mut self, data: u8) -> Result<Option<usize>, usize> {
use DecoderState::*;
let (ret, state) = match (&self.state, data) {
(Idle, 0x00) => (Ok(None), Idle),
(Idle, 0xFF) => (Ok(None), GrabChain(0xFE)),
(Idle, n) => (Ok(None), Grab(n - 1)),
(Grab(0), 0x00) => (Ok(Some(self.dest_idx)), ErrOrComplete),
(Grab(0), 0xFF) => {
add(self.dest, self.dest_idx, 0u8).map_err(|_| self.dest_idx)?;
self.dest_idx += 1usize;
(Ok(None), GrabChain(0xFE))
},
(Grab(0), n) => {
add(self.dest, self.dest_idx, 0u8).map_err(|_| self.dest_idx)?;
self.dest_idx += 1usize;
(Ok(None), Grab(n - 1))
},
(Grab(_), 0) => {
(Err(self.dest_idx), ErrOrComplete)
}
(Grab(i), n) => {
add(self.dest, self.dest_idx, n).map_err(|_| self.dest_idx)?;
self.dest_idx += 1;
(Ok(None), Grab(i - 1))
},
(GrabChain(0), 0x00) => {
(Ok(Some(self.dest_idx)), ErrOrComplete)
}
(GrabChain(0), 0xFF) => (Ok(None), GrabChain(0xFE)),
(GrabChain(0), n) => (Ok(None), Grab(n - 1)),
(GrabChain(_), 0) => {
(Err(self.dest_idx), ErrOrComplete)
}
(GrabChain(i), n) => {
add(self.dest, self.dest_idx, n).map_err(|_| self.dest_idx)?;
self.dest_idx += 1;
(Ok(None), GrabChain(i - 1))
},
(ErrOrComplete, _) => (Err(self.dest_idx), ErrOrComplete),
};
self.state = state;
ret
}
pub fn push(&mut self, data: &[u8]) -> Result<Option<(usize, usize)>, usize> {
for (consumed_idx, d) in data.iter().enumerate() {
let x = self.feed(*d);
if let Some(decoded_bytes_ct) = x? {
return Ok(Some((decoded_bytes_ct, consumed_idx + 1)));
}
}
Ok(None)
}
}
macro_rules! decode_raw (
($src:ident, $dst:ident) => ({
let mut source_index = 0;
let mut dest_index = 0;
while source_index < $src.len() {
let code = $src[source_index];
if source_index + code as usize > $src.len() && code != 1 {
return Err(());
}
source_index += 1;
for _ in 1..code {
$dst[dest_index] = $src[source_index];
source_index += 1;
dest_index += 1;
}
if 0xFF != code && source_index < $src.len() {
$dst[dest_index] = 0;
dest_index += 1;
}
}
Ok(dest_index)
})
);
pub fn decode(source: &[u8], dest: &mut[u8]) -> Result<usize, ()> {
let mut dec = CobsDecoder::new(dest);
assert!(dec.push(source).unwrap().is_none());
if let Some((d_used, _s_used)) = dec.push(&[0]).unwrap() {
Ok(d_used)
} else {
Err(())
}
}
pub fn decode_in_place(buff: &mut[u8]) -> Result<usize, ()> {
decode_raw!(buff, buff)
}
pub fn decode_with_sentinel(source: &[u8], dest: &mut[u8], sentinel: u8) -> Result<usize, ()> {
for (x, y) in source.iter().zip(dest.iter_mut()) {
*y = *x ^ sentinel;
}
decode_in_place(dest)
}
pub fn decode_in_place_with_sentinel(buff: &mut[u8], sentinel: u8) -> Result<usize, ()> {
for x in buff.iter_mut() {
*x ^= sentinel;
}
decode_in_place(buff)
}
#[cfg(feature = "use_std")]
pub fn decode_vec(source: &[u8]) -> Result<Vec<u8>, ()> {
let mut decoded = vec![0; source.len()];
match decode(source, &mut decoded[..]) {
Ok(n) => {
decoded.truncate(n);
Ok(decoded)
},
Err(()) => Err(()),
}
}
#[cfg(feature = "use_std")]
pub fn decode_vec_with_sentinel(source: &[u8], sentinel: u8) -> Result<Vec<u8>, ()> {
let mut decoded = vec![0; source.len()];
match decode_with_sentinel(source, &mut decoded[..], sentinel) {
Ok(n) => {
decoded.truncate(n);
Ok(decoded)
},
Err(()) => Err(()),
}
}
pub fn max_encoding_length(source_len: usize) -> usize {
source_len + (source_len / 254) + if source_len % 254 > 0 { 1 } else { 0 }
}