From: "Gary Guo" <gary@garyguo.net>
To: "Alexandre Courbot" <acourbot@nvidia.com>, "Gary Guo" <gary@garyguo.net>
Cc: "Danilo Krummrich" <dakr@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Trevor Gross" <tmgross@umich.edu>,
"Tamir Duberstein" <tamird@kernel.org>,
"Onur Özkan" <work@onurozkan.dev>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Bjorn Helgaas" <bhelgaas@google.com>,
"Krzysztof Wilczyński" <kwilczynski@kernel.org>,
driver-core@lists.linux.dev, rust-for-linux@vger.kernel.org,
linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev,
dri-devel@lists.freedesktop.org, linux-pci@vger.kernel.org
Subject: Re: [PATCH v2 02/16] rust: io: add `IoRepr` trait
Date: Tue, 18 Aug 2026 15:41:35 +0100 [thread overview]
Message-ID: <DKS5CNQNI0XQ.2EDHGGIQ95FHK@garyguo.net> (raw)
In-Reply-To: <DKL5Q2P868GQ.29WSPCWX4HTHJ@nvidia.com>
On Mon Aug 10, 2026 at 10:30 AM BST, Alexandre Courbot wrote:
> On Thu Aug 6, 2026 at 1:35 AM JST, Gary Guo wrote:
>> +/// Trait indicating the underlying primitive types to be used for I/O operations.
>> +///
>> +/// Implementing trait allows arbitrary types to be used for I/O operations, not just raw
>> +/// primitives.
>> +///
>> +/// The layout of the type and the underlying primitive must match; this is enforced via const
>> +/// assertions when I/O methods are used, as the type system cannot represent this.
>> +/// [`IoRepr::from_repr`] and [`IoRepr::into_expr`] can be overridden for conversions, however it
>> +/// should be noted that they are only invoked on value read/write operations and are not invoked
>> +/// on byte operations such as [`Io::copy_read`].
>> +///
>> +/// # Examples
>> +///
>> +/// ```
>> +/// # use kernel::io::*;
>> +/// #[repr(transparent)]
>> +/// #[derive(FromBytes, IntoBytes)]
>> +/// pub struct MyNewType(u32);
>> +///
>> +/// impl IoRepr for MyNewType {
>> +/// type Repr = u32;
>> +/// }
>> +///
>> +/// #[repr(C)]
>> +/// pub struct MyStruct {
>> +/// raw: u32,
>> +/// new_type: MyNewType,
>> +/// }
>> +///
>> +/// # fn test(mmio: Mmio<'_, MyStruct>) {
>> +/// // let mmio: Mmio<'_, MyStruct>;
>> +/// let val: u32 = io_read!(mmio, .raw); // Raw primitive read
>> +/// io_write!(mmio, .raw, val); // Raw primitve write
>> +/// let val: MyNewType = io_read!(mmio, .new_type); // Read via `IoRepr`.
>> +/// io_write!(mmio, .new_type, val); // Write via `IoRepr`.
>> +/// # }
>> +/// ```
>> +pub trait IoRepr: FromBytes + IntoBytes + Sized {
>> + /// The backing I/O capable type.
>> + type Repr: FromBytes + IntoBytes;
>> +
>> + /// Convert from [`IoRepr::Repr`] to `Self`.
>> + #[inline(always)]
>> + fn from_repr(repr: Self::Repr) -> Self {
>> + transmute_neo(repr)
>> + }
>> +
>> + /// Convert from `Self` to [`IoRepr::Repr`].
>> + #[inline(always)]
>> + fn into_repr(this: Self) -> Self::Repr {
>> + transmute_neo(this)
>> + }
>> +}
>> +
>> +macro_rules! impl_io_repr {
>> + ($($ty:ty => $backing:ty,)*) => {
>> + $(impl IoRepr for $ty {
>> + type Repr = $backing;
>> + })*
>> + };
>> +}
>> +
>> +impl_io_repr! {
>> + u8 => u8,
>> + u16 => u16,
>> + u32 => u32,
>> + u64 => u64,
>> + i8 => u8,
>> + i16 => u16,
>> + i32 => u32,
>> + i64 => u64,
>> +}
>
> ... and `IoRepr` and its implementations for primitive types should also
> be part of `transmute` IMHO (after being renamed to e.g. `Repr`), for
> there is nothing I/O exclusive to it. It just indicates that one type
> can be represented by another, a property that is again useful outside
> of I/O.
>
> That way `bitfield` gets a dependency on `transmute` rather than `io`,
> which doesn't break layering.
>
> In order to avoid `Repr::Repr` we can also rename the associated type to
> `Raw` and update the method names accordingly to `from_raw`/`into_raw` -
> which would have allowed us to remove the `bitfield` methods of the same
> name if they weren't needed in const context! But at least it makes
> things align nicely.
So I am working on this design for `kernel::mem`:
pub const unsafe fn transmute_neo_unchecked<Src, Dst>(val: Src) -> Dst { ... }
pub const fn transmute_neo<Src: IntoBytes, Dst: FromBytes>(val: Src) -> Dst { ... }
// Round-trip transmutable.
pub unsafe trait AsRepr: Sized {
/// Primitive representation of this type.
type Repr;
unsafe fn from_repr_unchecked(repr: Self::Repr) -> Self { ... }
fn into_repr(this: Self) -> Self::Repr { ... }
// Name from conceptually having this (not actually added)
// fn as_repr(this: &Self) -> &Self::Repr { ... }
}
// Bi-directional transmutable.
pub unsafe trait AsReprMut: AsRepr {
fn from_repr(repr: Self::Repr) -> Self { ... }
// Name from conceptually having this (not actually added)
// fn as_repr_mut(this: &mut Self) -> &mut Self::Repr { ... }
}
This design works well with both `Atomic` and `Io`: atomic can use
`T: AsRepr<Repr: AtomicImpl>` while I/O can use
`T: AsReprMut<Repr>, IO: IoCapable<<T as AsReprMut>::Repr>`.
One thing that I ran into is with signed/unsignedness of repr. Say for example
you have
#[repr(i8)]
enum Foo {
...
}
Then it'd be more natural to have
type Repr = i8;
Similarly if user specified u8, then we would naturally want to put u8 there.
However, to avoid duplicating signed/unsignedness code, `Atomic` and `Io` would
need to pick a preferred signedness. So far, `Atomic` uses signed integers,
while `Io` uses unsigned integers.
Would it make sense to canonicalize everything to unsigned integers (even if
users explicitly specify signed integer) for this trait, and convert `Atomic` to
use unsigned types as impl (we can always cast sign back in the impl before
calling C)?
Best,
Gary
next prev parent reply other threads:[~2026-08-18 14:41 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-05 16:35 [PATCH v2 00/16] rust: io: support register projections and remove relative registers Gary Guo
2026-08-05 16:35 ` [PATCH v2 01/16] rust: io: add static `cast()` method for views Gary Guo
2026-08-10 9:29 ` Alexandre Courbot
2026-08-13 17:29 ` Gary Guo
2026-08-05 16:35 ` [PATCH v2 02/16] rust: io: add `IoRepr` trait Gary Guo
2026-08-10 9:30 ` Alexandre Courbot
2026-08-10 11:21 ` Gary Guo
2026-08-12 4:51 ` Alexandre Courbot
2026-08-18 14:41 ` Gary Guo [this message]
2026-08-05 16:35 ` [PATCH v2 03/16] rust: io: support register projections Gary Guo
2026-08-10 9:30 ` Alexandre Courbot
2026-08-10 11:23 ` Gary Guo
2026-08-05 16:35 ` [PATCH v2 04/16] rust: io: register: handle one register at a time Gary Guo
2026-08-10 9:30 ` Alexandre Courbot
2026-08-05 16:35 ` [PATCH v2 05/16] rust: io: register extract offset computation to helper rules Gary Guo
2026-08-10 9:31 ` Alexandre Courbot
2026-08-05 16:35 ` [PATCH v2 06/16] rust: io: register: allow explicit base type specification Gary Guo
2026-08-10 9:32 ` Alexandre Courbot
2026-08-05 16:35 ` [PATCH v2 07/16] gpu: nova-core: specify base type for registers Gary Guo
2026-08-05 16:35 ` [PATCH v2 08/16] drm/tyr: " Gary Guo
2026-08-05 16:59 ` Gary Guo
2026-08-05 16:35 ` [PATCH v2 09/16] samples: rust: pci: " Gary Guo
2026-08-05 16:35 ` [PATCH v2 10/16] rust: io: register: make register have a typed base Gary Guo
2026-08-05 16:35 ` [PATCH v2 11/16] rust: io: register: support fixed offset register without bitfield Gary Guo
2026-08-12 9:01 ` Alexandre Courbot
2026-08-05 16:35 ` [PATCH v2 12/16] gpu: nova-core: use projection for PFALCON and PFALCON2 registers Gary Guo
2026-08-12 14:48 ` Alexandre Courbot
2026-08-12 20:44 ` John Hubbard
2026-08-14 13:05 ` Gary Guo
2026-08-05 16:35 ` [PATCH v2 13/16] gpu: nova-core: convert hshub0 from relative register to projection Gary Guo
2026-08-05 16:35 ` [PATCH v2 14/16] rust: io: register: remove relative registers Gary Guo
2026-08-13 0:58 ` Alexandre Courbot
2026-08-05 16:35 ` [PATCH v2 15/16] rust: io: register: remove `Register` trait and cleanup macro Gary Guo
2026-08-14 13:56 ` Alexandre Courbot
2026-08-05 16:35 ` [PATCH v2 16/16] rust: io: register: unify handling of register with/without bitfields Gary Guo
2026-08-14 13:56 ` Alexandre Courbot
2026-08-14 14:27 ` Gary 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=DKS5CNQNI0XQ.2EDHGGIQ95FHK@garyguo.net \
--to=gary@garyguo.net \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=airlied@gmail.com \
--cc=aliceryhl@google.com \
--cc=bhelgaas@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=driver-core@lists.linux.dev \
--cc=kwilczynski@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=nova-gpu@lists.linux.dev \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=tamird@kernel.org \
--cc=tmgross@umich.edu \
--cc=work@onurozkan.dev \
/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