[PATCH v2 1/2] rust: macros: Add derive Display for enums

Maurice Hieronymus posted 2 patches 3 days, 2 hours ago
[PATCH v2 1/2] rust: macros: Add derive Display for enums
Posted by Maurice Hieronymus 3 days, 2 hours ago
Add a derive macro that implements kernel::fmt::Display for enums.
The macro outputs the exact variant name as written, preserving case.

This supports all enum variant types: unit, tuple, and struct variants.
For variants with data, only the variant name is displayed.

Signed-off-by: Maurice Hieronymus <mhi@mailbox.org>
---
 rust/macros/display.rs | 52 ++++++++++++++++++++++++++++++++++++++++++
 rust/macros/lib.rs     | 42 ++++++++++++++++++++++++++++++++++
 2 files changed, 94 insertions(+)
 create mode 100644 rust/macros/display.rs

diff --git a/rust/macros/display.rs b/rust/macros/display.rs
new file mode 100644
index 000000000000..5cd396d3900e
--- /dev/null
+++ b/rust/macros/display.rs
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Derive macro for `Display` on enums.
+//!
+//! This module provides a derive macro that implements `kernel::fmt::Display`
+//! for enums, outputting the exact variant name as written.
+
+use proc_macro::TokenStream;
+
+pub(crate) fn derive_display(input: TokenStream) -> TokenStream {
+    let input: syn::DeriveInput = syn::parse(input).expect("failed to parse input");
+
+    let data = match &input.data {
+        syn::Data::Enum(data) => data,
+        syn::Data::Struct(_) => {
+            panic!("derive(Display) only supports enums, not structs");
+        }
+        syn::Data::Union(_) => {
+            panic!("derive(Display) only supports enums, not unions");
+        }
+    };
+
+    // Generate match arms for each variant.
+    let match_arms = data.variants.iter().map(|variant| {
+        let variant_ident = &variant.ident;
+        let variant_name = variant_ident.to_string();
+
+        // Handle different variant types: unit, tuple, and struct.
+        let pattern = match &variant.fields {
+            syn::Fields::Unit => quote::quote! { Self::#variant_ident },
+            syn::Fields::Unnamed(_) => quote::quote! { Self::#variant_ident(..) },
+            syn::Fields::Named(_) => quote::quote! { Self::#variant_ident { .. } },
+        };
+
+        quote::quote! {
+            #pattern => f.write_str(#variant_name)
+        }
+    });
+
+    let name = &input.ident;
+    let expanded = quote::quote! {
+        impl ::kernel::fmt::Display for #name {
+            fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
+                match self {
+                    #(#match_arms),*
+                }
+            }
+        }
+    };
+
+    expanded.into()
+}
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index b38002151871..4c95a132fefe 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -14,6 +14,7 @@
 #[macro_use]
 mod quote;
 mod concat_idents;
+mod display;
 mod export;
 mod fmt;
 mod helpers;
@@ -475,3 +476,44 @@ pub fn paste(input: TokenStream) -> TokenStream {
 pub fn kunit_tests(attr: TokenStream, ts: TokenStream) -> TokenStream {
     kunit::kunit_tests(attr, ts)
 }
+
+/// Derives the [`Display`] trait for enums.
+///
+/// This macro generates an implementation of [`kernel::fmt::Display`] for enums
+/// that outputs the exact variant name as written (case-preserved).
+///
+/// # Requirements
+///
+/// - Can only be applied to enums (not structs or unions).
+/// - Supports unit variants, tuple variants, and struct variants.
+/// - For variants with data, only the variant name is displayed.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::fmt::Adapter;
+/// use kernel::macros::Display;
+///
+/// #[allow(non_camel_case_types)]
+/// #[derive(Display)]
+/// enum TestEnum {
+///     Foo,
+///     bAr(u8),
+///     baZ { value: u8 },
+/// }
+///
+/// let foo = TestEnum::Foo;
+/// let bar = TestEnum::bAr(42);
+/// let baz = TestEnum::baZ { value: 0 };
+///
+/// assert!(format!("{}", Adapter(&foo)) == "Foo");
+/// assert!(format!("{}", Adapter(&bar)) == "bAr");
+/// assert!(format!("{}", Adapter(&baz)) == "baZ");
+/// ```
+///
+/// [`Display`]: ../kernel/fmt/trait.Display.html
+/// [`kernel::fmt::Display`]: ../kernel/fmt/trait.Display.html
+#[proc_macro_derive(Display)]
+pub fn derive_display(input: TokenStream) -> TokenStream {
+    display::derive_display(input)
+}
-- 
2.51.2
Re: [PATCH v2 1/2] rust: macros: Add derive Display for enums
Posted by Benno Lossin 2 days, 14 hours ago
On Sun Jan 4, 2026 at 9:07 PM CET, Maurice Hieronymus wrote:
> Add a derive macro that implements kernel::fmt::Display for enums.
> The macro outputs the exact variant name as written, preserving case.
>
> This supports all enum variant types: unit, tuple, and struct variants.
> For variants with data, only the variant name is displayed.

I don't think we should be adding this. Display is designed for
user-facing output and so it should always be carefully designed and no
automation should exist for it.

The use-case in the second patch is also much better served by either a
manual match on the enum:

    impl fmt::Display for Chipset {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match self {
                Chipset::Variant => write!(f, "Variant"),
                // ...
            }
        }
    }

Or by adding the respective code in the declarative macro already used
to define it.

Cheers,
Benno

> Signed-off-by: Maurice Hieronymus <mhi@mailbox.org>
> ---
>  rust/macros/display.rs | 52 ++++++++++++++++++++++++++++++++++++++++++
>  rust/macros/lib.rs     | 42 ++++++++++++++++++++++++++++++++++
>  2 files changed, 94 insertions(+)
>  create mode 100644 rust/macros/display.rs
Re: [PATCH v2 1/2] rust: macros: Add derive Display for enums
Posted by Danilo Krummrich 2 days, 12 hours ago
On Mon Jan 5, 2026 at 10:02 AM CET, Benno Lossin wrote:
> On Sun Jan 4, 2026 at 9:07 PM CET, Maurice Hieronymus wrote:
>> Add a derive macro that implements kernel::fmt::Display for enums.
>> The macro outputs the exact variant name as written, preserving case.
>>
>> This supports all enum variant types: unit, tuple, and struct variants.
>> For variants with data, only the variant name is displayed.
>
> I don't think we should be adding this. Display is designed for
> user-facing output and so it should always be carefully designed and no
> automation should exist for it.

In general I agree, but simple stringification of an enum variant for a Display
implementation is a very common use-case and it seems pretty unfortunate to have
to fall back to either do the below (especially if there are a lot of enum
variants) or having to go the declarative path of doing something as in [1].

Especially in combination with things like FromPrimitive and ToPrimitive it gets
us rid of the cases where we need such declarative macro mess.

Eventually, drivers will most likely implement their own proc macro for this or
repeat the declarative macro pattern over and over again.

Maybe we should just pick a more specific name for such a derive macro than
macros::Display.

Maybe something along the lines of macros::EnumVariantDisplay? We could also
have an optional argument indicating whether it should be converted to lower /
upper case.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/gpu/nova-core/gpu.rs#n25
Re: [PATCH v2 1/2] rust: macros: Add derive Display for enums
Posted by Gary Guo 2 days, 6 hours ago
On Mon, 05 Jan 2026 11:29:04 +0100
"Danilo Krummrich" <dakr@kernel.org> wrote:

> On Mon Jan 5, 2026 at 10:02 AM CET, Benno Lossin wrote:
> > On Sun Jan 4, 2026 at 9:07 PM CET, Maurice Hieronymus wrote:  
> >> Add a derive macro that implements kernel::fmt::Display for enums.
> >> The macro outputs the exact variant name as written, preserving case.
> >>
> >> This supports all enum variant types: unit, tuple, and struct variants.
> >> For variants with data, only the variant name is displayed.  
> >
> > I don't think we should be adding this. Display is designed for
> > user-facing output and so it should always be carefully designed and no
> > automation should exist for it.  
> 
> In general I agree, but simple stringification of an enum variant for a Display
> implementation is a very common use-case and it seems pretty unfortunate to have
> to fall back to either do the below (especially if there are a lot of enum
> variants) or having to go the declarative path of doing something as in [1].
> 
> Especially in combination with things like FromPrimitive and ToPrimitive it gets
> us rid of the cases where we need such declarative macro mess.
> 
> Eventually, drivers will most likely implement their own proc macro for this or
> repeat the declarative macro pattern over and over again.
> 
> Maybe we should just pick a more specific name for such a derive macro than
> macros::Display.
> 
> Maybe something along the lines of macros::EnumVariantDisplay? We could also
> have an optional argument indicating whether it should be converted to lower /
> upper case.

I think the proposal is reasonable.

Being able to print enum name is very common and this is why crates like
`strum` exist.

Perhaps if we want to make user having a thought about what names to
expose to users, we can have the case conversion argument be mandatory, so
they are forced to make a choice rather than blindly stuck
`#[derive(Display)]` onto their enum.

Best,
Gary
Re: [PATCH v2 1/2] rust: macros: Add derive Display for enums
Posted by Maurice Hieronymus 2 days, 1 hour ago
On Mon, 2026-01-05 at 16:11 +0000, Gary Guo wrote:
> On Mon, 05 Jan 2026 11:29:04 +0100
> "Danilo Krummrich" <dakr@kernel.org> wrote:
> 
> > On Mon Jan 5, 2026 at 10:02 AM CET, Benno Lossin wrote:
> > > On Sun Jan 4, 2026 at 9:07 PM CET, Maurice Hieronymus wrote:  
> > > > Add a derive macro that implements kernel::fmt::Display for
> > > > enums.
> > > > The macro outputs the exact variant name as written, preserving
> > > > case.
> > > > 
> > > > This supports all enum variant types: unit, tuple, and struct
> > > > variants.
> > > > For variants with data, only the variant name is displayed.  
> > > 
> > > I don't think we should be adding this. Display is designed for
> > > user-facing output and so it should always be carefully designed
> > > and no
> > > automation should exist for it.  
> > 
> > In general I agree, but simple stringification of an enum variant
> > for a Display
> > implementation is a very common use-case and it seems pretty
> > unfortunate to have
> > to fall back to either do the below (especially if there are a lot
> > of enum
> > variants) or having to go the declarative path of doing something
> > as in [1].
> > 
> > Especially in combination with things like FromPrimitive and
> > ToPrimitive it gets
> > us rid of the cases where we need such declarative macro mess.
> > 
> > Eventually, drivers will most likely implement their own proc macro
> > for this or
> > repeat the declarative macro pattern over and over again.
> > 
> > Maybe we should just pick a more specific name for such a derive
> > macro than
> > macros::Display.
> > 
> > Maybe something along the lines of macros::EnumVariantDisplay? We
> > could also
> > have an optional argument indicating whether it should be converted
> > to lower /
> > upper case.
> 
> I think the proposal is reasonable.
> Being able to print enum name is very common and this is why crates
> like
> `strum` exist.
> 
Before I start implementing, I want to reach common ground.

In my opinion a derive macro which implements Display would be
perfectly fine, as long as the name suggests what it does. So for
example #[derive(DisplayEnumVariant)]. This would communicate the
intent clearly to the user.

Benno, would you be okay with that? If not, Gary and Danilo, are you
fine with the proposed trait implementation (e.g. the variant_name
function)?
> Perhaps if we want to make user having a thought about what names to
> expose to users, we can have the case conversion argument be
> mandatory, so
> they are forced to make a choice rather than blindly stuck
> `#[derive(Display)]` onto their enum.
> 
Are there any common use-cases where one wants to change the case of
the enum variants? If not, I would not implement an argument and rather
name the macro accordingly, so the intent is clear.

Thanks,

Maurice
> Best,
> Gary
Re: [PATCH v2 1/2] rust: macros: Add derive Display for enums
Posted by Danilo Krummrich 2 days ago
On Mon Jan 5, 2026 at 10:11 PM CET, Maurice Hieronymus wrote:
> Before I start implementing, I want to reach common ground.
>
> In my opinion a derive macro which implements Display would be
> perfectly fine, as long as the name suggests what it does. So for
> example #[derive(DisplayEnumVariant)]. This would communicate the
> intent clearly to the user.
>
> Benno, would you be okay with that? If not, Gary and Danilo, are you
> fine with the proposed trait implementation (e.g. the variant_name
> function)?

Actually, it might even be reasonable to have both. In the Nova driver we have
the case that we want to print the enum variant exactly as it is defined in the
code and a lowercase version of the enum variant.

> Are there any common use-cases where one wants to change the case of
> the enum variants? If not, I would not implement an argument and rather
> name the macro accordingly, so the intent is clear.

As mentioned above, we do have a case in Nova where we also want a lowercase
representation to construct a firmware path with.
Re: [PATCH v2 1/2] rust: macros: Add derive Display for enums
Posted by Maurice Hieronymus 1 day, 17 hours ago
On Mon, 2026-01-05 at 23:03 +0100, Danilo Krummrich wrote:
> On Mon Jan 5, 2026 at 10:11 PM CET, Maurice Hieronymus wrote:
> > Before I start implementing, I want to reach common ground.
> > 
> > In my opinion a derive macro which implements Display would be
> > perfectly fine, as long as the name suggests what it does. So for
> > example #[derive(DisplayEnumVariant)]. This would communicate the
> > intent clearly to the user.
> > 
> > Benno, would you be okay with that? If not, Gary and Danilo, are
> > you
> > fine with the proposed trait implementation (e.g. the variant_name
> > function)?
> 
> Actually, it might even be reasonable to have both. In the Nova
> driver we have
> the case that we want to print the enum variant exactly as it is
> defined in the
> code and a lowercase version of the enum variant.
> 
> > Are there any common use-cases where one wants to change the case
> > of
> > the enum variants? If not, I would not implement an argument and
> > rather
> > name the macro accordingly, so the intent is clear.
> 
> As mentioned above, we do have a case in Nova where we also want a
> lowercase
> representation to construct a firmware path with.

So there would be the need to have two derive macros:

1. #[derive(DisplayEnumVariant)]
Implements Display for all enum variants as they are (original case).

2. #[derive(ImplementVariantName(Case::Lowercase))]
Implements the mentioned trait. Case could be an Enum where one could
choose between Case::Lowercase and Case::Original.

Something along those lines?
Re: [PATCH v2 1/2] rust: macros: Add derive Display for enums
Posted by Benno Lossin 1 day, 10 hours ago
On Tue Jan 6, 2026 at 6:56 AM CET, Maurice Hieronymus wrote:
> On Mon, 2026-01-05 at 23:03 +0100, Danilo Krummrich wrote:
>> On Mon Jan 5, 2026 at 10:11 PM CET, Maurice Hieronymus wrote:
>> > Before I start implementing, I want to reach common ground.
>> > 
>> > In my opinion a derive macro which implements Display would be
>> > perfectly fine, as long as the name suggests what it does. So for
>> > example #[derive(DisplayEnumVariant)]. This would communicate the
>> > intent clearly to the user.
>> > 
>> > Benno, would you be okay with that? If not, Gary and Danilo, are

I'd prefer if we stay a bit more cautious about directly deriving
`Display`. The trait with the variant name sounds like a very sensible
idea.

We can talk about this in the team in our weekly meeting, they might
change my mind :)

