Skip to content

Commit 06e4e20

Browse files
rust: switch to CoercePointee macro, with examples
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/[email protected]/ [3] Signed-off-by: Xiangfei Ding <[email protected]>
1 parent 1dc707e commit 06e4e20

File tree

5 files changed

+39
-10
lines changed

5 files changed

+39
-10
lines changed

init/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,6 +1978,9 @@ config RUST
19781978

19791979
If unsure, say N.
19801980

1981+
config RUST_COERCE_POINTEE
1982+
def_bool y if RUSTC_VERSION >= 108300
1983+
19811984
config RUSTC_VERSION_TEXT
19821985
string
19831986
depends on RUST

rust/kernel/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
1414
#![no_std]
1515
#![feature(arbitrary_self_types)]
16-
#![feature(coerce_unsized)]
17-
#![feature(dispatch_from_dyn)]
16+
#![cfg_attr(CONFIG_RUST_COERCE_POINTEE, feature(derive_coerce_pointee))]
17+
#![cfg_attr(not(CONFIG_RUST_COERCE_POINTEE), feature(coerce_unsized))]
18+
#![cfg_attr(not(CONFIG_RUST_COERCE_POINTEE), feature(dispatch_from_dyn))]
19+
#![cfg_attr(not(CONFIG_RUST_COERCE_POINTEE), feature(unsize))]
1820
#![feature(inline_const)]
1921
#![feature(lint_reasons)]
20-
#![feature(unsize)]
2122

2223
// Ensure conditional compilation based on the kernel configuration works;
2324
// otherwise we may silently break things like initcall handling.

rust/kernel/list/arc.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use crate::alloc::{AllocError, Flags};
88
use crate::prelude::*;
99
use crate::sync::{Arc, ArcBorrow, UniqueArc};
10-
use core::marker::{PhantomPinned, Unsize};
10+
use core::marker::PhantomPinned;
1111
use core::ops::Deref;
1212
use core::pin::Pin;
1313
use core::sync::atomic::{AtomicBool, Ordering};
@@ -159,6 +159,7 @@ pub use impl_list_arc_safe;
159159
///
160160
/// [`List`]: crate::list::List
161161
#[repr(transparent)]
162+
#[cfg_attr(CONFIG_RUST_COERCE_POINTEE, derive(core::marker::CoercePointee))]
162163
pub struct ListArc<T, const ID: u64 = 0>
163164
where
164165
T: ListArcSafe<ID> + ?Sized,
@@ -443,18 +444,20 @@ where
443444

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

453455
// This is to allow `ListArc<U>` to be dispatched on when `ListArc<T>` can be coerced into
454456
// `ListArc<U>`.
457+
#[cfg(not(CONFIG_RUST_COERCE_POINTEE))]
455458
impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc<T, ID>
456459
where
457-
T: ListArcSafe<ID> + Unsize<U> + ?Sized,
460+
T: ListArcSafe<ID> + core::marker::Unsize<U> + ?Sized,
458461
U: ListArcSafe<ID> + ?Sized,
459462
{
460463
}

rust/kernel/sync/arc.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::{
2626
use core::{
2727
alloc::Layout,
2828
fmt,
29-
marker::{PhantomData, Unsize},
29+
marker::PhantomData,
3030
mem::{ManuallyDrop, MaybeUninit},
3131
ops::{Deref, DerefMut},
3232
pin::Pin,
@@ -125,6 +125,8 @@ mod std_vendor;
125125
/// let coerced: Arc<dyn MyTrait> = obj;
126126
/// # Ok::<(), Error>(())
127127
/// ```
128+
#[repr(transparent)]
129+
#[cfg_attr(CONFIG_RUST_COERCE_POINTEE, derive(core::marker::CoercePointee))]
128130
pub struct Arc<T: ?Sized> {
129131
ptr: NonNull<ArcInner<T>>,
130132
_p: PhantomData<ArcInner<T>>,
@@ -172,10 +174,12 @@ impl<T: ?Sized> ArcInner<T> {
172174

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

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

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

479485
// This is to allow `ArcBorrow<U>` to be dispatched on when `ArcBorrow<T>` can be coerced into
480486
// `ArcBorrow<U>`.
481-
impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<ArcBorrow<'_, U>>
487+
#[cfg(not(CONFIG_RUST_COERCE_POINTEE))]
488+
impl<T: ?Sized + core::marker::Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<ArcBorrow<'_, U>>
482489
for ArcBorrow<'_, T>
483490
{
484491
}

samples/rust/rust_print_main.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ fn arc_print() -> Result {
3434
// Uses `dbg` to print, will move `c` (for temporary debugging purposes).
3535
dbg!(c);
3636

37+
{
38+
use core::fmt::Display;
39+
fn arc_dyn_print(arc: &Arc<dyn Display>) {
40+
pr_info!("Arc<dyn Display> says {arc}");
41+
}
42+
// `Arc` can be used to delegate dynamic dispatch and the following is an example.
43+
// Both `i32` and `&str` implements `Display`.
44+
// This enables us to express a unified behaviour, contract or protocol
45+
// on both `i32` and `&str` into a single `Arc` type `Arc<dyn Display>`.
46+
let a_i32_display: Arc<dyn Display> = Arc::new(42i32, GFP_KERNEL)?;
47+
let a_str_display: Arc<dyn Display> = a.clone();
48+
arc_dyn_print(&a_i32_display);
49+
arc_dyn_print(&a_str_display);
50+
}
51+
3752
// Pretty-prints the debug formatting with lower-case hexadecimal integers.
3853
pr_info!("{:#x?}", a);
3954

0 commit comments

Comments
 (0)