Rust for Linux List
 help / color / mirror / Atom feed
From: Kaiqi Guo <chaoji_xinren@163.com>
To: rust-for-linux@vger.kernel.org, Miguel Ojeda <ojeda@kernel.org>
Cc: Jesung Yang <y.j3ms.n@gmail.com>,
	Alexandre Courbot <acourbot@nvidia.com>,
	Danilo Krummrich <dakr@kernel.org>,
	nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org,
	linux-kernel@vger.kernel.org, Kaiqi Guo <chaoji_xinren@163.com>
Subject: [PATCH v6 03/10] rust: macros: add `convert` helper attribute
Date: Tue, 29 Sep 2026 21:58:48 +0800	[thread overview]
Message-ID: <20260929135855.36775-4-chaoji_xinren@163.com> (raw)
In-Reply-To: <20260929135855.36775-1-chaoji_xinren@163.com>

From: Jesung Yang <y.j3ms.n@gmail.com>

Introduce `#[convert(...)]`, a common helper attribute for the `Into`
and `TryFrom` derive macros. This helps avoid repeating the same types
in `#[into(...)]` and `#[try_from(...)]` when deriving both traits for
the same enum.

For example:

    #[derive(Into, TryFrom)]
    #[try_from(u8)]
    #[into(u8)]
    enum Enum {
        A,
        B,
    }

The above snippet can be shortened to:

    #[derive(Into, TryFrom)]
    #[convert(u8)]
    enum Enum {
        A,
        B,
    }

Signed-off-by: Jesung Yang <y.j3ms.n@gmail.com>
Signed-off-by: Kaiqi Guo <chaoji_xinren@163.com>
---
 rust/macros/convert.rs |  7 +++-
 rust/macros/lib.rs     | 78 +++++++++++++++++++++++++++++++++++++++---
 2 files changed, 80 insertions(+), 5 deletions(-)

diff --git a/rust/macros/convert.rs b/rust/macros/convert.rs
index c64e35447859..21d79bca16a0 100644
--- a/rust/macros/convert.rs
+++ b/rust/macros/convert.rs
@@ -150,6 +150,10 @@ fn get_helper_name(&self) -> &'static str {
             Self::TryFrom => "try_from",
         }
     }
