@@ -716,52 +716,15 @@ pub mod unsync {
716
716
/// // 92
717
717
/// ```
718
718
pub struct Lazy < T , F = fn ( ) -> T > {
719
- state : Cell < State > ,
720
- data : Data < T , F > ,
721
- }
722
-
723
- /// Discriminant of the union.
724
- #[ derive( Debug , Clone , Copy ) ]
725
- enum State {
726
- /// `.init` has not been taken yet.
727
- Uninit ,
728
- /// `.init` has been *taken*, but the call has not completed (panic?), so there is no `.value` either.
729
- Poisoned ,
730
- /// `.value` has been set.
731
- Value ,
732
- }
733
-
734
- // One of the rare cases `#[repr(C)]` is not needed for an union ("externally tagged `enum`" pattern)
735
- union Data < T , F > {
736
- /// Idea: we don't need *mutation* to dispose of `F`, we can just let it be there, inert, behind a MD.
737
- ///
738
- /// This makes it so we remain covariant in `F`.
739
- init : mem:: ManuallyDrop < F > ,
740
- value : mem:: ManuallyDrop < UnsafeCell < T > > ,
741
- }
742
-
743
- impl < T , F > Drop for Lazy < T , F > {
744
- fn drop ( & mut self ) {
745
- match self . state . get_mut ( ) {
746
- State :: Value => unsafe { mem:: ManuallyDrop :: drop ( & mut self . data . value ) } ,
747
- State :: Uninit => unsafe { mem:: ManuallyDrop :: drop ( & mut self . data . init ) } ,
748
- State :: Poisoned => { }
749
- }
750
- }
719
+ cell : OnceCell < T > ,
720
+ init : Cell < Option < F > > ,
751
721
}
752
722
753
723
impl < T , F : RefUnwindSafe > RefUnwindSafe for Lazy < T , F > where OnceCell < T > : RefUnwindSafe { }
754
724
755
725
impl < T : fmt:: Debug , F > fmt:: Debug for Lazy < T , F > {
756
726
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
757
- match self . state . get ( ) {
758
- // `Lazy("some value")`
759
- State :: Value => {
760
- f. debug_tuple ( "Lazy" ) . field ( unsafe { & * self . data . value . get ( ) } ) . finish ( )
761
- }
762
- // `Uninit`, or `Poisoned`
763
- state => state. fmt ( f) ,
764
- }
727
+ f. debug_struct ( "Lazy" ) . field ( "cell" , & self . cell ) . field ( "init" , & ".." ) . finish ( )
765
728
}
766
729
}
767
730
@@ -781,28 +744,18 @@ pub mod unsync {
781
744
/// # }
782
745
/// ```
783
746
pub const fn new ( init : F ) -> Lazy < T , F > {
784
- Lazy {
785
- state : Cell :: new ( State :: Uninit ) ,
786
- data : Data { init : mem:: ManuallyDrop :: new ( init) } ,
787
- }
747
+ Lazy { cell : OnceCell :: new ( ) , init : Cell :: new ( Some ( init) ) }
788
748
}
789
749
790
750
/// Consumes this `Lazy` returning the stored value.
791
751
///
792
752
/// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
793
753
pub fn into_value ( this : Lazy < T , F > ) -> Result < T , F > {
794
- // Safety: beyond the typical "check discriminant before accessing corresponding union variant",
795
- // we have to be careful not to run `this`' `impl Drop` glue as we extract its fields,
796
- // hence the initial extra layer of `ManuallyDrop`.
797
- // Once that's done nothing is owned anymore, so we are free to `ManuallyDrop::take` what we want.
798
- let mut this = mem:: ManuallyDrop :: new ( this) ;
799
- match this. state . get_mut ( ) {
800
- State :: Value => {
801
- Ok ( unsafe { mem:: ManuallyDrop :: take ( & mut this. data . value ) } . into_inner ( ) )
802
- }
803
- State :: Uninit => Err ( unsafe { mem:: ManuallyDrop :: take ( & mut this. data . init ) } ) ,
804
- State :: Poisoned => panic ! ( "Lazy instance has previously been poisoned" ) ,
805
- }
754
+ let cell = this. cell ;
755
+ let init = this. init ;
756
+ cell. into_inner ( ) . ok_or_else ( || {
757
+ init. take ( ) . unwrap_or_else ( || panic ! ( "Lazy instance has previously been poisoned" ) )
758
+ } )
806
759
}
807
760
}
808
761
@@ -822,37 +775,10 @@ pub mod unsync {
822
775
/// assert_eq!(&*lazy, &92);
823
776
/// ```
824
777
pub fn force ( this : & Lazy < T , F > ) -> & T {
825
- match this. state . get ( ) {
826
- State :: Value => unsafe { & * this. data . value . get ( ) } ,
827
- State :: Uninit => {
828
- // Safety: `<*const _>::read(&*...)` is the by-ref counterpart of `ManuallyDrop::take`.
829
- // We are allowed to `take` the `F` once we have taken its `State::Uninit` discriminant.
830
- // We cannot put `State::Value` in its stead yet in case `init()` panics.
831
- // Hence the `Poisoned` / "empty `Lazy`" state.
832
- let init = unsafe {
833
- this. state . set ( State :: Poisoned ) ;
834
- <* const F >:: read ( & * this. data . init )
835
- } ;
836
- let value = init ( ) ;
837
- unsafe {
838
- // Safety: here we need to tread with caution, since we need to "pick a union variant"
839
- // without accidentally asserting that the `ManuallyDrop<... T ...>` is init since it still isn't.
840
- // Hence `ptr::addr_of!`.
841
- let ptr: * const mem:: ManuallyDrop < UnsafeCell < T > > =
842
- core:: ptr:: addr_of!( this. data. value) ;
843
- // There is no raw accessor on `ManuallyDrop`, but it's a `transparent` wrapper so we can
844
- // just `.cast()` that layer away.
845
- let ptr: * const UnsafeCell < T > = ptr. cast ( ) ;
846
- // To handle the `UnsafeCell` layer, no need for casts, there is a dedicated API.
847
- let ptr: * mut T = UnsafeCell :: raw_get ( ptr) ;
848
- // Once we've gotten the pointer, the rest is easy: set the value and discriminants accordingly.
849
- ptr. write ( value) ;
850
- this. state . set ( State :: Value ) ;
851
- & * ptr
852
- }
853
- }
854
- State :: Poisoned => panic ! ( "Lazy instance has previously been poisoned" ) ,
855
- }
778
+ this. cell . get_or_init ( || match this. init . take ( ) {
779
+ Some ( f) => f ( ) ,
780
+ None => panic ! ( "Lazy instance has previously been poisoned" ) ,
781
+ } )
856
782
}
857
783
858
784
/// Forces the evaluation of this lazy value and returns a mutable reference to
@@ -870,25 +796,14 @@ pub mod unsync {
870
796
/// assert_eq!(*lazy, 92);
871
797
/// ```
872
798
pub fn force_mut ( this : & mut Lazy < T , F > ) -> & mut T {
873
- let state = this. state . get_mut ( ) ;
874
- match state {
875
- State :: Value => unsafe { ( * this. data . value ) . get_mut ( ) } ,
876
- State :: Uninit => {
877
- // Safety: same reasoning as with `force`, except simpler since we can use `&mut` accesses.
878
- // (so we do not need to worry about any `UnsafeCell` shenanigans)
879
- let init = unsafe {
880
- * state = State :: Poisoned ;
881
- mem:: ManuallyDrop :: take ( & mut this. data . init )
882
- } ;
883
- let value = mem:: ManuallyDrop :: new ( init ( ) . into ( ) ) ;
884
- unsafe {
885
- core:: ptr:: addr_of_mut!( this. data. value) . write ( value) ;
886
- * state = State :: Value ;
887
- ( * this. data . value ) . get_mut ( )
888
- }
889
- }
890
- State :: Poisoned => panic ! ( "Lazy instance has previously been poisoned" ) ,
799
+ if this. cell . get_mut ( ) . is_none ( ) {
800
+ let value = match this. init . get_mut ( ) . take ( ) {
801
+ Some ( f) => f ( ) ,
802
+ None => panic ! ( "Lazy instance has previously been poisoned" ) ,
803
+ } ;
804
+ this. cell = OnceCell :: with_value ( value) ;
891
805
}
806
+ this. cell . get_mut ( ) . unwrap_or_else ( || unreachable ! ( ) )
892
807
}
893
808
894
809
/// Gets the reference to the result of this lazy value if
@@ -905,7 +820,7 @@ pub mod unsync {
905
820
/// assert_eq!(Lazy::get(&lazy), Some(&92));
906
821
/// ```
907
822
pub fn get ( this : & Lazy < T , F > ) -> Option < & T > {
908
- matches ! ( this. state . get( ) , State :: Value ) . then ( || unsafe { & * this . data . value . get ( ) } )
823
+ this. cell . get ( )
909
824
}
910
825
911
826
/// Gets the mutable reference to the result of this lazy value if
@@ -922,8 +837,7 @@ pub mod unsync {
922
837
/// assert_eq!(Lazy::get_mut(&mut lazy), Some(&mut 92));
923
838
/// ```
924
839
pub fn get_mut ( this : & mut Lazy < T , F > ) -> Option < & mut T > {
925
- matches ! ( this. state. get_mut( ) , State :: Value )
926
- . then ( || unsafe { ( * this. data . value ) . get_mut ( ) } )
840
+ this. cell . get_mut ( )
927
841
}
928
842
}
929
843
@@ -1376,8 +1290,7 @@ pub mod sync {
1376
1290
let cell = this. cell ;
1377
1291
let init = this. init ;
1378
1292
cell. into_inner ( ) . ok_or_else ( || {
1379
- init. into_inner ( )
1380
- . unwrap_or_else ( || panic ! ( "Lazy instance has previously been poisoned" ) )
1293
+ init. take ( ) . unwrap_or_else ( || panic ! ( "Lazy instance has previously been poisoned" ) )
1381
1294
} )
1382
1295
}
1383
1296
}
0 commit comments