diff options
| author | Gary Guo <gary@garyguo.net> | 2026-05-12 13:09:48 +0100 |
|---|---|---|
| committer | Gary Guo <gary@garyguo.net> | 2026-05-14 20:18:14 +0100 |
| commit | fea304ec875454360a3be106e0baad96032bf9fe (patch) | |
| tree | 25346c4763b8d26c6be97b357bbd8b08288b270a /rust | |
| parent | 4b60f38cd2a4b2d3288377f25100f8d67015988a (diff) | |
| download | ath-fea304ec875454360a3be106e0baad96032bf9fe.tar.gz | |
rust: pin-init: internal: add `PhantomInvariant` and `PhantomInvariantLifetime`
Currently, the `pin_init` library has an `Invariant` type alias, and it is
instantiated using `PhantomData`. Generated code from `pin_data` on the
other hand cannot access the crate-local type alias, so it generates
`PhantomData<fn(T) -> T>` directly. This is all very inconsistent, despite
the exact same use case of ensuring invariance.
Add `PhantomInvariant` and `PhantomInvariantLifetime` and switch all users
that need to express the concept of invariance to use these. They're
polyfills of unstable types in the same names in the Rust standard library.
Link: https://patch.msgid.link/20260512-pin-init-sync-v1-3-81963130dfbd@garyguo.net
Signed-off-by: Gary Guo <gary@garyguo.net>
Diffstat (limited to 'rust')
| -rw-r--r-- | rust/pin-init/internal/src/pin_data.rs | 12 | ||||
| -rw-r--r-- | rust/pin-init/src/__internal.rs | 56 | ||||
| -rw-r--r-- | rust/pin-init/src/lib.rs | 12 |
3 files changed, 59 insertions, 21 deletions
diff --git a/rust/pin-init/internal/src/pin_data.rs b/rust/pin-init/internal/src/pin_data.rs index 0199d01433086..44d0bd18e4ae0 100644 --- a/rust/pin-init/internal/src/pin_data.rs +++ b/rust/pin-init/internal/src/pin_data.rs @@ -180,10 +180,8 @@ fn generate_unpin_impl( #where_token #predicates { - __phantom_pin: ::core::marker::PhantomData<fn(&'__pin ()) -> &'__pin ()>, - __phantom: ::core::marker::PhantomData< - fn(#ident #ty_generics) -> #ident #ty_generics - >, + __phantom_pin: ::pin_init::__internal::PhantomInvariantLifetime<'__pin>, + __phantom: ::pin_init::__internal::PhantomInvariant<#ident #ty_generics>, #(#pinned_fields),* } @@ -434,9 +432,7 @@ fn generate_the_pin_data( #vis struct __ThePinData #generics #whr { - __phantom: ::core::marker::PhantomData< - fn(#struct_name #ty_generics) -> #struct_name #ty_generics - >, + __phantom: ::pin_init::__internal::PhantomInvariant<#struct_name #ty_generics>, } impl #impl_generics ::core::clone::Clone for __ThePinData #ty_generics @@ -465,7 +461,7 @@ fn generate_the_pin_data( type PinData = __ThePinData #ty_generics; unsafe fn __pin_data() -> Self::PinData { - __ThePinData { __phantom: ::core::marker::PhantomData } + __ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new() } } } diff --git a/rust/pin-init/src/__internal.rs b/rust/pin-init/src/__internal.rs index 5720a621aed74..e54d90a4742e4 100644 --- a/rust/pin-init/src/__internal.rs +++ b/rust/pin-init/src/__internal.rs @@ -7,20 +7,62 @@ use super::*; -/// See the [nomicon] for what subtyping is. See also [this table]. +/// Zero-sized type used to mark a type as invariant. +/// +/// This is a polyfill for the [unstable type] in the standard library of the same name. /// -/// The reason for not using `PhantomData<*mut T>` is that that type never implements [`Send`] and -/// [`Sync`]. Hence `fn(*mut T) -> *mut T` is used, as that type always implements them. +/// See the [nomicon] for what subtyping is. See also [this table]. /// +/// [unstable type]: https://doc.rust-lang.org/nightly/std/marker/struct.PhantomInvariant.html /// [nomicon]: https://doc.rust-lang.org/nomicon/subtyping.html /// [this table]: https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns -pub(crate) type Invariant<T> = PhantomData<fn(*mut T) -> *mut T>; +#[repr(transparent)] +pub struct PhantomInvariant<T: ?Sized>(PhantomData<fn(T) -> T>); + +impl<T: ?Sized> Clone for PhantomInvariant<T> { + #[inline(always)] + fn clone(&self) -> Self { + *self + } +} + +impl<T: ?Sized> Copy for PhantomInvariant<T> {} + +impl<T: ?Sized> Default for PhantomInvariant<T> { + #[inline(always)] + fn default() -> Self { + Self::new() + } +} + +impl<T: ?Sized> PhantomInvariant<T> { + #[inline(always)] + pub const fn new() -> Self { + Self(PhantomData) + } +} + +/// Zero-sized type used to mark a lifetime as invariant. +/// +/// This is a polyfill for the [unstable type] in the standard library of the same name. +/// +/// [unstable type]: https://doc.rust-lang.org/nightly/std/marker/struct.PhantomInvariantLifetime.html +#[repr(transparent)] +#[derive(Clone, Copy, Default)] +pub struct PhantomInvariantLifetime<'a>(PhantomInvariant<&'a ()>); + +impl PhantomInvariantLifetime<'_> { + #[inline(always)] + pub const fn new() -> Self { + Self(PhantomInvariant::new()) + } +} /// Module-internal type implementing `PinInit` and `Init`. /// /// It is unsafe to create this type, since the closure needs to fulfill the same safety /// requirement as the `__pinned_init`/`__init` functions. -pub(crate) struct InitClosure<F, T: ?Sized, E>(pub(crate) F, pub(crate) Invariant<(E, T)>); +pub(crate) struct InitClosure<F, T: ?Sized, E>(pub(crate) F, pub(crate) PhantomInvariant<(E, T)>); // SAFETY: While constructing the `InitClosure`, the user promised that it upholds the // `__init` invariants. @@ -126,7 +168,7 @@ pub unsafe trait InitData: Copy { } } -pub struct AllData<T: ?Sized>(Invariant<T>); +pub struct AllData<T: ?Sized>(PhantomInvariant<T>); impl<T: ?Sized> Clone for AllData<T> { fn clone(&self) -> Self { @@ -146,7 +188,7 @@ unsafe impl<T: ?Sized> HasInitData for T { type InitData = AllData<T>; unsafe fn __init_data() -> Self::InitData { - AllData(PhantomData) + AllData(PhantomInvariant::new()) } } diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs index 80c476e605f72..4098c65d63c3a 100644 --- a/rust/pin-init/src/lib.rs +++ b/rust/pin-init/src/lib.rs @@ -947,12 +947,12 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized { where F: FnOnce(Pin<&mut T>) -> Result<(), E>, { - ChainPinInit(self, f, PhantomData) + ChainPinInit(self, f, __internal::PhantomInvariant::new()) } } /// An initializer returned by [`PinInit::pin_chain`]. -pub struct ChainPinInit<I, F, T: ?Sized, E>(I, F, __internal::Invariant<(E, T)>); +pub struct ChainPinInit<I, F, T: ?Sized, E>(I, F, __internal::PhantomInvariant<(E, T)>); // SAFETY: The `__pinned_init` function is implemented such that it // - returns `Ok(())` on successful initialization, @@ -1055,12 +1055,12 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> { where F: FnOnce(&mut T) -> Result<(), E>, { - ChainInit(self, f, PhantomData) + ChainInit(self, f, __internal::PhantomInvariant::new()) } } /// An initializer returned by [`Init::chain`]. -pub struct ChainInit<I, F, T: ?Sized, E>(I, F, __internal::Invariant<(E, T)>); +pub struct ChainInit<I, F, T: ?Sized, E>(I, F, __internal::PhantomInvariant<(E, T)>); // SAFETY: The `__init` function is implemented such that it // - returns `Ok(())` on successful initialization, @@ -1108,7 +1108,7 @@ where pub const unsafe fn pin_init_from_closure<T: ?Sized, E>( f: impl FnOnce(*mut T) -> Result<(), E>, ) -> impl PinInit<T, E> { - __internal::InitClosure(f, PhantomData) + __internal::InitClosure(f, __internal::PhantomInvariant::new()) } /// Creates a new [`Init<T, E>`] from the given closure. @@ -1127,7 +1127,7 @@ pub const unsafe fn pin_init_from_closure<T: ?Sized, E>( pub const unsafe fn init_from_closure<T: ?Sized, E>( f: impl FnOnce(*mut T) -> Result<(), E>, ) -> impl Init<T, E> { - __internal::InitClosure(f, PhantomData) + __internal::InitClosure(f, __internal::PhantomInvariant::new()) } /// Changes the to be initialized type. |
