@@ -850,6 +850,80 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
850850 /// deallocate.
851851 /// - `slot` will not move until it is dropped, i.e. it will be pinned.
852852 unsafe fn __pinned_init ( self , slot : * mut T ) -> Result < ( ) , E > ;
853+
854+ /// First initializes the value using `self` then calls the function `f` with the initialized
855+ /// value.
856+ ///
857+ /// If `f` returns an error the value is dropped and the initializer will forward the error.
858+ ///
859+ /// # Examples
860+ ///
861+ /// ```rust
862+ /// # #![allow(clippy::disallowed_names)]
863+ /// # use core::{convert::Infallible, pin::Pin};
864+ /// # use pinned_init::*;
865+ /// use pinned_init::pin_init_from_closure;
866+ /// #[repr(C)]
867+ /// struct RawFoo([u8; 16]);
868+ /// extern {
869+ /// fn init_foo(_: *mut RawFoo);
870+ /// }
871+ ///
872+ /// #[pin_data]
873+ /// struct Foo {
874+ /// #[pin]
875+ /// raw: RawFoo,
876+ /// }
877+ ///
878+ /// impl Foo {
879+ /// fn setup(self: Pin<&mut Self>) {
880+ /// println!("Setting up foo");
881+ /// }
882+ /// }
883+ ///
884+ /// let foo = pin_init!(Foo {
885+ /// raw <- unsafe { pin_init_from_closure(|slot| {
886+ /// init_foo(slot);
887+ /// Ok::<_, Infallible>(())
888+ /// }) },
889+ /// }).pin_chain(|foo| {
890+ /// foo.setup();
891+ /// Ok(())
892+ /// });
893+ /// ```
894+ fn pin_chain < F > ( self , f : F ) -> ChainPinInit < Self , F , T , E >
895+ where
896+ F : FnOnce ( Pin < & mut T > ) -> Result < ( ) , E > ,
897+ {
898+ ChainPinInit ( self , f, PhantomData )
899+ }
900+ }
901+
902+ /// An initializer returned by [`PinInit::pin_chain`].
903+ pub struct ChainPinInit < I , F , T : ?Sized , E > ( I , F , __internal:: Invariant < ( E , Box < T > ) > ) ;
904+
905+ // SAFETY: The `__pinned_init` function is implemented such that it
906+ // - returns `Ok(())` on successful initialization,
907+ // - returns `Err(err)` on error and in this case `slot` will be dropped.
908+ // - considers `slot` pinned.
909+ unsafe impl < T : ?Sized , E , I , F > PinInit < T , E > for ChainPinInit < I , F , T , E >
910+ where
911+ I : PinInit < T , E > ,
912+ F : FnOnce ( Pin < & mut T > ) -> Result < ( ) , E > ,
913+ {
914+ unsafe fn __pinned_init ( self , slot : * mut T ) -> Result < ( ) , E > {
915+ // SAFETY: All requirements fulfilled since this function is `__pinned_init`.
916+ unsafe { self . 0 . __pinned_init ( slot) ? } ;
917+ // SAFETY: The above call initialized `slot` and we still have unique access.
918+ let val = unsafe { & mut * slot } ;
919+ // SAFETY: `slot` is considered pinned.
920+ let val = unsafe { Pin :: new_unchecked ( val) } ;
921+ ( self . 1 ) ( val) . map_err ( |e| {
922+ // SAFETY: `slot` was initialized above.
923+ unsafe { core:: ptr:: drop_in_place ( slot) } ;
924+ e
925+ } )
926+ }
853927}
854928
855929/// An initializer for `T`.
@@ -882,7 +956,7 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
882956///
883957/// [`Arc<T>`]: alloc::sync::Arc
884958#[ must_use = "An initializer must be used in order to create its value." ]
885- pub unsafe trait Init < T : ?Sized , E = Infallible > : Sized {
959+ pub unsafe trait Init < T : ?Sized , E = Infallible > : PinInit < T , E > {
886960 /// Initializes `slot`.
887961 ///
888962 /// # Safety
@@ -891,16 +965,75 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: Sized {
891965 /// - the caller does not touch `slot` when `Err` is returned, they are only permitted to
892966 /// deallocate.
893967 unsafe fn __init ( self , slot : * mut T ) -> Result < ( ) , E > ;
968+
969+ /// First initializes the value using `self` then calls the function `f` with the initialized
970+ /// value.
971+ ///
972+ /// If `f` returns an error the value is dropped and the initializer will forward the error.
973+ ///
974+ /// # Examples
975+ ///
976+ /// ```rust
977+ /// # #![allow(clippy::disallowed_names)]
978+ /// # use pinned_init::*;
979+ /// # use core::convert::Infallible;
980+ /// use pinned_init::{self, init_from_closure};
981+ /// struct Foo {
982+ /// buf: [u8; 1_000_000],
983+ /// }
984+ ///
985+ /// impl Foo {
986+ /// fn setup(&mut self) {
987+ /// println!("Setting up foo");
988+ /// }
989+ /// }
990+ ///
991+ /// let foo = init!(Foo {
992+ /// buf <- zeroed::<_, Infallible>()
993+ /// }).chain(|foo| {
994+ /// foo.setup();
995+ /// Ok(())
996+ /// });
997+ /// ```
998+ fn chain < F > ( self , f : F ) -> ChainInit < Self , F , T , E >
999+ where
1000+ F : FnOnce ( & mut T ) -> Result < ( ) , E > ,
1001+ {
1002+ ChainInit ( self , f, PhantomData )
1003+ }
1004+ }
1005+
1006+ /// An initializer returned by [`Init::chain`].
1007+ pub struct ChainInit < I , F , T : ?Sized , E > ( I , F , __internal:: Invariant < ( E , Box < T > ) > ) ;
1008+
1009+ // SAFETY: The `__init` function is implemented such that it
1010+ // - returns `Ok(())` on successful initialization,
1011+ // - returns `Err(err)` on error and in this case `slot` will be dropped.
1012+ unsafe impl < T : ?Sized , E , I , F > Init < T , E > for ChainInit < I , F , T , E >
1013+ where
1014+ I : Init < T , E > ,
1015+ F : FnOnce ( & mut T ) -> Result < ( ) , E > ,
1016+ {
1017+ unsafe fn __init ( self , slot : * mut T ) -> Result < ( ) , E > {
1018+ // SAFETY: All requirements fulfilled since this function is `__init`.
1019+ unsafe { self . 0 . __pinned_init ( slot) ? } ;
1020+ // SAFETY: The above call initialized `slot` and we still have unique access.
1021+ ( self . 1 ) ( unsafe { & mut * slot } ) . map_err ( |e| {
1022+ // SAFETY: `slot` was initialized above.
1023+ unsafe { core:: ptr:: drop_in_place ( slot) } ;
1024+ e
1025+ } )
1026+ }
8941027}
8951028
896- // SAFETY: Every in-place initializer can also be used as a pin-initializer .
897- unsafe impl < T : ?Sized , E , I > PinInit < T , E > for I
1029+ // SAFETY: `__pinned_init` behaves exactly the same as `__init` .
1030+ unsafe impl < T : ?Sized , E , I , F > PinInit < T , E > for ChainInit < I , F , T , E >
8981031where
8991032 I : Init < T , E > ,
1033+ F : FnOnce ( & mut T ) -> Result < ( ) , E > ,
9001034{
9011035 unsafe fn __pinned_init ( self , slot : * mut T ) -> Result < ( ) , E > {
902- // SAFETY: `__init` meets the same requirements as `__pinned_init`, except that it does not
903- // require `slot` to not move after init.
1036+ // SAFETY: `__init` has less strict requirements compared to `__pinned_init`.
9041037 unsafe { self . __init ( slot) }
9051038 }
9061039}
@@ -953,13 +1086,20 @@ pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> {
9531086}
9541087
9551088// SAFETY: Every type can be initialized by-value.
956- unsafe impl < T > Init < T > for T {
957- unsafe fn __init ( self , slot : * mut T ) -> Result < ( ) , Infallible > {
1089+ unsafe impl < T , E > Init < T , E > for T {
1090+ unsafe fn __init ( self , slot : * mut T ) -> Result < ( ) , E > {
9581091 unsafe { slot. write ( self ) } ;
9591092 Ok ( ( ) )
9601093 }
9611094}
9621095
1096+ // SAFETY: Every type can be initialized by-value. `__pinned_init` calls `__init`.
1097+ unsafe impl < T , E > PinInit < T , E > for T {
1098+ unsafe fn __pinned_init ( self , slot : * mut T ) -> Result < ( ) , E > {
1099+ unsafe { self . __init ( slot) }
1100+ }
1101+ }
1102+
9631103/// Smart pointer that can initialize memory in-place.
9641104pub trait InPlaceInit < T > : Sized {
9651105 /// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
0 commit comments