1use bitvec::order::Msb0;
2use bitvec::vec::BitVec;
3use bitvec::view::BitView;
4use std::fmt::{self, Debug, Formatter};
5use std::sync::Arc;
6use thiserror::Error;
7
8#[derive(Clone)]
9pub struct BitArrayValue {
10 bytes: Arc<[u8]>,
11 byte_offset: usize,
12 bit_len: usize,
13}
14
15#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
16#[error("bit length {bit_len} exceeds the {available_bits} bits supplied")]
17pub struct BitArrayValueLengthError {
18 pub bit_len: usize,
19 pub available_bits: usize,
20}
21
22impl BitArrayValue {
23 pub fn from_bytes(bytes: Vec<u8>) -> Self {
24 let bit_len = bytes.len().saturating_mul(8);
25 Self {
26 bytes: bytes.into(),
27 byte_offset: 0,
28 bit_len,
29 }
30 }
31
32 pub fn try_from_parts(
33 bytes: Vec<u8>,
34 bit_len: usize,
35 ) -> Result<Self, BitArrayValueLengthError> {
36 let available_bits = bytes.len().saturating_mul(8);
37 if bit_len > available_bits {
38 return Err(BitArrayValueLengthError {
39 bit_len,
40 available_bits,
41 });
42 }
43
44 let mut bytes = bytes;
45 bytes.truncate(bit_len.div_ceil(8));
46 let remaining = bit_len % 8;
47 if let Some(last) = bytes.last_mut()
48 && remaining != 0
49 {
50 *last &= u8::MAX << (8 - remaining);
51 }
52 Ok(Self {
53 bytes: bytes.into(),
54 byte_offset: 0,
55 bit_len,
56 })
57 }
58
59 pub fn bytes(&self) -> &[u8] {
60 let byte_len = self.bit_len.div_ceil(8);
61 &self.bytes[self.byte_offset..self.byte_offset + byte_len]
62 }
63
64 pub fn bit_len(&self) -> usize {
65 self.bit_len
66 }
67
68 pub(crate) fn bits(&self) -> &bitvec::slice::BitSlice<u8, Msb0> {
69 &self.bytes().view_bits::<Msb0>()[..self.bit_len]
70 }
71
72 pub(crate) fn from_evaluated(mut bits: BitVec<u8, Msb0>) -> Self {
73 let bit_len = bits.len();
74 bits.force_align();
75 bits.set_uninitialized(false);
76 Self {
77 bytes: bits.into_vec().into(),
78 byte_offset: 0,
79 bit_len,
80 }
81 }
82
83 pub(crate) fn byte_slice(&self, start: usize, length: usize) -> Option<Self> {
84 if !self.bit_len.is_multiple_of(8) {
85 return None;
86 }
87 let end = start.checked_add(length)?;
88 if end > self.bit_len / 8 {
89 return None;
90 }
91 Some(Self {
92 bytes: Arc::clone(&self.bytes),
93 byte_offset: self.byte_offset + start,
94 bit_len: length * 8,
95 })
96 }
97
98 pub(crate) fn pad_to_bytes(&self) -> Self {
99 Self {
100 bytes: Arc::clone(&self.bytes),
101 byte_offset: self.byte_offset,
102 bit_len: self.bit_len.div_ceil(8) * 8,
103 }
104 }
105}
106
107impl Debug for BitArrayValue {
108 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
109 formatter
110 .debug_struct("BitArrayValue")
111 .field("bytes", &self.bytes())
112 .field("bit_len", &self.bit_len)
113 .finish()
114 }
115}
116
117impl PartialEq for BitArrayValue {
118 fn eq(&self, other: &Self) -> bool {
119 self.bits() == other.bits()
120 }
121}
122
123impl Eq for BitArrayValue {}
124
125#[cfg(test)]
126mod tests {
127 use super::{BitArrayValue, BitArrayValueLengthError};
128 use std::sync::Arc;
129
130 #[test]
131 fn aligned_bytes_preserve_all_bits() {
132 let value = BitArrayValue::from_bytes(vec![0xa5, 0xff]);
133
134 assert_eq!(value.bytes(), &[0xa5, 0xff]);
135 assert_eq!(value.bit_len(), 16);
136 }
137
138 #[test]
139 fn clones_share_the_immutable_bit_storage() {
140 let value = BitArrayValue::from_bytes(vec![0xa5]);
141 let clone = value.clone();
142
143 assert!(Arc::ptr_eq(&value.bytes, &clone.bytes));
144 assert_send_sync::<BitArrayValue>();
145 }
146
147 #[test]
148 fn checked_parts_preserve_unaligned_logical_bits() {
149 let left = BitArrayValue::try_from_parts(vec![0b1011_1111], 4)
150 .expect("four supplied bits should be valid");
151 let right = BitArrayValue::try_from_parts(vec![0b1011_0000], 4)
152 .expect("four supplied bits should be valid");
153
154 assert_eq!(left, right);
155 assert_eq!(left.bytes(), &[0b1011_0000]);
156 assert_eq!(left.bit_len(), 4);
157 }
158
159 #[test]
160 fn checked_parts_preserve_empty_and_aligned_values() {
161 assert_eq!(
162 BitArrayValue::try_from_parts(Vec::new(), 0),
163 Ok(BitArrayValue::from_bytes(Vec::new())),
164 );
165 assert_eq!(
166 BitArrayValue::try_from_parts(vec![0xa5], 8),
167 Ok(BitArrayValue::from_bytes(vec![0xa5])),
168 );
169 }
170
171 #[test]
172 fn checked_parts_reject_bit_length_beyond_supplied_bytes() {
173 assert_eq!(
174 BitArrayValue::try_from_parts(vec![0], 9),
175 Err(BitArrayValueLengthError {
176 bit_len: 9,
177 available_bits: 8,
178 }),
179 );
180 }
181
182 #[test]
183 fn byte_slices_and_padding_share_the_backing_storage() {
184 let value = BitArrayValue::from_bytes(vec![1, 2, 3, 4]);
185 let slice = value
186 .byte_slice(1, 2)
187 .expect("aligned in-bounds byte slice should exist");
188 let unaligned = BitArrayValue::try_from_parts(vec![0b1010_0000], 4)
189 .expect("four supplied bits should be valid");
190 let padded = unaligned.pad_to_bytes();
191
192 assert_eq!(slice.bytes(), &[2, 3]);
193 assert_eq!(slice.bit_len(), 16);
194 assert!(Arc::ptr_eq(&value.bytes, &slice.bytes));
195 assert_eq!(padded.bytes(), &[0b1010_0000]);
196 assert_eq!(padded.bit_len(), 8);
197 assert!(Arc::ptr_eq(&unaligned.bytes, &padded.bytes));
198 assert_eq!(unaligned.byte_slice(0, 0), None);
199 assert_eq!(value.byte_slice(usize::MAX, 1), None);
200 assert_eq!(value.byte_slice(3, 2), None);
201 }
202
203 #[test]
204 fn equality_and_debug_use_only_the_logical_range() {
205 let value = BitArrayValue::from_bytes(vec![1, 2, 3]);
206 let slice = value
207 .byte_slice(1, 1)
208 .expect("middle byte should be sliceable");
209
210 assert_eq!(slice, BitArrayValue::from_bytes(vec![2]));
211 assert_eq!(
212 format!("{slice:?}"),
213 "BitArrayValue { bytes: [2], bit_len: 8 }",
214 );
215 }
216
217 fn assert_send_sync<Value: Send + Sync>() {}
218}