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}