1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
// Re-export libcore using an alias so that the macros can work without
// requiring `extern crate core` downstream.
#[doc(hidden)]
pub extern crate core as _core;

/// Implements an arbitrary-length bitfield.  The implementation and interface is similar to and
/// derived from [bitflags](https://crates.io/crates/bitflags).
///
/// Instead of implementing the bitfield over an integral type, this implements it on an array of
/// bytes.  Each flag is defined using the byte and the mask _within that byte_.  It does not
/// support masks across bytes.
///
/// # Example
///
/// See [`ChannelClassification`] and [`event::command::CommandFlags`] for examples in this crate.
///
/// Basic usage is similar to [bitflags](https://crates.io/crates/bitflags):
///
/// ```
/// # #[macro_use]
/// # extern crate bluetooth_hci;
/// # fn main() {}
/// bitflag_array! {
///     #[derive(Clone)]
///     pub struct Flags : 3; // Bit field over a [u8; 3]
///     pub struct Flag;      // Name the internal struct
///
///     const ALPHA = 0, 0x01; // First byte, first bit
///     const BETA = 0, 0x02;
///     // ...
///     const THETA = 1, 0x01; // Second byte, first bit
///     // ...
///     const OMEGA = 2, 0x80; // Third byte, last bit
/// }
/// ```
///
/// A subset of the bitflags interface is implemented, including bitwise OR operations:
/// ```
/// # #[macro_use]
/// # extern crate bluetooth_hci;
/// # bitflag_array! {
/// #    #[derive(Clone)]
/// #    pub struct Flags : 3;
/// #    pub struct Flag;
/// #
/// #    const ALPHA = 0, 0x01;
/// #    const BETA = 0, 0x02;
/// #    const THETA = 1, 0x01;
/// #    const OMEGA = 2, 0x80;
/// # }
/// # fn main() {
/// let mut letters = Flags::ALPHA | Flags::BETA;
/// letters |= Flags::THETA;
/// assert_eq!(letters.bits(), [0x03, 0x01, 0x00]);
/// assert_eq!(letters.is_empty(), false);
/// assert_eq!(letters.is_set(Flags::OMEGA), false);
/// assert!(letters.contains(Flags::BETA | Flags::THETA));
/// # }
/// ```
macro_rules! bitflag_array {
    {
        $(#[$inner:ident $($args:tt)*])*
        pub struct $flags:ident : $size:expr;
        pub struct $flag:ident;

        $(
            $(#[$var_inner:ident $($var_args:tt)*])*
            const $var:ident = $octet:expr, $mask:expr;
        )+
    } => {
        $(#[$inner $($args)*])*
        pub struct $flags([u8; $size]);

        #[doc(hidden)]
        #[allow(missing_docs)]
        #[derive(Copy, Clone, Debug)]
        pub struct $flag {
            octet: usize,
            mask: u8,
        }

        impl $flags {
            $(
                $(#[$var_inner $($var_args)*])*
                pub const $var: $flag = $flag {
                    octet: $octet,
                    mask: $mask,
                };
            )+

            /// Attempts to create a bit field from the given byte array.  If any unknown bit is
            /// set, returns None.
            pub fn from_bits(bits: &[u8]) -> Option<$flags> {
                assert_eq!(bits.len(), $size);

                let all_flags = $flags::all();
                let all_bits = all_flags.bits();
                for i in 0..$size {
                    let provided_bits = bits[i];
                    let allowed_bits = all_bits[i];
                    if (provided_bits & !allowed_bits) != 0 {
                        return None;
                    }
                }

                let mut flags = $flags([0; $size]);
                flags.0.copy_from_slice(bits);
                Some(flags)
            }

            /// Copies the bitfield array into the given slice.  The slice must have exactly the
            /// right number of elements.
            pub fn into_bytes(&self, bytes: &mut [u8]) {
                assert_eq!(self.0.len(), bytes.len());
                bytes.copy_from_slice(&self.0);
            }

            /// Returns a bit field with all flags set.
            #[allow(deprecated)]
            #[allow(unused_doc_comments)]
            #[allow(unused_attributes)]
            pub fn all() -> $flags {
                let mut bits = [0; $size];
                $(
                    $(#[$var_inner $($var_args)*])*
                    {
                        bits[$octet] |= $mask;
                    }
                )+
                $flags(bits)
            }

            /// Returns a bit field with no flags set.
            pub fn empty() -> $flags {
                $flags([0; $size])
            }

            /// Returns a slice to the underlying representation of the bit field.
            pub fn bits(&self) -> &[u8] {
                &self.0
            }

            /// Returns true if no fields are set.
            pub fn is_empty(&self) -> bool {
                self.0.iter().all(|&x| x == 0)
            }

            /// Returns true if the flag is set in the bitfield.
            pub fn is_set(&self, flag: $flag) -> bool {
                (self.0[flag.octet] & flag.mask) != 0
            }

            /// Returns true if all flags from `flags` are set in the bitfield.
            pub fn contains(&self, flags: $flags) -> bool {
                self.0
                    .iter()
                    .zip(flags.0.iter())
                    .all(|(a, b)| (a & b) == *b)
            }
        }

        impl $crate::bitflag_array::_core::ops::BitOr for $flag {
            type Output = $flags;

            fn bitor(self, rhs: $flag) -> Self::Output {
                let mut flags = $flags([0; $size]);
                flags.0[self.octet] |= self.mask;
                flags.0[rhs.octet] |= rhs.mask;

                flags
            }
        }

        impl $crate::bitflag_array::_core::ops::BitOr<$flag> for $flags {
            type Output = $flags;

            fn bitor(mut self, rhs: $flag) -> Self::Output {
                self |= rhs;

                self
            }
        }

        impl $crate::bitflag_array::_core::ops::BitOrAssign<$flag> for $flags {
            fn bitor_assign(&mut self, rhs: $flag) {
                self.0[rhs.octet] |= rhs.mask;
            }
        }

        impl $crate::bitflag_array::_core::cmp::PartialEq<$flag> for $flags {
            fn eq(&self, rhs: &$flag) -> bool {
                for i in 0..$size {
                    if i == rhs.octet as usize {
                        if self.0[i] != rhs.mask {
                            return false;
                        }
                    } else if self.0[i] != 0 {
                        return false;
                    }
                }

                return true;
            }
        }

        impl $crate::bitflag_array::_core::cmp::PartialEq for $flags {
            fn eq(&self, rhs: &$flags) -> bool {
                self.0.iter().zip(rhs.0.iter()).all(|(a, b)| a == b)
            }
        }

        impl $crate::bitflag_array::_core::convert::From<$flag> for $flags {
            fn from(value: $flag) -> $flags {
                let mut flags = $flags([0; $size]);
                flags.0[value.octet] = value.mask;

                flags
            }
        }
    }
}