resol_vbus/
blob_buffer.rs

1use std::{
2    io,
3    ops::{Deref, Index},
4    slice::SliceIndex,
5};
6
7/// A size-adating buffer to store bytes in. The buffer grows when data is
8/// stored into it. The contents can then be consumed which results in
9/// the buffer dropping the consumed data before new data are appended.
10#[derive(Clone, Debug, Default)]
11pub struct BlobBuffer {
12    buf: Vec<u8>,
13    start: usize,
14    offset: usize,
15}
16
17impl BlobBuffer {
18    /// Constructs a new `BlobBuffer`.
19    pub fn new() -> BlobBuffer {
20        BlobBuffer::default()
21    }
22
23    /// Provide additional data to the internal buffer.
24    pub fn extend_from_slice(&mut self, data: &[u8]) {
25        if self.start > 0 {
26            drop(self.buf.drain(0..self.start));
27            self.start = 0;
28        }
29
30        self.buf.extend_from_slice(data);
31    }
32
33    /// Consume the given amount of data from the internal buffer.
34    pub fn consume(&mut self, length: usize) {
35        self.start += length;
36        self.offset += length;
37    }
38
39    /// Returns the unconsumed byte length of the internal buffer.
40    pub fn len(&self) -> usize {
41        self.buf.len() - self.start
42    }
43
44    /// Returns whether the internal buffer is empty.
45    pub fn is_empty(&self) -> bool {
46        self.buf.len() == self.start
47    }
48
49    /// Get amount of already consumed bytes.
50    pub fn offset(&self) -> usize {
51        self.offset
52    }
53}
54
55impl Deref for BlobBuffer {
56    type Target = [u8];
57
58    fn deref(&self) -> &[u8] {
59        &self.buf[self.start..]
60    }
61}
62
63impl<I> Index<I> for BlobBuffer
64where
65    I: SliceIndex<[u8]>,
66{
67    type Output = I::Output;
68
69    fn index(&self, index: I) -> &Self::Output {
70        &self.deref()[index]
71    }
72}
73
74impl io::Read for BlobBuffer {
75    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
76        let src_len = self.len();
77        let dst_len = buf.len();
78        let len = if src_len < dst_len { src_len } else { dst_len };
79        buf[0..len].copy_from_slice(&self[0..len]);
80        self.consume(len);
81        Ok(len)
82    }
83}
84
85impl io::Write for BlobBuffer {
86    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
87        self.extend_from_slice(buf);
88        Ok(buf.len())
89    }
90
91    fn flush(&mut self) -> io::Result<()> {
92        // nop
93        Ok(())
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn test() {
103        let mut bb = BlobBuffer::new();
104
105        assert_eq!(0, bb.buf.len());
106        assert_eq!(0, bb.start);
107        assert_eq!(0, bb.offset);
108        assert_eq!(0, bb.len());
109        assert_eq!(true, bb.is_empty());
110
111        bb.extend_from_slice(&[0x00, 0x01, 0x02, 0x03]);
112
113        assert_eq!(4, bb.buf.len());
114        assert_eq!(0, bb.start);
115        assert_eq!(0, bb.offset);
116        assert_eq!(4, bb.len());
117        assert_eq!(false, bb.is_empty());
118        assert_eq!(&[0x00, 0x01, 0x02, 0x03], &*bb);
119
120        bb.consume(2);
121
122        assert_eq!(4, bb.buf.len());
123        assert_eq!(2, bb.start);
124        assert_eq!(2, bb.offset);
125        assert_eq!(2, bb.len());
126        assert_eq!(false, bb.is_empty());
127        assert_eq!(&[0x02, 0x03], &*bb);
128
129        bb.consume(1);
130
131        assert_eq!(4, bb.buf.len());
132        assert_eq!(3, bb.start);
133        assert_eq!(3, bb.offset);
134        assert_eq!(1, bb.len());
135        assert_eq!(false, bb.is_empty());
136        assert_eq!(&[0x03], &*bb);
137
138        bb.extend_from_slice(&[0x04, 0x05, 0x06, 0x07]);
139
140        assert_eq!(5, bb.buf.len());
141        assert_eq!(0, bb.start);
142        assert_eq!(3, bb.offset);
143        assert_eq!(5, bb.len());
144        assert_eq!(false, bb.is_empty());
145        assert_eq!(&[0x03, 0x04, 0x05, 0x06, 0x07], &*bb);
146
147        // Deref trait impl
148        assert_eq!(&[0x03, 0x04, 0x05, 0x06, 0x07], &(*bb));
149
150        // Index trait impl
151        assert_eq!(0x05, bb[2]);
152        assert_eq!(&[0x05, 0x06], &bb[2..4]);
153    }
154}