Skip to content

Add documentation for derive(CoercePointee) #136351

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

Merged
merged 1 commit into from
Feb 1, 2025
Merged
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
190 changes: 189 additions & 1 deletion library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,195 @@ pub trait FnPtr: Copy + Clone {
fn addr(self) -> *const ();
}

/// Derive macro generating impls of traits related to smart pointers.
/// Derive macro that makes a smart pointer usable with trait objects.
///
/// # What this macro does
///
/// This macro is intended to be used with user-defined pointer types, and makes it possible to
/// perform coercions on the pointee of the user-defined pointer. There are two aspects to this:
///
/// ## Unsizing coercions of the pointee
///
/// By using the macro, the following example will compile:
/// ```
/// #![feature(derive_coerce_pointee)]
/// use std::marker::CoercePointee;
/// use std::ops::Deref;
///
/// #[derive(CoercePointee)]
/// #[repr(transparent)]
/// struct MySmartPointer<T: ?Sized>(Box<T>);
///
/// impl<T: ?Sized> Deref for MySmartPointer<T> {
/// type Target = T;
/// fn deref(&self) -> &T {
/// &self.0
/// }
/// }
///
/// trait MyTrait {}
///
/// impl MyTrait for i32 {}
///
/// fn main() {
/// let ptr: MySmartPointer<i32> = MySmartPointer(Box::new(4));
///
/// // This coercion would be an error without the derive.
/// let ptr: MySmartPointer<dyn MyTrait> = ptr;
/// }
/// ```
/// Without the `#[derive(CoercePointee)]` macro, this example would fail with the following error:
/// ```text
/// error[E0308]: mismatched types
/// --> src/main.rs:11:44
/// |
/// 11 | let ptr: MySmartPointer<dyn MyTrait> = ptr;
/// | --------------------------- ^^^ expected `MySmartPointer<dyn MyTrait>`, found `MySmartPointer<i32>`
/// | |
/// | expected due to this
/// |
/// = note: expected struct `MySmartPointer<dyn MyTrait>`
/// found struct `MySmartPointer<i32>`
/// = help: `i32` implements `MyTrait` so you could box the found value and coerce it to the trait object `Box<dyn MyTrait>`, you will have to change the expected type as well
/// ```
///
/// ## Dyn compatibility
///
/// This macro allows you to dispatch on the user-defined pointer type. That is, traits using the
/// type as a receiver are dyn-compatible. For example, this compiles:
///
/// ```
/// #![feature(arbitrary_self_types, derive_coerce_pointee)]
/// use std::marker::CoercePointee;
/// use std::ops::Deref;
///
/// #[derive(CoercePointee)]
/// #[repr(transparent)]
/// struct MySmartPointer<T: ?Sized>(Box<T>);
///
/// impl<T: ?Sized> Deref for MySmartPointer<T> {
/// type Target = T;
/// fn deref(&self) -> &T {
/// &self.0
/// }
/// }
///
/// // You can always define this trait. (as long as you have #![feature(arbitrary_self_types)])
/// trait MyTrait {
/// fn func(self: MySmartPointer<Self>);
/// }
///
/// // But using `dyn MyTrait` requires #[derive(CoercePointee)].
/// fn call_func(value: MySmartPointer<dyn MyTrait>) {
/// value.func();
/// }
/// ```
/// If you remove the `#[derive(CoercePointee)]` annotation from the struct, then the above example
/// will fail with this error message:
/// ```text
/// error[E0038]: the trait `MyTrait` is not dyn compatible
/// --> src/lib.rs:21:36
/// |
/// 17 | fn func(self: MySmartPointer<Self>);
/// | -------------------- help: consider changing method `func`'s `self` parameter to be `&self`: `&Self`
/// ...
/// 21 | fn call_func(value: MySmartPointer<dyn MyTrait>) {
/// | ^^^^^^^^^^^ `MyTrait` is not dyn compatible
/// |
/// note: for a trait to be dyn compatible it needs to allow building a vtable
/// for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
/// --> src/lib.rs:17:19
/// |
/// 16 | trait MyTrait {
/// | ------- this trait is not dyn compatible...
/// 17 | fn func(self: MySmartPointer<Self>);
/// | ^^^^^^^^^^^^^^^^^^^^ ...because method `func`'s `self` parameter cannot be dispatched on
/// ```
///
/// # Requirements for using the macro
///
/// This macro can only be used if:
/// * The type is a `#[repr(transparent)]` struct.
/// * The type of its non-zero-sized field must either be a standard library pointer type
/// (reference, raw pointer, `NonNull`, `Box`, `Rc`, `Arc`, etc.) or another user-defined type
/// also using the `#[derive(CoercePointee)]` macro.
/// * Zero-sized fields must not mention any generic parameters unless the zero-sized field has
/// type [`PhantomData`].
///
/// ## Multiple type parameters
///
/// If the type has multiple type parameters, then you must explicitly specify which one should be
/// used for dynamic dispatch. For example:
/// ```
/// # #![feature(derive_coerce_pointee)]
/// # use std::marker::{CoercePointee, PhantomData};
/// #[derive(CoercePointee)]
/// #[repr(transparent)]
/// struct MySmartPointer<#[pointee] T: ?Sized, U> {
/// ptr: Box<T>,
/// _phantom: PhantomData<U>,
/// }
/// ```
/// Specifying `#[pointee]` when the struct has only one type parameter is allowed, but not required.
///
/// # Examples
///
/// A custom implementation of the `Rc` type:
/// ```
/// #![feature(derive_coerce_pointee)]
/// use std::marker::CoercePointee;
/// use std::ops::Deref;
/// use std::ptr::NonNull;
///
/// #[derive(CoercePointee)]
/// #[repr(transparent)]
/// pub struct Rc<T: ?Sized> {
/// inner: NonNull<RcInner<T>>,
/// }
///
/// struct RcInner<T: ?Sized> {
/// refcount: usize,
/// value: T,
/// }
///
/// impl<T: ?Sized> Deref for Rc<T> {
/// type Target = T;
/// fn deref(&self) -> &T {
/// let ptr = self.inner.as_ptr();
/// unsafe { &(*ptr).value }
/// }
/// }
///
/// impl<T> Rc<T> {
/// pub fn new(value: T) -> Self {
/// let inner = Box::new(RcInner {
/// refcount: 1,
/// value,
/// });
/// Self {
/// inner: NonNull::from(Box::leak(inner)),
/// }
/// }
/// }
///
/// impl<T: ?Sized> Clone for Rc<T> {
/// fn clone(&self) -> Self {
/// // A real implementation would handle overflow here.
/// unsafe { (*self.inner.as_ptr()).refcount += 1 };
/// Self { inner: self.inner }
/// }
/// }
///
/// impl<T: ?Sized> Drop for Rc<T> {
/// fn drop(&mut self) {
/// let ptr = self.inner.as_ptr();
/// unsafe { (*ptr).refcount -= 1 };
/// if unsafe { (*ptr).refcount } == 0 {
/// drop(unsafe { Box::from_raw(ptr) });
/// }
/// }
/// }
/// ```
#[rustc_builtin_macro(CoercePointee, attributes(pointee))]
#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)]
#[unstable(feature = "derive_coerce_pointee", issue = "123430")]
Expand Down
Loading