network_types/
bitfield.rs1#[repr(C)]
7#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
8#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
9#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
10pub struct BitfieldU16 {
11 storage: [u8; 2],
12}
13
14impl BitfieldU16 {
15 #[inline]
16 pub const fn new(storage: [u8; 2]) -> Self {
17 Self { storage }
18 }
19
20 #[inline]
21 pub fn get_bit(&self, index: usize) -> bool {
22 debug_assert!(index / 8 < self.storage.as_ref().len());
23
24 let byte_index = index / 8;
25 let byte = self.storage.as_ref()[byte_index];
26
27 let bit_index = if cfg!(target_endian = "big") {
28 7 - (index % 8)
29 } else {
30 index % 8
31 };
32
33 let mask = 1 << bit_index;
34
35 byte & mask == mask
36 }
37
38 #[inline]
39 pub fn set_bit(&mut self, index: usize, val: bool) {
40 debug_assert!(index / 8 < self.storage.as_ref().len());
41
42 let byte_index = index / 8;
43 let byte = &mut self.storage.as_mut()[byte_index];
44
45 let bit_index = if cfg!(target_endian = "big") {
46 7 - (index % 8)
47 } else {
48 index % 8
49 };
50
51 let mask = 1 << bit_index;
52 if val {
53 *byte |= mask;
54 } else {
55 *byte &= !mask;
56 }
57 }
58
59 #[inline]
60 pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
61 debug_assert!(bit_width <= 64);
62 debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
63 debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
64
65 let mut val = 0;
66
67 for i in 0..(bit_width as usize) {
68 if self.get_bit(i + bit_offset) {
69 let index = if cfg!(target_endian = "big") {
70 bit_width as usize - 1 - i
71 } else {
72 i
73 };
74 val |= 1 << index;
75 }
76 }
77
78 val
79 }
80
81 #[inline]
82 pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
83 debug_assert!(bit_width <= 64);
84 debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
85 debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
86
87 for i in 0..(bit_width as usize) {
88 let mask = 1 << i;
89 let val_bit_is_set = val & mask == mask;
90 let index = if cfg!(target_endian = "big") {
91 bit_width as usize - 1 - i
92 } else {
93 i
94 };
95 self.set_bit(index + bit_offset, val_bit_is_set);
96 }
97 }
98}
99
100#[cfg(all(test, feature = "wincode"))]
101mod wincode_prop_tests {
102 use super::*;
103 use core::mem;
104 use proptest::prelude::*;
105 use proptest::test_runner::Config as ProptestConfig;
106
107 fn round_trip(unit: &BitfieldU16) -> BitfieldU16 {
108 let mut buf = [0u8; mem::size_of::<BitfieldU16>()];
109 wincode::serialize_into(buf.as_mut_slice(), unit).unwrap();
110 wincode::deserialize(&buf).unwrap()
111 }
112
113 proptest! {
114 #![proptest_config(ProptestConfig {
115 failure_persistence: None,
116 ..ProptestConfig::default()
117 })]
118
119 #[test]
120 fn bitfield_unit_round_trip(initial in proptest::array::uniform2(any::<u8>())) {
121 let mut unit = BitfieldU16::new(initial);
122 let bit = (initial[0] as usize) % (initial.len() * 8);
123 unit.set_bit(bit, true);
124
125 let via_wincode = round_trip(&unit);
126 prop_assert_eq!(via_wincode.storage, unit.storage);
127 }
128 }
129}