use std::mem;
#[derive(Debug, Default, Clone)]
pub(crate) struct CompactBytes {
n_segments: usize,
data: Vec<u8>,
}
impl CompactBytes {
pub fn new() -> Self {
Self::default()
}
pub fn add_segment(&mut self, segment: &[u8]) {
self.data.extend_from_slice(segment);
self.data.extend_from_slice(&segment.len().to_ne_bytes());
self.n_segments += 1;
}
pub fn reverse_iter(&self) -> CompactBytesIter<'_> {
CompactBytesIter {
bytes: self,
offset_back: self.data.len(),
n_segments_left: self.n_segments,
}
}
pub fn len(&self) -> usize {
self.n_segments
}
pub fn pop_segment(&mut self) -> Option<Vec<u8>> {
if self.n_segments < 1 {
return None;
}
let length_size = mem::size_of::<usize>();
let last_segment_length = usize::from_ne_bytes(
self.data[self.data.len() - length_size..]
.try_into()
.expect("internal structure bug"),
);
let segment = self.data
[self.data.len() - last_segment_length - length_size..self.data.len() - length_size]
.to_vec();
self.data
.truncate(self.data.len() - last_segment_length - length_size);
self.n_segments -= 1;
Some(segment)
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct CompactBytesIter<'a> {
bytes: &'a CompactBytes,
offset_back: usize,
n_segments_left: usize,
}
impl<'a> Iterator for CompactBytesIter<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
if self.offset_back == 0 {
return None;
}
let length_size = mem::size_of::<usize>();
let segment_length = usize::from_ne_bytes(
self.bytes.data[self.offset_back - length_size..self.offset_back]
.try_into()
.expect("internal structure bug"),
);
self.offset_back -= length_size;
let segment = &self.bytes.data[self.offset_back - segment_length..self.offset_back];
self.offset_back -= segment_length;
self.n_segments_left -= 1;
Some(segment)
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.n_segments_left, Some(self.n_segments_left))
}
}
impl ExactSizeIterator for CompactBytesIter<'_> {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_two_dimensional_bytes() {
let bytes = CompactBytes::new();
assert_eq!(bytes.len(), 0);
let mut iter = bytes.reverse_iter();
assert_eq!(iter.next(), None);
}
#[test]
fn non_empty_two_dimensional_bytes_backward_iterator() {
let mut bytes = CompactBytes::default();
bytes.add_segment(b"ayya");
bytes.add_segment(b"ayyb");
bytes.add_segment(b"didn'texpectthat!");
bytes.add_segment(b"ayyd");
assert_eq!(bytes.len(), 4);
let mut iter = bytes.reverse_iter();
assert_eq!(iter.next(), Some(b"ayyd".as_ref()));
assert_eq!(iter.next(), Some(b"didn'texpectthat!".as_ref()));
assert_eq!(iter.len(), 2);
assert_eq!(iter.next(), Some(b"ayyb".as_ref()));
assert_eq!(iter.next(), Some(b"ayya".as_ref()));
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
assert_eq!(bytes.len(), 4);
let mut iter = bytes.reverse_iter();
assert_eq!(iter.next(), Some(b"ayyd".as_ref()));
assert_eq!(iter.len(), 3);
assert_eq!(iter.next(), Some(b"didn'texpectthat!".as_ref()));
assert_eq!(iter.next(), Some(b"ayyb".as_ref()));
assert_eq!(iter.next(), Some(b"ayya".as_ref()));
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None);
}
#[test]
fn pop_segment() {
let mut bytes = CompactBytes::default();
bytes.add_segment(b"ayya");
bytes.add_segment(b"ayyb");
bytes.add_segment(b"ayyc");
bytes.add_segment(b"ayyd");
assert_eq!(bytes.pop_segment(), Some(b"ayyd".to_vec()));
assert_eq!(bytes.pop_segment(), Some(b"ayyc".to_vec()));
let mut v: Vec<_> = bytes.reverse_iter().collect();
v.reverse();
assert_eq!(v, vec![b"ayya".to_vec(), b"ayyb".to_vec()]);
assert_eq!(bytes.pop_segment(), Some(b"ayyb".to_vec()));
assert_eq!(bytes.pop_segment(), Some(b"ayya".to_vec()));
assert_eq!(bytes.pop_segment(), None);
assert_eq!(bytes.pop_segment(), None);
}
}