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}