@@ -767,6 +767,79 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
767
767
/// deallocate.
768
768
/// - `slot` will not move until it is dropped, i.e. it will be pinned.
769
769
unsafe fn __pinned_init ( self , slot : * mut T ) -> Result < ( ) , E > ;
770
+
771
+ /// First initializes the value using `self` then calls the function `f` with the initialized
772
+ /// value.
773
+ ///
774
+ /// If `f` returns an error the value is dropped and the initializer will forward the error.
775
+ ///
776
+ /// # Examples
777
+ ///
778
+ /// ```rust
779
+ /// # #![allow(clippy::disallowed_names)]
780
+ /// use kernel::{types::Opaque, init::pin_init_from_closure};
781
+ /// #[repr(C)]
782
+ /// struct RawFoo([u8; 16]);
783
+ /// extern {
784
+ /// fn init_foo(_: *mut RawFoo);
785
+ /// }
786
+ ///
787
+ /// #[pin_data]
788
+ /// struct Foo {
789
+ /// #[pin]
790
+ /// raw: Opaque<RawFoo>,
791
+ /// }
792
+ ///
793
+ /// impl Foo {
794
+ /// fn setup(self: Pin<&mut Self>) {
795
+ /// pr_info!("Setting up foo");
796
+ /// }
797
+ /// }
798
+ ///
799
+ /// let foo = pin_init!(Foo {
800
+ /// raw <- unsafe {
801
+ /// Opaque::ffi_init(|s| {
802
+ /// init_foo(s);
803
+ /// })
804
+ /// },
805
+ /// }).pin_chain(|foo| {
806
+ /// foo.setup();
807
+ /// Ok(())
808
+ /// });
809
+ /// ```
810
+ fn pin_chain < F > ( self , f : F ) -> ChainPinInit < Self , F , T , E >
811
+ where
812
+ F : FnOnce ( Pin < & mut T > ) -> Result < ( ) , E > ,
813
+ {
814
+ ChainPinInit ( self , f, PhantomData )
815
+ }
816
+ }
817
+
818
+ /// An initializer returned by [`PinInit::pin_chain`].
819
+ pub struct ChainPinInit < I , F , T : ?Sized , E > ( I , F , __internal:: Invariant < ( E , Box < T > ) > ) ;
820
+
821
+ // SAFETY: The `__pinned_init` function is implemented such that it
822
+ // - returns `Ok(())` on successful initialization,
823
+ // - returns `Err(err)` on error and in this case `slot` will be dropped.
824
+ // - considers `slot` pinned.
825
+ unsafe impl < T : ?Sized , E , I , F > PinInit < T , E > for ChainPinInit < I , F , T , E >
826
+ where
827
+ I : PinInit < T , E > ,
828
+ F : FnOnce ( Pin < & mut T > ) -> Result < ( ) , E > ,
829
+ {
830
+ unsafe fn __pinned_init ( self , slot : * mut T ) -> Result < ( ) , E > {
831
+ // SAFETY: All requirements fulfilled since this function is `__pinned_init`.
832
+ unsafe { self . 0 . __pinned_init ( slot) ? } ;
833
+ // SAFETY: The above call initialized `slot` and we still have unique access.
834
+ let val = unsafe { & mut * slot } ;
835
+ // SAFETY: `slot` is considered pinned.
836
+ let val = unsafe { Pin :: new_unchecked ( val) } ;
837
+ ( self . 1 ) ( val) . map_err ( |e| {
838
+ // SAFETY: `slot` was initialized above.
839
+ unsafe { core:: ptr:: drop_in_place ( slot) } ;
840
+ e
841
+ } )
842
+ }
770
843
}
771
844
772
845
/// An initializer for `T`.
@@ -808,6 +881,75 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
808
881
/// - the caller does not touch `slot` when `Err` is returned, they are only permitted to
809
882
/// deallocate.
810
883
unsafe fn __init ( self , slot : * mut T ) -> Result < ( ) , E > ;
884
+
885
+ /// First initializes the value using `self` then calls the function `f` with the initialized
886
+ /// value.
887
+ ///
888
+ /// If `f` returns an error the value is dropped and the initializer will forward the error.
889
+ ///
890
+ /// # Examples
891
+ ///
892
+ /// ```rust
893
+ /// # #![allow(clippy::disallowed_names)]
894
+ /// use kernel::{types::Opaque, init::{self, init_from_closure}};
895
+ /// struct Foo {
896
+ /// buf: [u8; 1_000_000],
897
+ /// }
898
+ ///
899
+ /// impl Foo {
900
+ /// fn setup(&mut self) {
901
+ /// pr_info!("Setting up foo");
902
+ /// }
903
+ /// }
904
+ ///
905
+ /// let foo = init!(Foo {
906
+ /// buf <- init::zeroed()
907
+ /// }).chain(|foo| {
908
+ /// foo.setup();
909
+ /// Ok(())
910
+ /// });
911
+ /// ```
912
+ fn chain < F > ( self , f : F ) -> ChainInit < Self , F , T , E >
913
+ where
914
+ F : FnOnce ( & mut T ) -> Result < ( ) , E > ,
915
+ {
916
+ ChainInit ( self , f, PhantomData )
917
+ }
918
+ }
919
+
920
+ /// An initializer returned by [`Init::chain`].
921
+ pub struct ChainInit < I , F , T : ?Sized , E > ( I , F , __internal:: Invariant < ( E , Box < T > ) > ) ;
922
+
923
+ // SAFETY: The `__init` function is implemented such that it
924
+ // - returns `Ok(())` on successful initialization,
925
+ // - returns `Err(err)` on error and in this case `slot` will be dropped.
926
+ unsafe impl < T : ?Sized , E , I , F > Init < T , E > for ChainInit < I , F , T , E >
927
+ where
928
+ I : Init < T , E > ,
929
+ F : FnOnce ( & mut T ) -> Result < ( ) , E > ,
930
+ {
931
+ unsafe fn __init ( self , slot : * mut T ) -> Result < ( ) , E > {
932
+ // SAFETY: All requirements fulfilled since this function is `__init`.
933
+ unsafe { self . 0 . __pinned_init ( slot) ? } ;
934
+ // SAFETY: The above call initialized `slot` and we still have unique access.
935
+ ( self . 1 ) ( unsafe { & mut * slot } ) . map_err ( |e| {
936
+ // SAFETY: `slot` was initialized above.
937
+ unsafe { core:: ptr:: drop_in_place ( slot) } ;
938
+ e
939
+ } )
940
+ }
941
+ }
942
+
943
+ // SAFETY: `__pinned_init` behaves exactly the same as `__init`.
944
+ unsafe impl < T : ?Sized , E , I , F > PinInit < T , E > for ChainInit < I , F , T , E >
945
+ where
946
+ I : Init < T , E > ,
947
+ F : FnOnce ( & mut T ) -> Result < ( ) , E > ,
948
+ {
949
+ unsafe fn __pinned_init ( self , slot : * mut T ) -> Result < ( ) , E > {
950
+ // SAFETY: `__init` has less strict requirements compared to `__pinned_init`.
951
+ unsafe { self . __init ( slot) }
952
+ }
811
953
}
812
954
813
955
/// Creates a new [`PinInit<T, E>`] from the given closure.
0 commit comments