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