steel_utils/codec/
bit_set.rs1use std::io::{Cursor, Result, Write};
2
3use crate::serial::{PrefixedRead, PrefixedWrite, ReadFrom, WriteTo};
4
5use super::VarInt;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct BitSet(pub Box<[u64]>);
10
11impl BitSet {
12 pub fn set(&mut self, index: usize, value: bool) {
14 let u64_index = index / 64;
15 let bit_index = index % 64;
16
17 if u64_index >= self.0.len() {
18 return;
19 }
20
21 if value {
22 self.0[u64_index] |= 1 << bit_index;
23 } else {
24 self.0[u64_index] &= !(1 << bit_index);
25 }
26 }
27}
28
29impl ReadFrom for BitSet {
30 fn read(data: &mut Cursor<&[u8]>) -> Result<Self> {
32 let bytes = Vec::<u8>::read_prefixed::<VarInt>(data)?;
33 let mut words = vec![0_u64; bytes.len().div_ceil(8)];
34 for (index, byte) in bytes.iter().enumerate() {
35 words[index / 8] |= u64::from(*byte) << ((index % 8) * 8);
36 }
37 Ok(Self(words.into_boxed_slice()))
38 }
39}
40
41impl WriteTo for BitSet {
42 fn write(&self, writer: &mut impl Write) -> Result<()> {
46 let mut bytes = Vec::with_capacity(self.0.len() * 8);
47 for word in &self.0 {
48 bytes.extend_from_slice(&word.to_le_bytes());
49 }
50 let trimmed_len = bytes.iter().rposition(|&b| b != 0).map_or(0, |i| i + 1);
51 bytes.truncate(trimmed_len);
52 bytes.write_prefixed::<VarInt>(writer)
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use crate::serial::WriteTo;
59
60 use super::BitSet;
61
62 #[test]
63 fn write_trims_empty_bit_set_to_zero_bytes() {
64 let bit_set = BitSet(vec![0].into_boxed_slice());
65 let mut data = Vec::new();
66
67 bit_set.write(&mut data).expect("bit set should encode");
68
69 assert_eq!(data, vec![0]);
70 }
71
72 #[test]
73 fn write_trims_to_last_non_zero_byte_little_endian() {
74 let bit_set = BitSet(vec![5, 0, 7, 0, 0].into_boxed_slice());
75 let mut data = Vec::new();
76
77 bit_set.write(&mut data).expect("bit set should encode");
78
79 let expected = vec![17_u8, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7];
82 assert_eq!(data, expected);
83 }
84
85 #[test]
86 fn round_trips_through_read() {
87 use std::io::Cursor;
88
89 use crate::serial::ReadFrom;
90
91 let bit_set =
92 BitSet(vec![0x0102_0304_0506_0708, 0, 0x0000_0000_0000_00ff].into_boxed_slice());
93 let mut data = Vec::new();
94 bit_set.write(&mut data).expect("bit set should encode");
95
96 let mut cursor = Cursor::new(data.as_slice());
97 let read_back = BitSet::read(&mut cursor).expect("bit set should decode");
98
99 assert_eq!(read_back.0.as_ref(), bit_set.0.as_ref());
100 }
101}