#[derive(Debug)]
pub struct CobsDecoder<'a> {
dest: &'a mut [u8],
dest_idx: usize,
state: DecoderState,
}
#[derive(Debug)]
pub enum DecoderState {
Idle,
Grab(u8),
GrabChain(u8),
}
fn add(to: &mut [u8], idx: usize, data: u8) -> Result<(), ()> {
*to.get_mut(idx)
.ok_or_else(|| ())? = data;
Ok(())
}
pub enum DecodeResult {
NoData,
DataComplete,
DataContinue(u8),
}
impl DecoderState {
pub fn feed(&mut self, data: u8) -> Result<DecodeResult, ()> {
use DecoderState::*;
use DecodeResult::*;
let (ret, state) = match (&self, data) {
(Idle, 0x00) => (Ok(NoData), Idle),
(Idle, 0xFF) => (Ok(NoData), GrabChain(0xFE)),
(Idle, n) => (Ok(NoData), Grab(n - 1)),
(Grab(0), 0x00) => (Ok(DataComplete), Idle),
(Grab(0), 0xFF) => {
(Ok(DataContinue(0)), GrabChain(0xFE))
},
(Grab(0), n) => {
(Ok(DataContinue(0)), Grab(n - 1))
},
(Grab(_), 0) => {
(Err(()), Idle)
}
(Grab(i), n) => {
(Ok(DataContinue(n)), Grab(*i - 1))
},
(GrabChain(0), 0x00) => {
(Ok(DataComplete), Idle)
}
(GrabChain(0), 0xFF) => (Ok(NoData), GrabChain(0xFE)),
(GrabChain(0), n) => (Ok(NoData), Grab(n - 1)),
(GrabChain(_), 0) => {
(Err(()), Idle)
}
(GrabChain(i), n) => {
(Ok(DataContinue(n)), GrabChain(*i - 1))
},
};
*self = state;
ret
}
}
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> {
match self.state.feed(data) {
Err(()) => Err(self.dest_idx),
Ok(DecodeResult::NoData) => Ok(None),
Ok(DecodeResult::DataContinue(n)) => {
add(self.dest, self.dest_idx, n).map_err(|_| self.dest_idx)?;
self.dest_idx += 1;
Ok(None)
}
Ok(DecodeResult::DataComplete) => {
Ok(Some(self.dest_idx))
}
}
}
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).or(Err(()))?.is_none());
if let Some((d_used, _s_used)) = dec.push(&[0]).or(Err(()))? {
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(()),
}
}