split_buffer/
lib.rs

1#[derive(Clone)]
2pub struct Buffer(Vec<u8>);
3
4impl Buffer {
5    /// Build a buffer from parts that resolve to a slice of byte slices.
6    ///
7    /// A size hint will be calculated from the parts to preallocate the buffer.
8    pub fn build<T: AsRef<[U]>, U: AsRef<[u8]>>(parts: T) -> Self {
9        let parts = parts.as_ref();
10        let parts_len = parts.len();
11        let bytes_total = parts.into_iter().fold(0usize, |acc, part| acc + part.as_ref().len());
12        Self::build_with_size_hint(parts, (parts_len * std::mem::size_of::<usize>()) + bytes_total)
13    }
14
15    /// Build a buffer from parts that resolve to a slice of byte slices.
16    pub fn build_with_size_hint<T: AsRef<[U]>, U: AsRef<[u8]>>(parts: T, size_hint: usize) -> Self {
17        let parts = parts.as_ref();
18
19        let mut buffer = Vec::with_capacity(size_hint);
20
21        for part in parts {
22            let part = part.as_ref();
23            let part_len = part.len();
24            buffer.extend_from_slice(&part_len.to_le_bytes());
25            buffer.extend_from_slice(part);
26        }
27
28        buffer.shrink_to_fit();
29
30        Buffer(buffer)
31    }
32
33    /// Get the inner `Vec<u8>`
34    pub fn into_inner(self) -> Vec<u8> {
35        self.0
36    }
37}
38
39/// Iterator over parts of a `Buffer`
40pub struct BufferIterator<'a> {
41    buffer: &'a [u8],
42    offset: usize,
43}
44
45impl<'a> IntoIterator for &'a Buffer {
46    type Item = &'a [u8];
47    type IntoIter = BufferIterator<'a>;
48
49    fn into_iter(self) -> Self::IntoIter {
50        BufferIterator { buffer: &self.0, offset: 0 }
51    }
52}
53
54impl<'a> Iterator for BufferIterator<'a> {
55    type Item = &'a [u8];
56    fn next(&mut self) -> Option<Self::Item> {
57        use std::convert::TryInto;
58
59        if self.buffer[self.offset..].is_empty() {
60            return None;
61        }
62
63        let bytes_start = self.offset + std::mem::size_of::<usize>();
64        let len = usize::from_le_bytes(
65            self.buffer[self.offset..bytes_start].try_into().expect("Must be `usize`"),
66        ) as usize;
67        self.offset = bytes_start + len;
68
69        Some(&self.buffer[bytes_start..self.offset])
70    }
71}