1- use crate :: cell:: Cell ;
1+ use crate :: cell:: UnsafeCell ;
22use crate :: fmt;
3+ use crate :: mem:: ManuallyDrop ;
34use crate :: ops:: Deref ;
45use crate :: panic:: { RefUnwindSafe , UnwindSafe } ;
5- use crate :: sync:: OnceLock ;
6+ use crate :: sync:: Once ;
7+
8+ use super :: once:: ExclusiveState ;
9+
10+ // We use the state of a Once as discriminant value. Upon creation, the state is
11+ // "incomplete" and `f` contains the initialization closure. In the first call to
12+ // `call_once`, `f` is taken and run. If it succeeds, `value` is set and the state
13+ // is changed to "complete". If it panics, the Once is poisoned, so none of the
14+ // two fields is initialized.
15+ union Data < T , F > {
16+ value : ManuallyDrop < T > ,
17+ f : ManuallyDrop < F > ,
18+ }
619
720/// A value which is initialized on the first access.
821///
@@ -43,16 +56,17 @@ use crate::sync::OnceLock;
4356/// ```
4457#[ unstable( feature = "once_cell" , issue = "74465" ) ]
4558pub struct LazyLock < T , F = fn ( ) -> T > {
46- cell : OnceLock < T > ,
47- init : Cell < Option < F > > ,
59+ once : Once ,
60+ data : UnsafeCell < Data < T , F > > ,
4861}
62+
4963impl < T , F : FnOnce ( ) -> T > LazyLock < T , F > {
5064 /// Creates a new lazy value with the given initializing
5165 /// function.
5266 #[ inline]
5367 #[ unstable( feature = "once_cell" , issue = "74465" ) ]
5468 pub const fn new ( f : F ) -> LazyLock < T , F > {
55- LazyLock { cell : OnceLock :: new ( ) , init : Cell :: new ( Some ( f) ) }
69+ LazyLock { once : Once :: new ( ) , data : UnsafeCell :: new ( Data { f : ManuallyDrop :: new ( f) } ) }
5670 }
5771
5872 /// Forces the evaluation of this lazy value and
@@ -74,10 +88,50 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
7488 #[ inline]
7589 #[ unstable( feature = "once_cell" , issue = "74465" ) ]
7690 pub fn force ( this : & LazyLock < T , F > ) -> & T {
77- this. cell . get_or_init ( || match this. init . take ( ) {
78- Some ( f) => f ( ) ,
79- None => panic ! ( "Lazy instance has previously been poisoned" ) ,
80- } )
91+ this. once . call_once ( || {
92+ // SAFETY: `call_once` only runs this closure once, ever.
93+ let data = unsafe { & mut * this. data . get ( ) } ;
94+ let f = unsafe { ManuallyDrop :: take ( & mut data. f ) } ;
95+ let value = f ( ) ;
96+ data. value = ManuallyDrop :: new ( value) ;
97+ } ) ;
98+
99+ // SAFETY:
100+ // There are four possible scenarios:
101+ // * the closure was called and initialized `value`.
102+ // * the closure was called and panicked, so this point is never reached.
103+ // * the closure was not called, but a previous call initialized `value`.
104+ // * the closure was not called because the Once is poisoned, so this point
105+ // is never reached.
106+ // So `value` has definitely been initialized and will not be modified again.
107+ unsafe { & * ( * this. data . get ( ) ) . value }
108+ }
109+ }
110+
111+ impl < T , F > LazyLock < T , F > {
112+ /// Get the inner value if it has already been initialized.
113+ fn get ( & self ) -> Option < & T > {
114+ if self . once . is_completed ( ) {
115+ // SAFETY:
116+ // The closure has been run successfully, so `value` has been initialized
117+ // and will not be modified again.
118+ Some ( unsafe { & * ( * self . data . get ( ) ) . value } )
119+ } else {
120+ None
121+ }
122+ }
123+ }
124+
125+ #[ unstable( feature = "once_cell" , issue = "74465" ) ]
126+ impl < T , F > Drop for LazyLock < T , F > {
127+ fn drop ( & mut self ) {
128+ match self . once . state ( ) {
129+ ExclusiveState :: Incomplete => unsafe { ManuallyDrop :: drop ( & mut self . data . get_mut ( ) . f ) } ,
130+ ExclusiveState :: Complete => unsafe {
131+ ManuallyDrop :: drop ( & mut self . data . get_mut ( ) . value )
132+ } ,
133+ ExclusiveState :: Poisoned => { }
134+ }
81135 }
82136}
83137
@@ -103,23 +157,23 @@ impl<T: Default> Default for LazyLock<T> {
103157#[ unstable( feature = "once_cell" , issue = "74465" ) ]
104158impl < T : fmt:: Debug , F > fmt:: Debug for LazyLock < T , F > {
105159 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
106- f. debug_struct ( "Lazy" ) . field ( "cell" , & self . cell ) . finish_non_exhaustive ( )
160+ match self . get ( ) {
161+ Some ( v) => f. debug_tuple ( "LazyLock" ) . field ( v) . finish ( ) ,
162+ None => f. write_str ( "LazyLock(Uninit)" ) ,
163+ }
107164 }
108165}
109166
110167// We never create a `&F` from a `&LazyLock<T, F>` so it is fine
111168// to not impl `Sync` for `F`
112- // we do create a `&mut Option<F>` in `force`, but this is
113- // properly synchronized, so it only happens once
114- // so it also does not contribute to this impl.
115169#[ unstable( feature = "once_cell" , issue = "74465" ) ]
116- unsafe impl < T , F : Send > Sync for LazyLock < T , F > where OnceLock < T > : Sync { }
170+ unsafe impl < T : Sync + Send , F : Send > Sync for LazyLock < T , F > { }
117171// auto-derived `Send` impl is OK.
118172
119173#[ unstable( feature = "once_cell" , issue = "74465" ) ]
120- impl < T , F : UnwindSafe > RefUnwindSafe for LazyLock < T , F > where OnceLock < T > : RefUnwindSafe { }
174+ impl < T : RefUnwindSafe + UnwindSafe , F : UnwindSafe > RefUnwindSafe for LazyLock < T , F > { }
121175#[ unstable( feature = "once_cell" , issue = "74465" ) ]
122- impl < T , F : UnwindSafe > UnwindSafe for LazyLock < T , F > where OnceLock < T > : UnwindSafe { }
176+ impl < T : UnwindSafe , F : UnwindSafe > UnwindSafe for LazyLock < T , F > { }
123177
124178#[ cfg( test) ]
125179mod tests;
0 commit comments