stm32wb_hci/bitflag_array.rs
1//! Implements an arbitrary-length bitfield. The implementation and interface is similar to and
2//! derived from [bitflags](https://crates.io/crates/bitflags).
3
4// Re-export libcore using an alias so that the macros can work without
5// requiring `extern crate core` downstream.
6#[doc(hidden)]
7pub extern crate core as _core;
8
9/// Implements an arbitrary-length bitfield. The implementation and interface is similar to and
10/// derived from [bitflags](https://crates.io/crates/bitflags).
11///
12/// Instead of implementing the bitfield over an integral type, this implements it on an array of
13/// bytes. Each flag is defined using the byte and the mask _within that byte_. It does not
14/// support masks across bytes.
15///
16/// # Example
17///
18/// See [`ChannelClassification`] and [`event::command::CommandFlags`] for examples in this crate.
19///
20/// Basic usage is similar to [bitflags](https://crates.io/crates/bitflags):
21///
22/// ```
23/// # #[macro_use]
24/// # extern crate stm32wb_hci as hci;
25/// # fn main() {}
26/// bitflag_array! {
27/// #[derive(Clone)]
28/// pub struct Flags : 3; // Bit field over a [u8; 3]
29/// pub struct Flag; // Name the internal struct
30///
31/// const ALPHA = 0, 0x01; // First byte, first bit
32/// const BETA = 0, 0x02;
33/// // ...
34/// const THETA = 1, 0x01; // Second byte, first bit
35/// // ...
36/// const OMEGA = 2, 0x80; // Third byte, last bit
37/// }
38/// ```
39///
40/// A subset of the bitflags interface is implemented, including bitwise OR operations:
41/// ```
42/// # #[macro_use]
43/// # extern crate stm32wb_hci as hci;
44/// # bitflag_array! {
45/// # #[derive(Clone)]
46/// # pub struct Flags : 3;
47/// # pub struct Flag;
48/// #
49/// # const ALPHA = 0, 0x01;
50/// # const BETA = 0, 0x02;
51/// # const THETA = 1, 0x01;
52/// # const OMEGA = 2, 0x80;
53/// # }
54/// # fn main() {
55/// let mut letters = Flags::ALPHA | Flags::BETA;
56/// letters |= Flags::THETA;
57/// assert_eq!(letters.bits(), [0x03, 0x01, 0x00]);
58/// assert_eq!(letters.is_empty(), false);
59/// assert_eq!(letters.is_set(Flags::OMEGA), false);
60/// assert!(letters.contains(Flags::BETA | Flags::THETA));
61/// # }
62/// ```
63#[macro_export]
64macro_rules! bitflag_array {
65 {
66 $(#[$inner:ident $($args:tt)*])*
67 pub struct $flags:ident : $size:expr;
68 pub struct $flag:ident;
69
70 $(
71 $(#[$var_inner:ident $($var_args:tt)*])*
72 const $var:ident = $octet:expr, $mask:expr;
73 )+
74 } => {
75 $(#[$inner $($args)*])*
76 pub struct $flags([u8; $size]);
77
78 #[doc(hidden)]
79 #[allow(missing_docs)]
80 #[derive(Copy, Clone, Debug)]
81 pub struct $flag {
82 octet: usize,
83 mask: u8,
84 }
85
86 impl $flags {
87 $(
88 $(#[$var_inner $($var_args)*])*
89 pub const $var: $flag = $flag {
90 octet: $octet,
91 mask: $mask,
92 };
93 )+
94
95 /// Attempts to create a bit field from the given byte array. If any unknown bit is
96 /// set, returns None.
97 pub fn from_bits(bits: &[u8]) -> Option<$flags> {
98 assert_eq!(bits.len(), $size);
99
100 let all_flags = $flags::all();
101 let all_bits = all_flags.bits();
102 for i in 0..$size {
103 let provided_bits = bits[i];
104 let allowed_bits = all_bits[i];
105 if (provided_bits & !allowed_bits) != 0 {
106 return None;
107 }
108 }
109
110 let mut flags = $flags([0; $size]);
111 flags.0.copy_from_slice(bits);
112 Some(flags)
113 }
114
115 /// Copies the bitfield array into the given slice. The slice must have exactly the
116 /// right number of elements.
117 pub fn copy_into_slice(&self, bytes: &mut [u8]) {
118 assert_eq!(self.0.len(), bytes.len());
119 bytes.copy_from_slice(&self.0);
120 }
121
122 /// Returns a bit field with all flags set.
123 #[allow(deprecated)]
124 #[allow(unused_doc_comments)]
125 #[allow(unused_attributes)]
126 pub fn all() -> $flags {
127 let mut bits = [0; $size];
128 $(
129 $(#[$var_inner $($var_args)*])*
130 {
131 bits[$octet] |= $mask;
132 }
133 )+
134 $flags(bits)
135 }
136
137 /// Returns a bit field with no flags set.
138 pub fn empty() -> $flags {
139 $flags([0; $size])
140 }
141
142 /// Returns a slice to the underlying representation of the bit field.
143 pub fn bits(&self) -> &[u8] {
144 &self.0
145 }
146
147 /// Returns true if no fields are set.
148 pub fn is_empty(&self) -> bool {
149 self.0.iter().all(|&x| x == 0)
150 }
151
152 /// Returns true if the flag is set in the bitfield.
153 pub fn is_set(&self, flag: $flag) -> bool {
154 (self.0[flag.octet] & flag.mask) != 0
155 }
156
157 /// Returns true if all flags from `flags` are set in the bitfield.
158 pub fn contains(&self, flags: $flags) -> bool {
159 self.0
160 .iter()
161 .zip(flags.0.iter())
162 .all(|(a, b)| (a & b) == *b)
163 }
164 }
165
166 impl $crate::bitflag_array::_core::ops::BitOr for $flag {
167 type Output = $flags;
168
169 fn bitor(self, rhs: $flag) -> Self::Output {
170 let mut flags = $flags([0; $size]);
171 flags.0[self.octet] |= self.mask;
172 flags.0[rhs.octet] |= rhs.mask;
173
174 flags
175 }
176 }
177
178 impl $crate::bitflag_array::_core::ops::BitOr<$flag> for $flags {
179 type Output = $flags;
180
181 fn bitor(mut self, rhs: $flag) -> Self::Output {
182 self |= rhs;
183
184 self
185 }
186 }
187
188 impl $crate::bitflag_array::_core::ops::BitOrAssign<$flag> for $flags {
189 fn bitor_assign(&mut self, rhs: $flag) {
190 self.0[rhs.octet] |= rhs.mask;
191 }
192 }
193
194 impl $crate::bitflag_array::_core::cmp::PartialEq<$flag> for $flags {
195 fn eq(&self, rhs: &$flag) -> bool {
196 for i in 0..$size {
197 if i == rhs.octet as usize {
198 if self.0[i] != rhs.mask {
199 return false;
200 }
201 } else if self.0[i] != 0 {
202 return false;
203 }
204 }
205
206 return true;
207 }
208 }
209
210 impl $crate::bitflag_array::_core::cmp::PartialEq for $flags {
211 fn eq(&self, rhs: &$flags) -> bool {
212 self.0.iter().zip(rhs.0.iter()).all(|(a, b)| a == b)
213 }
214 }
215
216 impl $crate::bitflag_array::_core::convert::From<$flag> for $flags {
217 fn from(value: $flag) -> $flags {
218 let mut flags = $flags([0; $size]);
219 flags.0[value.octet] = value.mask;
220
221 flags
222 }
223 }
224 }
225}