Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/kernel/impl_flags.rs
121797 views
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]
70
macro_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
}
273
274