* [PATCH v6] rust: add new macro for common bitmap operations
@ 2025-12-05 10:15 Filipe Xavier
2025-12-14 3:53 ` Daniel Almeida
2025-12-15 11:55 ` Gary Guo
0 siblings, 2 replies; 3+ messages in thread
From: Filipe Xavier @ 2025-12-05 10:15 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich
Cc: daniel.almeida, rust-for-linux, felipe_life, linux-kernel,
Filipe Xavier, Lyude Paul
We have seen a proliferation of mod_whatever::foo::Flags
being defined with essentially the same implementation
for BitAnd, BitOr, contains and etc.
This macro aims to bring a solution for this,
allowing to generate these methods for user-defined structs.
With some use cases in KMS and upcoming GPU drivers.
Link: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/We.20really.20need.20a.20common.20.60Flags.60.20type
Signed-off-by: Filipe Xavier <felipeaggger@gmail.com>
Suggested-by: Daniel Almeida <daniel.almeida@collabora.com>
Suggested-by: Lyude Paul <lyude@redhat.com>
---
Changes in v6:
- New methods: add new methods contains_any and contains_all.
- Link to v5: https://lore.kernel.org/r/20251109-feat-add-bitmask-macro-v5-1-9d911b207ef4@gmail.com
Changes in v5:
- Docs: improve macro documentation.
- Link to v4: https://lore.kernel.org/r/20251026-feat-add-bitmask-macro-v4-1-e1b59b4762bc@gmail.com
Changes in v4:
- Use enum: changed flag type from struct to enum.
- Minor fix: airect casting (flag as $ty) instead of field access (.0).
- Link to v3: https://lore.kernel.org/r/20250411-feat-add-bitmask-macro-v3-1-187bd3e4a03e@gmail.com
Changes in v3:
- New Feat: added support to declare flags inside macro use.
- Minor fixes: used absolute paths to refer to items, fix rustdoc and fix example cases.
- Link to v2: https://lore.kernel.org/r/20250325-feat-add-bitmask-macro-v2-1-d3beabdad90f@gmail.com
Changes in v2:
- rename: change macro and file name to impl_flags.
- negation sign: change char for negation to `!`.
- transpose docs: add support to transpose user provided docs.
- visibility: add support to use user defined visibility.
- operations: add new operations for flag,
to support use between bit and bitmap, eg: flag & flags.
- code style: small fixes to remove warnings.
- Link to v1: https://lore.kernel.org/r/20250304-feat-add-bitmask-macro-v1-1-1c2d2bcb476b@gmail.com
---
rust/kernel/impl_flags.rs | 243 ++++++++++++++++++++++++++++++++++++++++++++++
rust/kernel/lib.rs | 2 +
rust/kernel/prelude.rs | 1 +
3 files changed, 246 insertions(+)
diff --git a/rust/kernel/impl_flags.rs b/rust/kernel/impl_flags.rs
new file mode 100644
index 0000000000000000000000000000000000000000..aff6f14bc2f6097e78ba21bb13d124ff999b376a
--- /dev/null
+++ b/rust/kernel/impl_flags.rs
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/// Common helper for declaring bitflag and bitmask types.
+///
+/// This macro handles:
+/// - A struct representing a bitmask, and an enumerator representing bitflags which
+/// may be used in the aforementioned bitmask.
+/// - Implementations of common bitmap op. ([`::core::ops::BitOr`], [`::core::ops::BitAnd`], etc.).
+/// - Utility methods such as `.contains()` to check flags.
+///
+/// # Examples
+///
+/// Defining and using impl_flags:
+///
+/// ```
+/// use kernel::impl_flags;
+///
+/// impl_flags!(
+/// /// Represents multiple permissions.
+/// #[derive(Debug, Clone, Default, Copy, PartialEq, Eq)]
+/// pub struct Permissions(u32);
+/// /// Represents a single permission.
+/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+/// pub enum Permission {
+/// Read = 1 << 0,
+/// Write = 1 << 1,
+/// Execute = 1 << 2,
+/// }
+/// );
+///
+/// // Combine multiple permissions using operation OR (`|`).
+/// let read_write: Permissions = Permission::Read | Permission::Write;
+///
+/// assert!(read_write.contains(Permission::Read));
+/// assert!(read_write.contains(Permission::Write));
+/// assert!(!read_write.contains(Permission::Execute));
+/// assert!(read_write.contains_any(Permission::Read | Permission::Execute));
+/// assert!(read_write.contains_all(Permission::Read | Permission::Write));
+///
+/// // Removing a permission with operation AND (`&`).
+/// let read_only: Permissions = read_write & Permission::Read;
+/// assert!(read_only.contains(Permission::Read));
+/// assert!(!read_only.contains(Permission::Write));
+///
+/// // Toggling permissions with XOR (`^`).
+/// let toggled: Permissions = read_only ^ Permission::Read;
+/// assert!(!toggled.contains(Permission::Read));
+///
+/// // Inverting permissions with negation (`!`).
+/// let negated = !read_only;
+/// assert!(negated.contains(Permission::Write));
+/// ```
+#[macro_export]
+macro_rules! impl_flags {
+ (
+ $(#[$outer_flags:meta])*
+ $vis_flags:vis struct $flags:ident($ty:ty);
+
+ $(#[$outer_flag:meta])*
+ $vis_flag:vis enum $flag:ident {
+ $(
+ $(#[$inner_flag:meta])*
+ $name:ident = $value:expr
+ ),+ $( , )?
+ }
+ ) => {
+ $(#[$outer_flags])*
+ #[repr(transparent)]
+ $vis_flags struct $flags($ty);
+
+ $(#[$outer_flag])*
+ #[repr($ty)]
+ $vis_flag enum $flag {
+ $(
+ $(#[$inner_flag])*
+ $name = $value
+ ),+
+ }
+
+ impl ::core::convert::From<$flag> for $flags {
+ #[inline]
+ fn from(value: $flag) -> Self {
+ Self(value as $ty)
+ }
+ }
+
+ impl ::core::convert::From<$flags> for $ty {
+ #[inline]
+ fn from(value: $flags) -> Self {
+ value.0
+ }
+ }
+
+ impl ::core::ops::BitOr for $flags {
+ type Output = Self;
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self::Output {
+ Self(self.0 | rhs.0)
+ }
+ }
+
+ impl ::core::ops::BitOrAssign for $flags {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = *self | rhs;
+ }
+ }
+
+ impl ::core::ops::BitAnd for $flags {
+ type Output = Self;
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self::Output {
+ Self(self.0 & rhs.0)
+ }
+ }
+
+ impl ::core::ops::BitAndAssign for $flags {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Self) {
+ *self = *self & rhs;
+ }
+ }
+
+ impl ::core::ops::BitOr<$flag> for $flags {
+ type Output = Self;
+ #[inline]
+ fn bitor(self, rhs: $flag) -> Self::Output {
+ self | Self::from(rhs)
+ }
+ }
+
+ impl ::core::ops::BitOrAssign<$flag> for $flags {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: $flag) {
+ *self = *self | rhs;
+ }
+ }
+
+ impl ::core::ops::BitAnd<$flag> for $flags {
+ type Output = Self;
+ #[inline]
+ fn bitand(self, rhs: $flag) -> Self::Output {
+ self & Self::from(rhs)
+ }
+ }
+
+ impl ::core::ops::BitAndAssign<$flag> for $flags {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: $flag) {
+ *self = *self & rhs;
+ }
+ }
+
+ impl ::core::ops::BitXor for $flags {
+ type Output = Self;
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self::Output {
+ Self(self.0 ^ rhs.0)
+ }
+ }
+
+ impl ::core::ops::BitXorAssign for $flags {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Self) {
+ *self = *self ^ rhs;
+ }
+ }
+
+ impl ::core::ops::Not for $flags {
+ type Output = Self;
+ #[inline]
+ fn not(self) -> Self::Output {
+ Self(!self.0)
+ }
+ }
+
+ impl ::core::ops::BitOr for $flag {
+ type Output = $flags;
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self::Output {
+ $flags(self as $ty | rhs as $ty)
+ }
+ }
+
+ impl ::core::ops::BitAnd for $flag {
+ type Output = $flags;
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self::Output {
+ $flags(self as $ty & rhs as $ty)
+ }
+ }
+
+ impl ::core::ops::BitXor for $flag {
+ type Output = $flags;
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self::Output {
+ $flags(self as $ty ^ rhs as $ty)
+ }
+ }
+
+ impl ::core::ops::Not for $flag {
+ type Output = $flags;
+ #[inline]
+ fn not(self) -> Self::Output {
+ $flags(!(self as $ty))
+ }
+ }
+
+ impl ::core::ops::BitXor<$flag> for $flags {
+ type Output = Self;
+ #[inline]
+ fn bitxor(self, rhs: $flag) -> Self::Output {
+ self ^ Self::from(rhs)
+ }
+ }
+
+ impl $flags {
+ /// Returns an empty instance of `type` where no flags are set.
+ #[inline]
+ pub const fn empty() -> Self {
+ Self(0)
+ }
+
+ /// Checks if a specific flag is set.
+ #[inline]
+ pub fn contains(self, flag: $flag) -> bool {
+ (self.0 & flag as $ty) == flag as $ty
+ }
+
+ /// Checks if at least one of the provided flags is set.
+ #[inline]
+ pub fn contains_any(self, flags: $flags) -> bool {
+ (self.0 & flags.0) != 0
+ }
+
+ /// Checks if all of the provided flags are set.
+ #[inline]
+ pub fn contains_all(self, flags: $flags) -> bool {
+ (self.0 & flags.0) == flags.0
+ }
+ }
+ };
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 28007be98fbad0e875d7e5345e164e2af2c5da32..57b789315deda3d2fa8961af79cad4462fff7fa8 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -67,6 +67,8 @@
#[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)]
pub mod firmware;
pub mod fs;
+#[doc(hidden)]
+pub mod impl_flags;
pub mod init;
pub mod io;
pub mod ioctl;
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index baa774a351ceeb995a2a647f78a27b408d9f3834..085f23502544c80c2202eacd18ba190186a74f30 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -27,6 +27,7 @@
#[doc(no_inline)]
pub use super::dbg;
pub use super::fmt;
+pub use super::impl_flags;
pub use super::{dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn};
pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
---
base-commit: edc5e6e019c99b529b3d1f2801d5cce9924ae79b
change-id: 20250304-feat-add-bitmask-macro-6424b1c317e2
Best regards,
--
Filipe Xavier <felipeaggger@gmail.com>
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v6] rust: add new macro for common bitmap operations
2025-12-05 10:15 [PATCH v6] rust: add new macro for common bitmap operations Filipe Xavier
@ 2025-12-14 3:53 ` Daniel Almeida
2025-12-15 11:55 ` Gary Guo
1 sibling, 0 replies; 3+ messages in thread
From: Daniel Almeida @ 2025-12-14 3:53 UTC (permalink / raw)
To: Filipe Xavier
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, rust-for-linux, felipe_life,
linux-kernel, Lyude Paul, Filipe Xavier
> On 5 Dec 2025, at 19:16, Filipe Xavier <felipeaggger@gmail.com> wrote:
>
> We have seen a proliferation of mod_whatever::foo::Flags
> being defined with essentially the same implementation
> for BitAnd, BitOr, contains and etc.
>
> This macro aims to bring a solution for this,
> allowing to generate these methods for user-defined structs.
> With some use cases in KMS and upcoming GPU drivers.
>
> Link: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/We.20really.20need.20a.20common.20.60Flags.60.20type
> Signed-off-by: Filipe Xavier <felipeaggger@gmail.com>
> Suggested-by: Daniel Almeida <daniel.almeida@collabora.com>
> Suggested-by: Lyude Paul <lyude@redhat.com>
> ---
> Changes in v6:
> - New methods: add new methods contains_any and contains_all.
> - Link to v5: https://lore.kernel.org/r/20251109-feat-add-bitmask-macro-v5-1-9d911b207ef4@gmail.com
>
> Changes in v5:
> - Docs: improve macro documentation.
> - Link to v4: https://lore.kernel.org/r/20251026-feat-add-bitmask-macro-v4-1-e1b59b4762bc@gmail.com
>
> Changes in v4:
> - Use enum: changed flag type from struct to enum.
> - Minor fix: airect casting (flag as $ty) instead of field access (.0).
> - Link to v3: https://lore.kernel.org/r/20250411-feat-add-bitmask-macro-v3-1-187bd3e4a03e@gmail.com
>
> Changes in v3:
> - New Feat: added support to declare flags inside macro use.
> - Minor fixes: used absolute paths to refer to items, fix rustdoc and fix example cases.
> - Link to v2: https://lore.kernel.org/r/20250325-feat-add-bitmask-macro-v2-1-d3beabdad90f@gmail.com
>
> Changes in v2:
> - rename: change macro and file name to impl_flags.
> - negation sign: change char for negation to `!`.
> - transpose docs: add support to transpose user provided docs.
> - visibility: add support to use user defined visibility.
> - operations: add new operations for flag,
> to support use between bit and bitmap, eg: flag & flags.
> - code style: small fixes to remove warnings.
> - Link to v1: https://lore.kernel.org/r/20250304-feat-add-bitmask-macro-v1-1-1c2d2bcb476b@gmail.com
> ---
> rust/kernel/impl_flags.rs | 243 ++++++++++++++++++++++++++++++++++++++++++++++
> rust/kernel/lib.rs | 2 +
> rust/kernel/prelude.rs | 1 +
> 3 files changed, 246 insertions(+)
>
> diff --git a/rust/kernel/impl_flags.rs b/rust/kernel/impl_flags.rs
> new file mode 100644
> index 0000000000000000000000000000000000000000..aff6f14bc2f6097e78ba21bb13d124ff999b376a
> --- /dev/null
> +++ b/rust/kernel/impl_flags.rs
> @@ -0,0 +1,243 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/// Common helper for declaring bitflag and bitmask types.
> +///
> +/// This macro handles:
> +/// - A struct representing a bitmask, and an enumerator representing bitflags which
> +/// may be used in the aforementioned bitmask.
> +/// - Implementations of common bitmap op. ([`::core::ops::BitOr`], [`::core::ops::BitAnd`], etc.).
> +/// - Utility methods such as `.contains()` to check flags.
> +///
> +/// # Examples
> +///
> +/// Defining and using impl_flags:
> +///
> +/// ```
> +/// use kernel::impl_flags;
> +///
> +/// impl_flags!(
> +/// /// Represents multiple permissions.
> +/// #[derive(Debug, Clone, Default, Copy, PartialEq, Eq)]
> +/// pub struct Permissions(u32);
> +/// /// Represents a single permission.
> +/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
> +/// pub enum Permission {
> +/// Read = 1 << 0,
> +/// Write = 1 << 1,
> +/// Execute = 1 << 2,
> +/// }
> +/// );
> +///
> +/// // Combine multiple permissions using operation OR (`|`).
> +/// let read_write: Permissions = Permission::Read | Permission::Write;
> +///
> +/// assert!(read_write.contains(Permission::Read));
> +/// assert!(read_write.contains(Permission::Write));
> +/// assert!(!read_write.contains(Permission::Execute));
> +/// assert!(read_write.contains_any(Permission::Read | Permission::Execute));
> +/// assert!(read_write.contains_all(Permission::Read | Permission::Write));
> +///
> +/// // Removing a permission with operation AND (`&`).
> +/// let read_only: Permissions = read_write & Permission::Read;
> +/// assert!(read_only.contains(Permission::Read));
> +/// assert!(!read_only.contains(Permission::Write));
> +///
> +/// // Toggling permissions with XOR (`^`).
> +/// let toggled: Permissions = read_only ^ Permission::Read;
> +/// assert!(!toggled.contains(Permission::Read));
> +///
> +/// // Inverting permissions with negation (`!`).
> +/// let negated = !read_only;
> +/// assert!(negated.contains(Permission::Write));
> +/// ```
> +#[macro_export]
> +macro_rules! impl_flags {
> + (
> + $(#[$outer_flags:meta])*
> + $vis_flags:vis struct $flags:ident($ty:ty);
> +
> + $(#[$outer_flag:meta])*
> + $vis_flag:vis enum $flag:ident {
> + $(
> + $(#[$inner_flag:meta])*
> + $name:ident = $value:expr
> + ),+ $( , )?
> + }
> + ) => {
> + $(#[$outer_flags])*
> + #[repr(transparent)]
> + $vis_flags struct $flags($ty);
> +
> + $(#[$outer_flag])*
> + #[repr($ty)]
> + $vis_flag enum $flag {
> + $(
> + $(#[$inner_flag])*
> + $name = $value
> + ),+
> + }
> +
> + impl ::core::convert::From<$flag> for $flags {
> + #[inline]
> + fn from(value: $flag) -> Self {
> + Self(value as $ty)
> + }
> + }
> +
> + impl ::core::convert::From<$flags> for $ty {
> + #[inline]
> + fn from(value: $flags) -> Self {
> + value.0
> + }
> + }
> +
> + impl ::core::ops::BitOr for $flags {
> + type Output = Self;
> + #[inline]
> + fn bitor(self, rhs: Self) -> Self::Output {
> + Self(self.0 | rhs.0)
> + }
> + }
> +
> + impl ::core::ops::BitOrAssign for $flags {
> + #[inline]
> + fn bitor_assign(&mut self, rhs: Self) {
> + *self = *self | rhs;
> + }
> + }
> +
> + impl ::core::ops::BitAnd for $flags {
> + type Output = Self;
> + #[inline]
> + fn bitand(self, rhs: Self) -> Self::Output {
> + Self(self.0 & rhs.0)
> + }
> + }
> +
> + impl ::core::ops::BitAndAssign for $flags {
> + #[inline]
> + fn bitand_assign(&mut self, rhs: Self) {
> + *self = *self & rhs;
> + }
> + }
> +
> + impl ::core::ops::BitOr<$flag> for $flags {
> + type Output = Self;
> + #[inline]
> + fn bitor(self, rhs: $flag) -> Self::Output {
> + self | Self::from(rhs)
> + }
> + }
> +
> + impl ::core::ops::BitOrAssign<$flag> for $flags {
> + #[inline]
> + fn bitor_assign(&mut self, rhs: $flag) {
> + *self = *self | rhs;
> + }
> + }
> +
> + impl ::core::ops::BitAnd<$flag> for $flags {
> + type Output = Self;
> + #[inline]
> + fn bitand(self, rhs: $flag) -> Self::Output {
> + self & Self::from(rhs)
> + }
> + }
> +
> + impl ::core::ops::BitAndAssign<$flag> for $flags {
> + #[inline]
> + fn bitand_assign(&mut self, rhs: $flag) {
> + *self = *self & rhs;
> + }
> + }
> +
> + impl ::core::ops::BitXor for $flags {
> + type Output = Self;
> + #[inline]
> + fn bitxor(self, rhs: Self) -> Self::Output {
> + Self(self.0 ^ rhs.0)
> + }
> + }
> +
> + impl ::core::ops::BitXorAssign for $flags {
> + #[inline]
> + fn bitxor_assign(&mut self, rhs: Self) {
> + *self = *self ^ rhs;
> + }
> + }
> +
> + impl ::core::ops::Not for $flags {
> + type Output = Self;
> + #[inline]
> + fn not(self) -> Self::Output {
> + Self(!self.0)
> + }
> + }
> +
> + impl ::core::ops::BitOr for $flag {
> + type Output = $flags;
> + #[inline]
> + fn bitor(self, rhs: Self) -> Self::Output {
> + $flags(self as $ty | rhs as $ty)
> + }
> + }
> +
> + impl ::core::ops::BitAnd for $flag {
> + type Output = $flags;
> + #[inline]
> + fn bitand(self, rhs: Self) -> Self::Output {
> + $flags(self as $ty & rhs as $ty)
> + }
> + }
> +
> + impl ::core::ops::BitXor for $flag {
> + type Output = $flags;
> + #[inline]
> + fn bitxor(self, rhs: Self) -> Self::Output {
> + $flags(self as $ty ^ rhs as $ty)
> + }
> + }
> +
> + impl ::core::ops::Not for $flag {
> + type Output = $flags;
> + #[inline]
> + fn not(self) -> Self::Output {
> + $flags(!(self as $ty))
> + }
> + }
> +
> + impl ::core::ops::BitXor<$flag> for $flags {
> + type Output = Self;
> + #[inline]
> + fn bitxor(self, rhs: $flag) -> Self::Output {
> + self ^ Self::from(rhs)
> + }
> + }
> +
> + impl $flags {
> + /// Returns an empty instance of `type` where no flags are set.
> + #[inline]
> + pub const fn empty() -> Self {
> + Self(0)
> + }
> +
> + /// Checks if a specific flag is set.
> + #[inline]
> + pub fn contains(self, flag: $flag) -> bool {
> + (self.0 & flag as $ty) == flag as $ty
> + }
> +
> + /// Checks if at least one of the provided flags is set.
> + #[inline]
> + pub fn contains_any(self, flags: $flags) -> bool {
> + (self.0 & flags.0) != 0
> + }
> +
> + /// Checks if all of the provided flags are set.
> + #[inline]
> + pub fn contains_all(self, flags: $flags) -> bool {
> + (self.0 & flags.0) == flags.0
> + }
> + }
> + };
> +}
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index 28007be98fbad0e875d7e5345e164e2af2c5da32..57b789315deda3d2fa8961af79cad4462fff7fa8 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -67,6 +67,8 @@
> #[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)]
> pub mod firmware;
> pub mod fs;
> +#[doc(hidden)]
> +pub mod impl_flags;
> pub mod init;
> pub mod io;
> pub mod ioctl;
> diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
> index baa774a351ceeb995a2a647f78a27b408d9f3834..085f23502544c80c2202eacd18ba190186a74f30 100644
> --- a/rust/kernel/prelude.rs
> +++ b/rust/kernel/prelude.rs
> @@ -27,6 +27,7 @@
> #[doc(no_inline)]
> pub use super::dbg;
> pub use super::fmt;
> +pub use super::impl_flags;
> pub use super::{dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn};
> pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
>
>
> ---
> base-commit: edc5e6e019c99b529b3d1f2801d5cce9924ae79b
> change-id: 20250304-feat-add-bitmask-macro-6424b1c317e2
>
> Best regards,
> --
> Filipe Xavier <felipeaggger@gmail.com>
>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Lyude, IIUC you were happy with the previous version already? Can you apply on the rust drm branch? The first users will most likely be the GPU drivers so it makes sense to get it there.
—Daniel
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v6] rust: add new macro for common bitmap operations
2025-12-05 10:15 [PATCH v6] rust: add new macro for common bitmap operations Filipe Xavier
2025-12-14 3:53 ` Daniel Almeida
@ 2025-12-15 11:55 ` Gary Guo
1 sibling, 0 replies; 3+ messages in thread
From: Gary Guo @ 2025-12-15 11:55 UTC (permalink / raw)
To: Filipe Xavier
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, daniel.almeida, rust-for-linux, felipe_life,
linux-kernel, Lyude Paul
On Fri, 05 Dec 2025 07:15:17 -0300
Filipe Xavier <felipeaggger@gmail.com> wrote:
> We have seen a proliferation of mod_whatever::foo::Flags
> being defined with essentially the same implementation
> for BitAnd, BitOr, contains and etc.
>
> This macro aims to bring a solution for this,
> allowing to generate these methods for user-defined structs.
> With some use cases in KMS and upcoming GPU drivers.
>
> Link: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/We.20really.20need.20a.20common.20.60Flags.60.20type
> Signed-off-by: Filipe Xavier <felipeaggger@gmail.com>
> Suggested-by: Daniel Almeida <daniel.almeida@collabora.com>
> Suggested-by: Lyude Paul <lyude@redhat.com>
> ---
> Changes in v6:
> - New methods: add new methods contains_any and contains_all.
> - Link to v5: https://lore.kernel.org/r/20251109-feat-add-bitmask-macro-v5-1-9d911b207ef4@gmail.com
>
> Changes in v5:
> - Docs: improve macro documentation.
> - Link to v4: https://lore.kernel.org/r/20251026-feat-add-bitmask-macro-v4-1-e1b59b4762bc@gmail.com
>
> Changes in v4:
> - Use enum: changed flag type from struct to enum.
> - Minor fix: airect casting (flag as $ty) instead of field access (.0).
> - Link to v3: https://lore.kernel.org/r/20250411-feat-add-bitmask-macro-v3-1-187bd3e4a03e@gmail.com
>
> Changes in v3:
> - New Feat: added support to declare flags inside macro use.
> - Minor fixes: used absolute paths to refer to items, fix rustdoc and fix example cases.
> - Link to v2: https://lore.kernel.org/r/20250325-feat-add-bitmask-macro-v2-1-d3beabdad90f@gmail.com
>
> Changes in v2:
> - rename: change macro and file name to impl_flags.
> - negation sign: change char for negation to `!`.
> - transpose docs: add support to transpose user provided docs.
> - visibility: add support to use user defined visibility.
> - operations: add new operations for flag,
> to support use between bit and bitmap, eg: flag & flags.
> - code style: small fixes to remove warnings.
> - Link to v1: https://lore.kernel.org/r/20250304-feat-add-bitmask-macro-v1-1-1c2d2bcb476b@gmail.com
> ---
> rust/kernel/impl_flags.rs | 243 ++++++++++++++++++++++++++++++++++++++++++++++
> rust/kernel/lib.rs | 2 +
> rust/kernel/prelude.rs | 1 +
> 3 files changed, 246 insertions(+)
>
> diff --git a/rust/kernel/impl_flags.rs b/rust/kernel/impl_flags.rs
> new file mode 100644
> index 0000000000000000000000000000000000000000..aff6f14bc2f6097e78ba21bb13d124ff999b376a
> --- /dev/null
> +++ b/rust/kernel/impl_flags.rs
> @@ -0,0 +1,243 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/// Common helper for declaring bitflag and bitmask types.
> +///
> +/// This macro handles:
> +/// - A struct representing a bitmask, and an enumerator representing bitflags which
> +/// may be used in the aforementioned bitmask.
> +/// - Implementations of common bitmap op. ([`::core::ops::BitOr`], [`::core::ops::BitAnd`], etc.).
> +/// - Utility methods such as `.contains()` to check flags.
> +///
> +/// # Examples
> +///
> +/// Defining and using impl_flags:
> +///
> +/// ```
> +/// use kernel::impl_flags;
> +///
> +/// impl_flags!(
> +/// /// Represents multiple permissions.
> +/// #[derive(Debug, Clone, Default, Copy, PartialEq, Eq)]
> +/// pub struct Permissions(u32);
> +/// /// Represents a single permission.
> +/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
> +/// pub enum Permission {
> +/// Read = 1 << 0,
> +/// Write = 1 << 1,
> +/// Execute = 1 << 2,
> +/// }
> +/// );
> +///
> +/// // Combine multiple permissions using operation OR (`|`).
> +/// let read_write: Permissions = Permission::Read | Permission::Write;
> +///
> +/// assert!(read_write.contains(Permission::Read));
> +/// assert!(read_write.contains(Permission::Write));
> +/// assert!(!read_write.contains(Permission::Execute));
> +/// assert!(read_write.contains_any(Permission::Read | Permission::Execute));
> +/// assert!(read_write.contains_all(Permission::Read | Permission::Write));
> +///
> +/// // Removing a permission with operation AND (`&`).
> +/// let read_only: Permissions = read_write & Permission::Read;
> +/// assert!(read_only.contains(Permission::Read));
> +/// assert!(!read_only.contains(Permission::Write));
> +///
> +/// // Toggling permissions with XOR (`^`).
> +/// let toggled: Permissions = read_only ^ Permission::Read;
> +/// assert!(!toggled.contains(Permission::Read));
> +///
> +/// // Inverting permissions with negation (`!`).
> +/// let negated = !read_only;
> +/// assert!(negated.contains(Permission::Write));
Your implementation of `!` does not specify whether it may contain bit
flags that are not defined. In this example, `negated` contains bit 3~31
as well despite not defined anywhere. Same for `^` implementation.
AFAIK this is a similar behaviour to bitflags crate v1 and in v2 they're
changing the impl to unset unknown flags. For a bitflags that's only ever
used in the driver itself, either behaviour makes sense, but it might be a
safer approach to unset all unknown flags in flag operations.
bitflags 2.x provides a `_ = !0` approach to mark all bits as known.
(Yes I know you currently do not expose any methods to get raw values, but
we'll either have that in the future, or currently you can do `flags.0`
directly in the same module)
Best,
Gary
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-12-15 11:55 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-05 10:15 [PATCH v6] rust: add new macro for common bitmap operations Filipe Xavier
2025-12-14 3:53 ` Daniel Almeida
2025-12-15 11:55 ` Gary Guo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).