bits_io/buf/
bit_buf.rs

1use crate::prelude::*;
2
3use super::{chain::Chain, take::Take};
4
5pub trait BitBuf {
6    /// Advance the internal cursor of the `BitBuf` by `count` bits.
7    ///
8    /// The next call to chunk() will return a slice starting count bits further into the
9    /// underlying buffer.
10    fn advance_bits(&mut self, count: usize);
11
12    /// Advance the internal cursor of the `BitBuf` by `count` bytes.
13    ///
14    /// The next call to chunk() will return a slice starting count bytes further into the
15    /// underlying buffer.
16    fn advance_bytes(&mut self, count: usize) {
17        self.advance_bits(count * 8)
18    }
19
20    /// Returns the number of bits between the current position and the end of the buffer.
21    ///
22    /// This value is greater than or equal to the length of the slice returned by `chunk`.
23    fn remaining_bits(&self) -> usize;
24
25    ///  Return the number of _full_ bytes between the current position and the end of the buffer.
26    fn remaining_bytes(&self) -> usize {
27        self.remaining_bits() / 8
28    }
29
30    /// Returns true if there are any more bits to consume.
31    ///
32    /// This is equivalent to `self.remaining_bits() > 0`
33    fn has_remaining_bits(&self) -> bool {
34        self.remaining_bits() > 0
35    }
36
37    /// Returns true if there are any more cmplete bytes to consume.
38    ///
39    /// This is equivalent to `self.remaining_bytes() > 0`
40    fn has_remaining_bytes(&self) -> bool {
41        self.remaining_bytes() > 0
42    }
43
44    /// Creates an adaptor which will chain this buffer to another.
45    ///
46    /// The returned `BitBuf` instance will first consume all data from `self`.  Afterwards the
47    /// output is equivalent to the output of `next`.
48    fn chain<U: BitBuf>(self, next: U) -> Chain<Self, U>
49    where
50        Self: Sized,
51    {
52        Chain::new(self, next)
53    }
54
55    /// Returns a [`BitSlice`] starting at the current position and of length between 0 and
56    /// `BitBuf::remaining`.  Note that this _can_ return a shorter slice.
57    fn chunk_bits(&self) -> &BitSlice;
58
59    /// Returns a slice of bytes starting at the current position and of length between 0 and
60    /// `BitBuf::remaining_bytes`.  Note that this _can_ return a shorter slice.
61    fn chunk_bytes(&self) -> &[u8];
62
63    /// Copy bits from `self` into `dest`.
64    ///
65    /// The cursor is advanced by the number of bits copied.  `self` must have enough remaining
66    /// bits to fill `dest`.
67    fn copy_to_bit_slice(&mut self, dest: &mut BitSlice) {
68        self.try_copy_to_bit_slice(dest).unwrap()
69    }
70
71    fn try_copy_to_bit_slice(&mut self, mut dest: &mut BitSlice) -> std::io::Result<()> {
72        if self.remaining_bits() < dest.len() {
73            return Err(std::io::Error::new(
74                std::io::ErrorKind::UnexpectedEof,
75                format!(
76                    "Remaining bytes ({}) are less than the size of the dest ({})",
77                    self.remaining_bytes(),
78                    dest.len()
79                ),
80            ));
81        }
82
83        while !dest.is_empty() {
84            let src = self.chunk_bits();
85            let count = usize::min(src.len(), dest.len());
86            dest[..count].copy_from_bitslice(&src[..count]);
87
88            dest = &mut dest[count..];
89
90            self.advance_bits(count);
91        }
92
93        Ok(())
94    }
95
96    /// Copy bytes from `self` into `dest`.  Call should call `byte_aligned()` beforehand to ensure
97    /// buffer is fully byte-aligned before calling, call may panic if buffer isn't byte-aligned.
98    ///
99    /// The cursor is advanced by the number of bytes copied.  `self` must have enough remaining
100    /// bytes to fill `dest`.
101    fn copy_to_slice_bytes(&mut self, dest: &mut [u8]) {
102        self.try_copy_to_slice_bytes(dest).unwrap()
103    }
104
105    /// Try to copy bytes from `self` into `dest`.  Returns error if `self` is not big enough to
106    /// fill `dest` or if self is not fully byte-aligned (start and end points both falling on byte
107    /// boundaries).
108    fn try_copy_to_slice_bytes(&mut self, mut dest: &mut [u8]) -> std::io::Result<()> {
109        if !self.byte_aligned() {
110            return Err(std::io::Error::new(
111                std::io::ErrorKind::InvalidData,
112                "Buf beginning and end must both be byte-aligned",
113            ));
114        }
115        if self.remaining_bytes() < dest.len() {
116            return Err(std::io::Error::new(
117                std::io::ErrorKind::UnexpectedEof,
118                format!(
119                    "Remaining bytes ({}) are less than the size of the dest ({})",
120                    self.remaining_bytes(),
121                    dest.len()
122                ),
123            ));
124        }
125        while !dest.is_empty() {
126            let src = self.chunk_bytes();
127            let count = usize::min(src.len(), dest.len());
128            dest[..count].copy_from_slice(&src[..count]);
129            dest = &mut dest[count..];
130
131            self.advance_bytes(count);
132        }
133
134        Ok(())
135    }
136
137    /// Create an adaptor which can read at most `limit` bits from `self`.
138    fn take_bits(self, limit: usize) -> Take<Self>
139    where
140        Self: Sized,
141    {
142        Take::new(self, limit)
143    }
144
145    /// Create an adaptor which can read at most `limit` bytes from `self`.
146    fn take_bytes(self, limit: usize) -> Take<Self>
147    where
148        Self: Sized,
149    {
150        Take::new(self, limit * 8)
151    }
152
153    /// Returns whether or not this `BitBuf` is fully byte-aligned (beginning and end) with the
154    /// underlying storage.
155    fn byte_aligned(&self) -> bool;
156}