use std::mem;
#[derive(Debug, Default)]
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
}
}
#[derive(Debug, Clone)]
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);
}
}