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