Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to CoercePointee macro, with examples #1130

Draft
wants to merge 1 commit into
base: rust-next
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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