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)
next prev 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