Description
Tracked by #123430
Stabilization: #133820
What is being proposed for stabilization
This stabilization report concerns the macro specified by RFC3621,
now called CoercePointee
.
This macro enables the derivation of trait implementation of Unsize
, CoerceUnsize
and DispatchFromDyn
traits, both of which are unstable at the moment, under a well-defined and structured schema, so that the users who would like to allow their custom type to admit unsizing coercion and use of dyn
DST in one of its generic type parameter in a safe way. The greatest use case of this macro is to allow users to equip their types with this behaviour without dependence on alloc
crate, or when alloc
is not available and a custom implementation of pointer-like data structure in the likes of Rc
and Arc
is highly desirable. The most prominent example is the kernel
crate by Rust-for-Linux, which would greatly benefit from this macro due to reduction of boilerplate, and reduce the project's dependence on unstable features behind Unsize
, CoerceUnsize
and DispatchFromDyn
.
In a nutshell, derive(CoercePointee)
derives the implementation of CoerceUnsize
and DispatchFromDyn
traits on the target struct
definition with all the necessary trait bounds. It identifies one generic type variable in the generic list of the target struct
, that is either uniquely annotated with the #[pointee]
attribute or is the only type variable among the generics. This identified generic, which is called source type in this document, will be treated as the target of unsizing operation and dyn
trait object dispatch. Correspondingly, the resultant type after the unsizing coercion will be called target type in this document. In case additional trait bounds applies on the source type, the said trait bounds will be migrated to both the source type and the target type in the trait implementation.
Out of necessity of unsizing coercion, the macro requires the struct
to adopt the repr(transparent)
layout. The only data field in the struct
definition, which is required by this layout, should also implement CoerceUnsize
and DispatchFromDyn
at the moment, or at least conform to requirement of the unsizing coercion and trait object dispatching protocol.
As an example, here is how the generated code would look like after expanding the macro. The following is a user source that invokes this macro.
pub trait MyTrait<T: ?Sized> {}
#[derive(core::marker::CoercePointee)]
#[repr(transparent)]
pub struct MyPointer2<'a, Y, Z: MyTrait<T>, #[pointee] T: ?Sized + MyTrait<T>, X: MyTrait<T> = ()>
where
Y: MyTrait<T>,
{
data: &'a mut T,
x: core::marker::PhantomData<X>,
}
This is the expansion result. The source type T
after the unsizing coercion is assumed to be __S
and the trait bounds requested by the original definition are migrated for __S
as well throughtout.
#[repr(transparent)]
pub struct MyPointer2<
'a, Y, Z: MyTrait<T>,
#[pointee] T: ?Sized + MyTrait<T>,
X: MyTrait<T> = ()
>
where Y: MyTrait<T>
{
data: &'a mut T,
x: core::marker::PhantomData<X>,
}
#[automatically_derived]
impl<
'a, Y,
Z: MyTrait<T> + MyTrait<__S>,
T: ?Sized + MyTrait<T> + ::core::marker::Unsize<__S>,
__S: ?Sized + MyTrait<__S>,
X: MyTrait<T> + MyTrait<__S>
>
::core::ops::DispatchFromDyn<MyPointer2<'a, Y, Z, __S, X>> for MyPointer2<'a, Y, Z, T, X>
where Y: MyTrait<T>, Y: MyTrait<__S> {
}
#[automatically_derived]
impl<
'a, Y,
Z: MyTrait<T> + MyTrait<__S>,
T: ?Sized + MyTrait<T> + ::core::marker::Unsize<__S>,
__S: ?Sized + MyTrait<__S>,
X: MyTrait<T> + MyTrait<__S>
>
::core::ops::CoerceUnsized<MyPointer2<'a, Y, Z, __S, X>> for MyPointer2<'a, Y, Z, T, X>
where Y: MyTrait<T>, Y: MyTrait<__S> {
}
Future interaction
This stabilization of this macro does not require the stabilization of any of the unstable traits mentioned. This macro aims at stabilising a subset of features thereof, which has widely proliferated in the ecosystem, without blocking further development of DSTs and unsizing coercion. In case of change in the design of these language features, as long as basic provision of the coercion operation remains the same, the macro should be updated to use the new facility inside its implementation when necessary, to preserve only the semantics and capabilities that this macro exposes users to.