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}