Skip to main content

geam_core/runtime/value/
bit_array.rs

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}