use std::cmp::min;
pub struct PartialBuffer<'a> {
slice: &'a [u8],
extra_buffer: &'a mut Vec<u8>,
continue_processing: bool,
}
impl<'a> PartialBuffer<'a> {
pub fn new(slice: &'a [u8], extra_buffer: &'a mut Vec<u8>) -> PartialBuffer<'a> {
PartialBuffer {
slice,
extra_buffer,
continue_processing: true,
}
}
pub fn continue_processing(&self) -> bool {
self.continue_processing
}
pub fn take(&mut self, size: usize, retention_bytes: usize) -> Option<Vec<u8>> {
if self.extra_buffer.len() + self.slice.len() < size + retention_bytes {
self.extra_buffer.extend_from_slice(self.slice);
self.slice = &[];
self.continue_processing = false;
return None;
}
let mut retval = Vec::with_capacity(size);
let amount_from_extra = min(self.extra_buffer.len(), size);
if amount_from_extra > 0 {
retval.extend_from_slice(&self.extra_buffer[0..amount_from_extra]);
self.extra_buffer.drain(0..amount_from_extra);
}
let amount_from_slice = size - amount_from_extra;
if amount_from_slice > 0 {
retval.extend_from_slice(&self.slice[0..amount_from_slice]);
self.slice = &self.slice[amount_from_slice..];
}
debug_assert!(retval.len() == size);
return Some(retval);
}
pub fn take_n<const N: usize>(&mut self, retention_bytes: usize) -> Option<[u8; N]> {
if self.extra_buffer.len() + self.slice.len() < N + retention_bytes {
self.extra_buffer.extend_from_slice(self.slice);
self.slice = &[];
self.continue_processing = false;
return None;
}
let mut retval = [0; N];
let amount_from_extra = min(self.extra_buffer.len(), N);
if amount_from_extra > 0 {
retval[0..amount_from_extra].copy_from_slice(&self.extra_buffer[0..amount_from_extra]);
self.extra_buffer.drain(0..amount_from_extra);
}
let amount_from_slice = N - amount_from_extra;
if amount_from_slice > 0 {
retval[amount_from_extra..N].copy_from_slice(&self.slice[0..amount_from_slice]);
self.slice = &self.slice[amount_from_slice..];
}
Some(retval)
}
}
#[test]
fn test_taking_simple() {
let mut extra = Vec::new();
let mut pb = PartialBuffer::new(&[1, 2, 3, 4], &mut extra);
let taken = pb.take(4, 0).unwrap();
assert_eq!(taken, vec![1, 2, 3, 4]);
assert_eq!(&extra[..], []);
}
#[test]
fn test_taking_simple_n() {
let mut extra = Vec::new();
let mut pb = PartialBuffer::new(&[1, 2, 3, 4], &mut extra);
let taken = pb.take_n::<4>(0).unwrap();
assert_eq!(taken, [1, 2, 3, 4]);
assert_eq!(&extra[..], []);
}
#[test]
fn test_taking_extra() {
let mut extra = Vec::new();
let mut pb = PartialBuffer::new(&[1, 2, 3, 4], &mut extra);
assert_eq!(pb.take(5, 0), None);
assert_eq!(&extra, &vec![1, 2, 3, 4]);
let mut pb = PartialBuffer::new(&[5, 6, 7, 8], &mut extra);
assert_eq!(pb.take(5, 0), Some(vec![1, 2, 3, 4, 5]));
assert_eq!(pb.take(5, 0), None);
assert!(!pb.continue_processing());
assert_eq!(&extra, &vec![6, 7, 8]);
}
#[test]
fn test_taking_extra_n() {
let mut extra = Vec::new();
let mut pb = PartialBuffer::new(&[1, 2, 3, 4], &mut extra);
assert_eq!(pb.take_n::<5>(0), None);
assert_eq!(&extra, &vec![1, 2, 3, 4]);
let mut pb = PartialBuffer::new(&[5, 6, 7, 8], &mut extra);
assert_eq!(pb.take_n::<5>(0), Some([1, 2, 3, 4, 5]));
assert_eq!(pb.take_n::<5>(0), None);
assert!(!pb.continue_processing());
assert_eq!(&extra, &vec![6, 7, 8]);
}
#[test]
fn test_taking_reserve() {
let mut extra = Vec::new();
let mut pb = PartialBuffer::new(&[1, 2, 3, 4, 5], &mut extra);
assert_eq!(pb.take(5, 1), None);
let mut pb = PartialBuffer::new(&[], &mut extra);
assert_eq!(pb.take(5, 0), Some(vec![1, 2, 3, 4, 5]));
}