Skip to content

Commit

Permalink
rust: switch to CoercePointee macro, with examples
Browse files Browse the repository at this point in the history
Since Rust 1.84.0 the macro `CoercePointee` has
been made public on Nightly, so that it answers
the some usability questions.

If one wants to equip generic types with the
ability to weaken itself and to work with
unsized types with dynamic dispatching.
This feature is useful such that Rust code are
enabled to work with a family of types satisfying
the same protocol or Rust traits, while the same
safety guarantees are still uphold [1].
Examples of this weakening include those from
*[u8; 8]* to *[u8]*, eliding the concrete size of
the array; and a concrete type *T* to *dyn Trait*
where *T* implements the trait or traits *Trait*.

As of date, the exact language features to enable
this type weakening is still under stabilization
effort. Nevertheless, Alice Ryhl has proposed [2]
a very valuable combination of them such that a
user can enable this feature via a procedural
macro `CoercePointee` without much verbosity and
without declaring dependence on the relevant
unstable language features.

Alice has previously filed a patch [3] to
demonstrate the capability of this macro.
This patch provides further updates to incorporate
recent changes to the proposal in [2] and paves
the way for the final stabilization of the
feature in the Rust language.

A minimal demostration code is added to
the *samples/rust/rust_print_main.rs* module.

The use of the macro is now gated behind the
available Rust version *1.83.0*.
The *kernel* crate will still be as functional on
the prior Rust toolchains.

Link: https://doc.rust-lang.org/stable/nomicon/exotic-sizes.html?highlight=dynamic#dynamically-sized-types-dsts [1]
Link: https://rust-lang.github.io/rfcs/3621-derive-smart-pointer.html [2]
Link: https://lore.kernel.org/all/20240823-derive-smart-pointer-v1-1-53769cd37239@google.com/ [3]
Signed-off-by: Xiangfei Ding <dingxiangfei2009@protonmail.ch>
  • Loading branch information
dingxiangfei2009 committed Nov 29, 2024
1 parent 1dc707e commit 06e4e20
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 10 deletions.
3 changes: 3 additions & 0 deletions init/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1978,6 +1978,9 @@ config RUST

If unsure, say N.

config RUST_COERCE_POINTEE
def_bool y if RUSTC_VERSION >= 108300

config RUSTC_VERSION_TEXT
string
depends on RUST
Expand Down
7 changes: 4 additions & 3 deletions rust/kernel/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
#![no_std]
#![feature(arbitrary_self_types)]
#![feature(coerce_unsized)]
#![feature(dispatch_from_dyn)]
#![cfg_attr(CONFIG_RUST_COERCE_POINTEE, feature(derive_coerce_pointee))]
#![cfg_attr(not(CONFIG_RUST_COERCE_POINTEE), feature(coerce_unsized))]
#![cfg_attr(not(CONFIG_RUST_COERCE_POINTEE), feature(dispatch_from_dyn))]
#![cfg_attr(not(CONFIG_RUST_COERCE_POINTEE), feature(unsize))]
#![feature(inline_const)]
#![feature(lint_reasons)]
#![feature(unsize)]

// Ensure conditional compilation based on the kernel configuration works;
// otherwise we may silently break things like initcall handling.
Expand Down
9 changes: 6 additions & 3 deletions rust/kernel/list/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use crate::alloc::{AllocError, Flags};
use crate::prelude::*;
use crate::sync::{Arc, ArcBorrow, UniqueArc};
use core::marker::{PhantomPinned, Unsize};
use core::marker::PhantomPinned;
use core::ops::Deref;
use core::pin::Pin;
use core::sync::atomic::{AtomicBool, Ordering};
Expand Down Expand Up @@ -159,6 +159,7 @@ pub use impl_list_arc_safe;
///
/// [`List`]: crate::list::List
#[repr(transparent)]
#[cfg_attr(CONFIG_RUST_COERCE_POINTEE, derive(core::marker::CoercePointee))]
pub struct ListArc<T, const ID: u64 = 0>
where
T: ListArcSafe<ID> + ?Sized,
Expand Down Expand Up @@ -443,18 +444,20 @@ where