>> > you
>> > fine with the proposed trait implementation (e.g. the variant_name
>> > function)?
>> 
>> Actually, it might even be reasonable to have both. In the Nova
>> driver we have
>> the case that we want to print the enum variant exactly as it is
>> defined in the
>> code and a lowercase version of the enum variant.
>> 
>> > Are there any common use-cases where one wants to change the case
>> > of
>> > the enum variants? If not, I would not implement an argument and
>> > rather
>> > name the macro accordingly, so the intent is clear.
>> 
>> As mentioned above, we do have a case in Nova where we also want a
>> lowercase
>> representation to construct a firmware path with.
>
> So there would be the need to have two derive macros:
>
> 1. #[derive(DisplayEnumVariant)]
> Implements Display for all enum variants as they are (original case).
>
> 2. #[derive(ImplementVariantName(Case::Lowercase))]
> Implements the mentioned trait. Case could be an Enum where one could
> choose between Case::Lowercase and Case::Original.

You'll need to use a helper attribute, something like:

    #[derive(VariantName)]
    #[variant_name(case = "lowercase")]

Cheers,
Benno
Re: [PATCH v2 1/2] rust: macros: Add derive Display for enums
Posted by Benno Lossin 2 days, 8 hours ago
On Mon Jan 5, 2026 at 11:29 AM CET, Danilo Krummrich wrote:
> On Mon Jan 5, 2026 at 10:02 AM CET, Benno Lossin wrote:
>> On Sun Jan 4, 2026 at 9:07 PM CET, Maurice Hieronymus wrote:
>>> Add a derive macro that implements kernel::fmt::Display for enums.
>>> The macro outputs the exact variant name as written, preserving case.
>>>
>>> This supports all enum variant types: unit, tuple, and struct variants.
>>> For variants with data, only the variant name is displayed.
>>
>> I don't think we should be adding this. Display is designed for
>> user-facing output and so it should always be carefully designed and no
>> automation should exist for it.
>
> In general I agree, but simple stringification of an enum variant for a Display
> implementation is a very common use-case and it seems pretty unfortunate to have
> to fall back to either do the below (especially if there are a lot of enum
> variants) or having to go the declarative path of doing something as in [1].
>
> Especially in combination with things like FromPrimitive and ToPrimitive it gets
> us rid of the cases where we need such declarative macro mess.
>
> Eventually, drivers will most likely implement their own proc macro for this or
> repeat the declarative macro pattern over and over again.

