From 39166fc191233fe60dea1054aee0faaee4899c21 Mon Sep 17 00:00:00 2001 From: y86-dev Date: Fri, 19 Apr 2024 15:01:47 +0200 Subject: [PATCH] make `Chain[Pin]Init` private --- src/__internal.rs | 70 +++++++++++++++++++ src/lib.rs | 70 ++----------------- .../ui/compile-fail/init/invalid_init.stderr | 1 - 3 files changed, 74 insertions(+), 67 deletions(-) diff --git a/src/__internal.rs b/src/__internal.rs index e63228d..19728f2 100644 --- a/src/__internal.rs +++ b/src/__internal.rs @@ -52,6 +52,76 @@ where } } +/// An initializer returned by [`PinInit::pin_chain`]. +pub(crate) struct ChainPinInit( + pub(crate) I, + pub(crate) F, + pub(crate) Invariant<(E, *const T)>, +); + +// SAFETY: The `__pinned_init` function is implemented such that it +// - returns `Ok(())` on successful initialization, +// - returns `Err(err)` on error and in this case `slot` will be dropped. +// - considers `slot` pinned. +unsafe impl PinInit for ChainPinInit +where + I: PinInit, + F: FnOnce(Pin<&mut T>) -> Result<(), E>, +{ + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: All requirements fulfilled since this function is `__pinned_init`. + unsafe { self.0.__pinned_init(slot)? }; + // SAFETY: The above call initialized `slot` and we still have unique access. + let val = unsafe { &mut *slot }; + // SAFETY: `slot` is considered pinned. + let val = unsafe { Pin::new_unchecked(val) }; + (self.1)(val).map_err(|e| { + // SAFETY: `slot` was initialized above. + unsafe { core::ptr::drop_in_place(slot) }; + e + }) + } +} + +/// An initializer returned by [`Init::chain`]. +pub(crate) struct ChainInit( + pub(crate) I, + pub(crate) F, + pub(crate) Invariant<(E, *const T)>, +); + +// SAFETY: The `__init` function is implemented such that it +// - returns `Ok(())` on successful initialization, +// - returns `Err(err)` on error and in this case `slot` will be dropped. +unsafe impl Init for ChainInit +where + I: Init, + F: FnOnce(&mut T) -> Result<(), E>, +{ + unsafe fn __init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: All requirements fulfilled since this function is `__init`. + unsafe { self.0.__pinned_init(slot)? }; + // SAFETY: The above call initialized `slot` and we still have unique access. + (self.1)(unsafe { &mut *slot }).map_err(|e| { + // SAFETY: `slot` was initialized above. + unsafe { core::ptr::drop_in_place(slot) }; + e + }) + } +} + +// SAFETY: `__pinned_init` behaves exactly the same as `__init`. +unsafe impl PinInit for ChainInit +where + I: Init, + F: FnOnce(&mut T) -> Result<(), E>, +{ + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: `__init` has less strict requirements compared to `__pinned_init`. + unsafe { self.__init(slot) } + } +} + /// This trait is only implemented via the `#[pin_data]` proc-macro. It is used to facilitate /// the pin projections within the initializers. /// diff --git a/src/lib.rs b/src/lib.rs index 7720033..c59b040 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -729,38 +729,11 @@ pub unsafe trait PinInit: Sized { /// Ok(()) /// }); /// ``` - fn pin_chain(self, f: F) -> ChainPinInit + fn pin_chain(self, f: F) -> impl PinInit where F: FnOnce(Pin<&mut T>) -> Result<(), E>, { - ChainPinInit(self, f, PhantomData) - } -} - -/// An initializer returned by [`PinInit::pin_chain`]. -pub struct ChainPinInit(I, F, __internal::Invariant<(E, *const T)>); - -// SAFETY: The `__pinned_init` function is implemented such that it -// - returns `Ok(())` on successful initialization, -// - returns `Err(err)` on error and in this case `slot` will be dropped. -// - considers `slot` pinned. -unsafe impl PinInit for ChainPinInit -where - I: PinInit, - F: FnOnce(Pin<&mut T>) -> Result<(), E>, -{ - unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { - // SAFETY: All requirements fulfilled since this function is `__pinned_init`. - unsafe { self.0.__pinned_init(slot)? }; - // SAFETY: The above call initialized `slot` and we still have unique access. - let val = unsafe { &mut *slot }; - // SAFETY: `slot` is considered pinned. - let val = unsafe { Pin::new_unchecked(val) }; - (self.1)(val).map_err(|e| { - // SAFETY: `slot` was initialized above. - unsafe { core::ptr::drop_in_place(slot) }; - e - }) + __internal::ChainPinInit(self, f, PhantomData) } } @@ -831,46 +804,11 @@ pub unsafe trait Init: PinInit { /// Ok(()) /// }); /// ``` - fn chain(self, f: F) -> ChainInit + fn chain(self, f: F) -> impl Init where F: FnOnce(&mut T) -> Result<(), E>, { - ChainInit(self, f, PhantomData) - } -} - -/// An initializer returned by [`Init::chain`]. -pub struct ChainInit(I, F, __internal::Invariant<(E, *const T)>); - -// SAFETY: The `__init` function is implemented such that it -// - returns `Ok(())` on successful initialization, -// - returns `Err(err)` on error and in this case `slot` will be dropped. -unsafe impl Init for ChainInit -where - I: Init, - F: FnOnce(&mut T) -> Result<(), E>, -{ - unsafe fn __init(self, slot: *mut T) -> Result<(), E> { - // SAFETY: All requirements fulfilled since this function is `__init`. - unsafe { self.0.__pinned_init(slot)? }; - // SAFETY: The above call initialized `slot` and we still have unique access. - (self.1)(unsafe { &mut *slot }).map_err(|e| { - // SAFETY: `slot` was initialized above. - unsafe { core::ptr::drop_in_place(slot) }; - e - }) - } -} - -// SAFETY: `__pinned_init` behaves exactly the same as `__init`. -unsafe impl PinInit for ChainInit -where - I: Init, - F: FnOnce(&mut T) -> Result<(), E>, -{ - unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { - // SAFETY: `__init` has less strict requirements compared to `__pinned_init`. - unsafe { self.__init(slot) } + __internal::ChainInit(self, f, PhantomData) } } diff --git a/tests/ui/compile-fail/init/invalid_init.stderr b/tests/ui/compile-fail/init/invalid_init.stderr index 2d18d8c..b6a004e 100644 --- a/tests/ui/compile-fail/init/invalid_init.stderr +++ b/tests/ui/compile-fail/init/invalid_init.stderr @@ -7,5 +7,4 @@ error[E0277]: the trait bound `impl pinned_init::PinInit: Init` is not 20 | | }); | |______^ the trait `Init` is not implemented for `impl pinned_init::PinInit` | - = help: the trait `Init` is implemented for `ChainInit` = note: this error originates in the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info)