// This is to allow coercion from `ListArc<T>` to `ListArc<U>` if `T` can be converted to the
// dynamically-sized type (DST) `U`.
#[cfg(not(CONFIG_RUST_COERCE_POINTEE))]
impl<T, U, const ID: u64> core::ops::CoerceUnsized<ListArc<U, ID>> for ListArc<T, ID>
where
T: ListArcSafe<ID> + Unsize<U> + ?Sized,
T: ListArcSafe<ID> + core::marker::Unsize<U> + ?Sized,
U: ListArcSafe<ID> + ?Sized,
{
}

// This is to allow `ListArc<U>` to be dispatched on when `ListArc<T>` can be coerced into
// `ListArc<U>`.
#[cfg(not(CONFIG_RUST_COERCE_POINTEE))]
impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc<T, ID>
where
T: ListArcSafe<ID> + Unsize<U> + ?Sized,
T: ListArcSafe<ID> + core::marker::Unsize<U> + ?Sized,
U: ListArcSafe<ID> + ?Sized,
{
}
Expand Down
15 changes: 11 additions & 4 deletions rust/kernel/sync/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{
use core::{
alloc::Layout,
fmt,
marker::{PhantomData, Unsize},
marker::PhantomData,
mem::{ManuallyDrop, MaybeUninit},
ops::{Deref, DerefMut},
pin::Pin,
Expand Down Expand Up @@ -125,6 +125,8 @@ mod std_vendor;
/// let coerced: Arc<dyn MyTrait> = obj;
/// # Ok::<(), Error>(())
/// ```
#[repr(transparent)]
#[cfg_attr(CONFIG_RUST_COERCE_POINTEE, derive(core::marker::CoercePointee))]
pub struct Arc<T: ?Sized> {
ptr: NonNull<ArcInner<T>>,
_p: PhantomData<ArcInner<T>>,
Expand Down Expand Up @@ -172,10 +174,12 @@ impl<T: ?Sized> ArcInner<T> {

// This is to allow coercion from `Arc<T>` to `Arc<U>` if `T` can be converted to the
// dynamically-sized type (DST) `U`.
impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Arc<U>> for Arc<T> {}
#[cfg(not(CONFIG_RUST_COERCE_POINTEE))]
impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Arc<U>> for Arc<T> {}

// This is to allow `Arc<U>` to be dispatched on when `Arc<T>` can be coerced into `Arc<U>`.
impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<Arc<U>> for Arc<T> {}
#[cfg(not(CONFIG_RUST_COERCE_POINTEE))]
impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<Arc<U>> for Arc<T> {}

// SAFETY: It is safe to send `Arc<T>` to another thread when the underlying `T` is `Sync` because
// it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs
Expand Down Expand Up @@ -471,14 +475,17 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {
/// obj.as_arc_borrow().use_reference();
/// # Ok::<(), Error>(())
/// ```
#[repr(transparent)]
#[cfg_attr(CONFIG_RUST_COERCE_POINTEE, derive(core::marker::CoercePointee))]
pub struct ArcBorrow<'a, T: ?Sized + 'a> {
inner: NonNull<ArcInner<T>>,
_p: PhantomData<&'a ()>,
}

// This is to allow `ArcBorrow<U>` to be dispatched on when `ArcBorrow<T>` can be coerced into
// `ArcBorrow<U>`.
impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<ArcBorrow<'_, U>>
#[cfg(not(CONFIG_RUST_COERCE_POINTEE))]
impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<ArcBorrow<'_, U>>
for ArcBorrow<'_, T>
{
}
Expand Down
15 changes: 15 additions & 0 deletions samples/rust/rust_print_main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,21 @@ fn arc_print() -> Result {
// Uses `dbg` to print, will move `c` (for temporary debugging purposes).
dbg!(c);

{
use core::fmt::Display;
fn arc_dyn_print(arc: &Arc<dyn Display>) {
pr_info!("Arc<dyn Display> says {arc}");
}
// `Arc` can be used to delegate dynamic dispatch and the following is an example.
// Both `i32` and `&str` implements `Display`.
// This enables us to express a unified behaviour, contract or protocol
// on both `i32` and `&str` into a single `Arc` type `Arc<dyn Display>`.
let a_i32_display: Arc<dyn Display> = Arc::new(42i32, GFP_KERNEL)?;
let a_str_display: Arc<dyn Display> = a.clone();
arc_dyn_print(&a_i32_display);
arc_dyn_print(&a_str_display);
}

// Pretty-prints the debug formatting with lower-case hexadecimal integers.
pr_info!("{:#x?}", a);

Expand Down

0 comments on commit 06e4e20

Please sign in to comment.