When the definition already uses declarative macros, adding the Display
impl there is the correct way to do it IMO. If it is just a normal
definition, then a match is annoying when you have many variants.

> Maybe we should just pick a more specific name for such a derive macro than
> macros::Display.
>
> Maybe something along the lines of macros::EnumVariantDisplay? We could also
> have an optional argument indicating whether it should be converted to lower /
> upper case.

I'm still skeptical about having a derive macro for `Display`. What
about adding & deriving the following trait instead:

    pub trait EnumVariantName {
        fn variant_name(&self) -> &'static str;
    }

To print this, you of course need to call the function, but it is much
more self-descriptive than printing the `Chipset` directly.

Cheers,
Benno
Re: [PATCH v2 1/2] rust: macros: Add derive Display for enums
Posted by Danilo Krummrich 2 days, 8 hours ago
On Mon Jan 5, 2026 at 3:42 PM CET, Benno Lossin wrote:
> I'm still skeptical about having a derive macro for `Display`. What
> about adding & deriving the following trait instead:
>
>     pub trait EnumVariantName {
>         fn variant_name(&self) -> &'static str;
>     }

With a derive macro for this trait, that sounds absolutely reasonable -- a
corresponding Display implementation becomes trivial with this.
Re: [PATCH v2 1/2] rust: macros: Add derive Display for enums
Posted by Maurice Hieronymus 2 days, 7 hours ago
On Mon, 2026-01-05 at 16:00 +0100, Danilo Krummrich wrote:
> On Mon Jan 5, 2026 at 3:42 PM CET, Benno Lossin wrote:
> > I'm still skeptical about having a derive macro for `Display`. What
> > about adding & deriving the following trait instead:
> > 
> >     pub trait EnumVariantName {
> >         fn variant_name(&self) -> &'static str;
> >     }
> 
> With a derive macro for this trait, that sounds absolutely reasonable
> -- a
> corresponding Display implementation becomes trivial with this.

Sounds good to me too. I will change my implementation and send a V3
shortly.