+
+    fn get_common_helper_name(&self) -> &'static str {
+        "convert"
+    }
 }
 
 fn parse_attrs(
@@ -157,6 +161,7 @@ fn parse_attrs(
     attrs: &[Attribute],
 ) -> syn::Result<(Vec<Type>, bool, Option<Ident>)> {
     let helper = target.get_helper_name();
+    let common_helper = target.get_common_helper_name();
 
     let mut is_repr_c = false;
     let mut repr_ty = None;
@@ -175,7 +180,7 @@ fn parse_attrs(
                 // Delegate `repr` attribute validation to rustc.
                 Ok(())
             })?;
-        } else if attr.path().is_ident(helper) {
+        } else if attr.path().is_ident(helper) || attr.path().is_ident(common_helper) {
             let args = attr.parse_args_with(Punctuated::<Type, Token![,]>::parse_terminated)?;
             helper_tys.extend(args);
         }
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 8b4f3e9dc860..cc6a96516c93 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -557,6 +557,10 @@ pub fn CovariantForLt(input: TokenStream) -> TokenStream {
 /// - The macro uses the `into` custom attribute or `repr` attribute to generate [`From`]
 ///   implementations. `into` always takes precedence over `repr`.
 ///
+/// - In addition to `into`, the `convert` custom attribute is supported. The purpose of
+///   this attribute is to avoid repetition when deriving both [`Into`] and [`TryFrom`]
+///   for the same enum. See ["With `#[convert(...)]`"](#with-convert) for an example.
+///
 /// - Currently, the macro does not support `repr(C)` fieldless enums since the actual
 ///   representation of discriminants is defined by rustc internally, and documentation
 ///   around it is not yet settled. See [Rust issue #124403] and [Rust PR #147017]
@@ -568,7 +572,7 @@ pub fn CovariantForLt(input: TokenStream) -> TokenStream {
 /// [Rust issue #124403]: https://github.com/rust-lang/rust/issues/124403
 /// [Rust PR #147017]: https://github.com/rust-lang/rust/pull/147017
 ///
-/// # Supported types in `#[into(...)]`
+/// # Supported types in `#[into(...)]` and `#[convert(...)]`
 ///
 /// - [`bool`]
 /// - Primitive integer types (e.g., [`i8`], [`u8`])
@@ -650,6 +654,36 @@ pub fn CovariantForLt(input: TokenStream) -> TokenStream {
 /// assert_eq!(Bounded::<u8, 4>::new::<1>(), foo_b);
 /// ```
 ///
+/// ## With `#[convert(...)]`
+///
+/// The macro implements `From<Foo>` for each `T` specified in `#[into(...)]`,
+/// which always overrides `#[repr(...)]`. `#[convert(...)]` is useful when the same type
+/// needs to be specified in both `#[into(...)]` and `#[try_from(...)]`:
+///
+/// ```rust
+/// # use kernel::prelude::*;
+/// use kernel::{
+///     macros::Into,
+///     macros::TryFrom,
+///     num::Bounded, //
+/// };
+///
+/// #[derive(Debug, Default, Into, PartialEq, TryFrom)]
+/// #[convert(bool)]
+/// #[repr(u8)]
+/// enum Foo {
+///     #[default]
+///     A,
+///     B,
+/// }
+///
+/// assert_eq!(false, Foo::A.into());
+/// assert_eq!(true, Foo::B.into());
+///
+/// assert_eq!(Ok(Foo::A), Foo::try_from(false));
+/// assert_eq!(Ok(Foo::B), Foo::try_from(true));
+/// ```
+///
 /// ## Compile-time Overflow Assertion
 ///
 /// The following examples do not compile:
@@ -702,7 +736,7 @@ pub fn CovariantForLt(input: TokenStream) -> TokenStream {
 /// #[repr(C)]
 /// struct Foo(u8);
 /// ```
-#[proc_macro_derive(Into, attributes(into))]
+#[proc_macro_derive(Into, attributes(into, convert))]
 pub fn derive_into(input: TokenStream) -> TokenStream {
     let input = parse_macro_input!(input as DeriveInput);
     convert::derive_into(input)
@@ -727,6 +761,11 @@ pub fn derive_into(input: TokenStream) -> TokenStream {
 /// - The macro uses the `try_from` custom attribute or `repr` attribute to generate
 ///   [`TryFrom`] implementations. `try_from` always takes precedence over `repr`.
 ///
+/// - In addition to `try_from`, the `convert` custom attribute is supported. The purpose
+///   of this attribute is to avoid repetition when deriving both [`Into`] and
+///   [`TryFrom`] for the same enum. See ["With `#[convert(...)]`"](#with-convert) for an
+///   example.
+///
 /// - Currently, the macro does not support `repr(C)` fieldless enums since the actual
 ///   representation of discriminants is defined by rustc internally, and documentation
 ///   around it is not yet settled. See [Rust issue #124403] and [Rust PR #147017]
@@ -739,7 +778,7 @@ pub fn derive_into(input: TokenStream) -> TokenStream {
 /// [Rust issue #124403]: https://github.com/rust-lang/rust/issues/124403
 /// [Rust PR #147017]: https://github.com/rust-lang/rust/pull/147017
 ///
-/// # Supported types in `#[try_from(...)]`
+/// # Supported types in `#[try_from(...)]` and `#[convert(...)]`
 ///
 /// - [`bool`]
 /// - Primitive integer types (e.g., [`i8`], [`u8`])
@@ -827,6 +866,37 @@ pub fn derive_into(input: TokenStream) -> TokenStream {
 /// assert_eq!(Ok(Foo::B), Foo::try_from(Bounded::<u8, 4>::new::<1>()));
 /// ```
 ///
+/// ## With `#[convert(...)]`
+///
+/// The macro implements `TryFrom<T>` for each `T` specified in `#[convert(...)]`,
+/// which always overrides `#[repr(...)]`. `#[convert(...)]` is useful when the same type
+/// needs to be specified in both `#[into(...)]` and `#[try_from(...)]`:
+///
+///
+/// ```rust
+/// # use kernel::prelude::*;
+/// use kernel::{
+///     macros::Into,
+///     macros::TryFrom,
+///     num::Bounded, //
+/// };
+///
+/// #[derive(Debug, Default, Into, PartialEq, TryFrom)]
+/// #[convert(bool)]
+/// #[repr(u8)]
+/// enum Foo {
+///     #[default]
+///     A,
+///     B,
+/// }
+///
+/// assert_eq!(Ok(Foo::A), Foo::try_from(false));
+/// assert_eq!(Ok(Foo::B), Foo::try_from(true));
+///
+/// assert_eq!(false, Foo::A.into());
+/// assert_eq!(true, Foo::B.into());
+/// ```
+///
 /// ## Compile-time Overflow Assertion
 ///
 /// The following examples do not compile:
@@ -879,7 +949,7 @@ pub fn derive_into(input: TokenStream) -> TokenStream {
 /// #[repr(C)]
 /// struct Foo(u8)
 /// ```
-#[proc_macro_derive(TryFrom, attributes(try_from))]
+#[proc_macro_derive(TryFrom, attributes(try_from, convert))]
 pub fn derive_try_from(input: TokenStream) -> TokenStream {
     let input = parse_macro_input!(input as DeriveInput);
     convert::derive_try_from(input)


  parent reply	other threads:[~2026-09-29 13:59 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-29 13:58 [PATCH v6 00/10] rust: add conversion derives and exhaustive From support Kaiqi Guo
2026-09-29 13:58 ` [PATCH v6 01/10] rust: macros: add derive macro for `Into` Kaiqi Guo
2026-09-29 13:58 ` [PATCH v6 02/10] rust: macros: add derive macro for `TryFrom` Kaiqi Guo
2026-09-29 13:58 ` Kaiqi Guo [this message]
2026-09-29 13:58 ` [PATCH v6 04/10] rust: macros: add private doctests for `Into` derive macro Kaiqi Guo
2026-09-29 13:58 ` [PATCH v6 05/10] rust: macros: add private doctests for `TryFrom` " Kaiqi Guo
2026-09-29 13:58 ` [PATCH v6 06/10] rust: macros: exercise the intended conversion doctest failures Kaiqi Guo
2026-09-29 18:47   ` Miguel Ojeda
2026-09-29 13:58 ` [PATCH v6 07/10] rust: macros: derive From for exhaustive enum conversions Kaiqi Guo
2026-09-29 13:58 ` [PATCH v6 08/10] rust: macros: test exhaustive conversion derives Kaiqi Guo
2026-09-29 13:58 ` [PATCH v6 09/10] rust: macros: validate and qualify conversion helper types Kaiqi Guo
2026-09-29 13:58 ` [PATCH v6 10/10] gpu: nova-core: use conversion derives for two register enums Kaiqi Guo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260929135855.36775-4-chaoji_xinren@163.com \
    --to=chaoji_xinren@163.com \
    --cc=acourbot@nvidia.com \
    --cc=dakr@kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nova-gpu@lists.linux.dev \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=y.j3ms.n@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox