Skip to main content

kernel/
impl_flags.rs

1// SPDX-License-Identifier: GPL-2.0
2
3//! Bitflag type generator.
4
5/// Common helper for declaring bitflag and bitmask types.
6///
7/// This macro takes as input:
8/// - A struct declaration representing a bitmask type
9///   (e.g., `pub struct Permissions(u32)`).
10/// - An enumeration declaration representing individual bit flags
11///   (e.g., `pub enum Permission { ... }`).
12///
13/// And generates:
14/// - The struct and enum types with appropriate `#[repr]` attributes.
15/// - Implementations of common bitflag operators
16///   ([`::core::ops::BitOr`], [`::core::ops::BitAnd`], etc.).
17/// - Utility methods such as `.contains()` to check flags.
18///
19/// # Examples
20///
21/// ```
22/// use kernel::impl_flags;
23///
24/// impl_flags!(
25///     /// Represents multiple permissions.
26///     #[derive(Debug, Clone, Default, Copy, PartialEq, Eq)]
27///     pub struct Permissions(u32);
28///
29///     /// Represents a single permission.
30///     #[derive(Debug, Clone, Copy, PartialEq, Eq)]
31///     pub enum Permission {
32///         /// Read permission.
33///         Read = 1 << 0,
34///
35///         /// Write permission.
36///         Write = 1 << 1,
37///
38///         /// Execute permission.
39///         Execute = 1 << 2,
40///     }
41/// );
42///
43/// // Combine multiple permissions using the bitwise OR (`|`) operator.
44/// let mut read_write: Permissions = Permission::Read | Permission::Write;
45/// assert!(read_write.contains(Permission::Read));
46/// assert!(read_write.contains(Permission::Write));
47/// assert!(!read_write.contains(Permission::Execute));
48/// assert!(read_write.contains_any(Permission::Read | Permission::Execute));
49/// assert!(read_write.contains_all(Permission::Read | Permission::Write));
50///
51/// // Using the bitwise OR assignment (`|=`) operator.
52/// read_write |= Permission::Execute;
53/// assert!(read_write.contains(Permission::Execute));
54///
55/// // Masking a permission with the bitwise AND (`&`) operator.
56/// let read_only: Permissions = read_write & Permission::Read;
57/// assert!(read_only.contains(Permission::Read));
58/// assert!(!read_only.contains(Permission::Write));
59///
60/// // Toggling permissions with the bitwise XOR (`^`) operator.
61/// let toggled: Permissions = read_only ^ Permission::Read;
62/// assert!(!toggled.contains(Permission::Read));
63///
64/// // Inverting permissions with the bitwise NOT (`!`) operator.
65/// let negated = !read_only;
66/// assert!(negated.contains(Permission::Write));
67/// assert!(!negated.contains(Permission::Read));
68/// ```
69#[macro_export]
70macro_rules! impl_flags {
71    (
72        $(#[$outer_flags:meta])*
73        $vis_flags:vis struct $flags:ident($ty:ty);
74
75        $(#[$outer_flag:meta])*
76        $vis_flag:vis enum $flag:ident {
77            $(
78                $(#[$inner_flag:meta])*
79                $name:ident = $value:expr
80            ),+ $( , )?
81        }
82    ) => {
83        $(#[$outer_flags])*
84        #[repr(transparent)]
85        $vis_flags struct $flags($ty);
86
87        $(#[$outer_flag])*
88        #[repr($ty)]
89        $vis_flag enum $flag {
90            $(
91                $(#[$inner_flag])*
92                $name = $value
93            ),+
94        }
95
96        impl ::core::convert::From<$flag> for $flags {
97            #[inline]
98            fn from(value: $flag) -> Self {
99                Self(value as $ty)
100            }
101        }
102
103        impl ::core::convert::From<$flags> for $ty {
104            #[inline]
105            fn from(value: $flags) -> Self {
106                value.0
107            }
108        }
109
110        impl ::core::ops::BitOr for $flags {
111            type Output = Self;
112            #[inline]
113            fn bitor(self, rhs: Self) -> Self::Output {
114                Self(self.0 | rhs.0)
115            }
116        }
117
118        impl ::core::ops::BitOrAssign for $flags {
119            #[inline]
120            fn bitor_assign(&mut self, rhs: Self) {
121                *self = *self | rhs;
122            }
123        }
124
125        impl ::core::ops::BitOr<$flag> for $flags {
126            type Output = Self;
127            #[inline]
128            fn bitor(self, rhs: $flag) -> Self::Output {
129                self | Self::from(rhs)
130            }
131        }
132
133        impl ::core::ops::BitOrAssign<$flag> for $flags {
134            #[inline]
135            fn bitor_assign(&mut self, rhs: $flag) {
136                *self = *self | rhs;
137            }
138        }
139
140        impl ::core::ops::BitAnd for $flags {
141            type Output = Self;
142            #[inline]
143            fn bitand(self, rhs: Self) -> Self::Output {
144                Self(self.0 & rhs.0)
145            }
146        }
147
148        impl ::core::ops::BitAndAssign for $flags {
149            #[inline]
150            fn bitand_assign(&mut self, rhs: Self) {
151                *self = *self & rhs;
152            }
153        }
154
155        impl ::core::ops::BitAnd<$flag> for $flags {
156            type Output = Self;
157            #[inline]
158            fn bitand(self, rhs: $flag) -> Self::Output {
159                self & Self::from(rhs)
160            }
161        }
162
163        impl ::core::ops::BitAndAssign<$flag> for $flags {
164            #[inline]
165            fn bitand_assign(&mut self, rhs: $flag) {
166                *self = *self & rhs;
167            }
168        }
169
170        impl ::core::ops::BitXor for $flags {
171            type Output = Self;
172            #[inline]
173            fn bitxor(self, rhs: Self) -> Self::Output {
174                Self((self.0 ^ rhs.0) & Self::all_bits())
175            }
176        }
177
178        impl ::core::ops::BitXorAssign for $flags {
179            #[inline]
180            fn bitxor_assign(&mut self, rhs: Self) {
181                *self = *self ^ rhs;
182            }
183        }
184
185        impl ::core::ops::BitXor<$flag> for $flags {
186            type Output = Self;
187            #[inline]
188            fn bitxor(self, rhs: $flag) -> Self::Output {
189                self ^ Self::from(rhs)
190            }
191        }
192
193        impl ::core::ops::BitXorAssign<$flag> for $flags {
194            #[inline]
195            fn bitxor_assign(&mut self, rhs: $flag) {
196                *self = *self ^ rhs;
197            }
198        }
199
200        impl ::core::ops::Not for $flags {
201            type Output = Self;
202            #[inline]
203            fn not(self) -> Self::Output {
204                Self((!self.0) & Self::all_bits())
205            }
206        }
207
208        impl ::core::ops::BitOr for $flag {
209            type Output = $flags;
210            #[inline]
211            fn bitor(self, rhs: Self) -> Self::Output {
212                $flags(self as $ty | rhs as $ty)
213            }
214        }
215
216        impl ::core::ops::BitAnd for $flag {
217            type Output = $flags;
218            #[inline]
219            fn bitand(self, rhs: Self) -> Self::Output {
220                $flags(self as $ty & rhs as $ty)
221            }
222        }
223
224        impl ::core::ops::BitXor for $flag {
225            type Output = $flags;
226            #[inline]
227            fn bitxor(self, rhs: Self) -> Self::Output {
228                $flags((self as $ty ^ rhs as $ty) & $flags::all_bits())
229            }
230        }
231
232        impl ::core::ops::Not for $flag {
233            type Output = $flags;
234            #[inline]
235            fn not(self) -> Self::Output {
236                $flags((!(self as $ty)) & $flags::all_bits())
237            }
238        }
239
240        impl $flags {
241            /// Returns an empty instance where no flags are set.
242            #[inline]
243            pub const fn empty() -> Self {
244                Self(0)
245            }
246
247            /// Returns a mask containing all valid flag bits.
248            #[inline]
249            pub const fn all_bits() -> $ty {
250                0 $( | $value )+
251            }
252
253            /// Checks if a specific flag is set.
254            #[inline]
255            pub fn contains(self, flag: $flag) -> bool {
256                (self.0 & flag as $ty) == flag as $ty
257            }
258
259            /// Checks if at least one of the provided flags is set.
260            #[inline]
261            pub fn contains_any(self, flags: $flags) -> bool {
262                (self.0 & flags.0) != 0
263            }
264
265            /// Checks if all of the provided flags are set.
266            #[inline]
267            pub fn contains_all(self, flags: $flags) -> bool {
268                (self.0 & flags.0) == flags.0
269            }
270        }
271    };
272}