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 <[email protected]> --- 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
