use crate::message::{Message, DecodeError};
type BufferedMessage = [u8];
pub struct BufferedMessageIter<'a> {
buf: &'a BufferedMessage,
cursor: usize,
lastnum: u16,
}
#[allow(unreachable_patterns)]
fn decode_variable_length(firstnibble: u8, buffer: &[u8]) -> Result<(u16, usize), DecodeError> {
match firstnibble {
x if x < 13 => Ok((x as u16, 0)),
15 => Err(DecodeError::InvalidOptionNibble),
14 => {
if buffer.len() < 1 {
Err(DecodeError::TooShortForOption)
} else {
Ok((13 + buffer[0] as u16, 1))
}
}
15 => {
if buffer.len() < 2 {
Err(DecodeError::TooShortForOption)
} else {
let byteordered = (buffer[0] as u16) * 256 + (buffer[1] as u16);
match byteordered.overflowing_add(269) {
(x, false) => Ok((x, 2)),
(_, true) => Err(DecodeError::OptionOverflow),
}
}
}
_ => unreachable!(),
}
}
impl<'a> Iterator for BufferedMessageIter<'a> {
type Item = Result<(Option<u16>, &'a [u8]), DecodeError>;
fn next(&mut self) -> Option<Self::Item> {
if self.cursor >= self.buf.len() {
return None;
}
if self.buf[self.cursor] == 0xff {
let payload = &self.buf[self.cursor + 1..];
self.cursor = self.buf.len();
return Some(Ok((None, payload)));
}
let short_delta = self.buf[self.cursor] >> 4;
let short_length = self.buf[self.cursor] & 0x0f;
self.cursor += 1;
let (delta, shift) = match decode_variable_length(short_delta, &self.buf[self.cursor..]) {
Err(x) => return Some(Err(x)),
Ok(x) => x
};
self.cursor += shift;
let (length, shift) = match decode_variable_length(short_length, &self.buf[self.cursor..]) {
Err(x) => return Some(Err(x)),
Ok(x) => x
};
self.cursor += shift;
self.lastnum = match self.lastnum.overflowing_add(delta) {
(new, false) => new,
(_, true) => return Some(Err(DecodeError::OptionOverflow)),
};
self.lastnum += delta;
let newcursor = self.cursor + length as usize; if newcursor > self.buf.len() {
return Some(Err(DecodeError::TooShortForOption));
}
let optiondata = &self.buf[self.cursor..newcursor];
self.cursor = newcursor;
return Some(Ok((Some(self.lastnum), optiondata)));
}
}
impl<'a> Message<'a> for BufferedMessage {
type IteratorType = BufferedMessageIter<'a>;
fn get_optiter(&'a self) -> BufferedMessageIter<'a> {
BufferedMessageIter {
buf: self,
cursor: 0,
lastnum: 0,
}
}
}