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}