1- use crate :: cell:: Cell ;
1+ use crate :: mem:: ManuallyDrop ;
2+
3+ use crate :: cell:: UnsafeCell ;
24use crate :: fmt;
35use crate :: ops:: Deref ;
46use crate :: panic:: { RefUnwindSafe , UnwindSafe } ;
5- use crate :: sync:: OnceLock ;
7+ use crate :: sync:: Once ;
8+
9+ use super :: once:: ExclusiveState ;
10+
11+ // We use the state of a Once as discriminant value. Upon creation, the state is
12+ // "incomplete" and `f` contains the initialization closure. In the first call to
13+ // `call_once`, `f` is taken and run. If it succeeds, `value` is set and the state
14+ // is changed to "complete". If it panics, the Once is poisoned, so none of the
15+ // two fields is initialized.
16+ union Data < T , F > {
17+ value : ManuallyDrop < T > ,
18+ f : ManuallyDrop < F > ,
19+ }
620
721/// A value which is initialized on the first access.
822///
@@ -43,16 +57,17 @@ use crate::sync::OnceLock;
4357/// ```
4458#[ unstable( feature = "once_cell" , issue = "74465" ) ]
4559pub struct LazyLock < T , F = fn ( ) -> T > {
46- cell : OnceLock < T > ,
47- init : Cell < Option < F > > ,
60+ once : Once ,
61+ data : UnsafeCell < Data < T , F > > ,
4862}
63+
4964impl < T , F : FnOnce ( ) -> T > LazyLock < T , F > {
5065 /// Creates a new lazy value with the given initializing
5166 /// function.
5267 #[ inline]
5368 #[ unstable( feature = "once_cell" , issue = "74465" ) ]
5469 pub const fn new ( f : F ) -> LazyLock < T , F > {
55- LazyLock { cell : OnceLock :: new ( ) , init : Cell :: new ( Some ( f) ) }
70+ LazyLock { once : Once :: new ( ) , data : UnsafeCell :: new ( Data { f : ManuallyDrop :: new ( f) } ) }
5671 }
5772
5873 /// Forces the evaluation of this lazy value and
@@ -74,10 +89,43 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
7489 #[ inline]
7590 #[ unstable( feature = "once_cell" , issue = "74465" ) ]
7691 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- } )
92+ this. once . call_once ( || {
93+ // SAFETY: `call_once` only runs this closure once, ever.
94+ let data = unsafe { & mut * this. data . get ( ) } ;
95+ let f = unsafe { ManuallyDrop :: take ( & mut data. f ) } ;
96+ let value = f ( ) ;
97+ data. value = ManuallyDrop :: new ( value) ;
98+ } ) ;
99+
100+ // SAFETY:
101+ // There are four possible scenarios:
102+ // * the closure was called and initialized `value`.
103+ // * the closure was called and panicked, so this point is never reached.
104+ // * the closure was not called, but a previous call initialized `value`.
105+ // * the closure was not called because the Once is poisoned, so this point
106+ // is never reached.
107+ // So `value` has definitely been initialized and will not be modified again.
108+ unsafe { & * ( * this. data . get ( ) ) . value }
109+ }
110+ }
111+
112+ impl < T , F > LazyLock < T , F > {
113+ /// Get the inner value if it has already been initialized.
114+ fn get ( & self ) -> Option < & T > {
115+ if self . once . is_completed ( ) { Some ( unsafe { & * ( * self . data . get ( ) ) . value } ) } else { None }
116+ }
117+ }
118+
119+ #[ unstable( feature = "once_cell" , issue = "74465" ) ]
120+ impl < T , F > Drop for LazyLock < T , F > {
121+ fn drop ( & mut self ) {
122+ match self . once . state ( ) {
123+ ExclusiveState :: Incomplete => unsafe { ManuallyDrop :: drop ( & mut self . data . get_mut ( ) . f ) } ,
124+ ExclusiveState :: Complete => unsafe {
125+ ManuallyDrop :: drop ( & mut self . data . get_mut ( ) . value )
126+ } ,
127+ ExclusiveState :: Poisoned => { }
128+ }
81129 }
82130}
83131
@@ -103,23 +151,25 @@ impl<T: Default> Default for LazyLock<T> {
103151#[ unstable( feature = "once_cell" , issue = "74465" ) ]
104152impl < T : fmt:: Debug , F > fmt:: Debug for LazyLock < T , F > {
105153 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
106- f. debug_struct ( "Lazy" ) . field ( "cell" , & self . cell ) . finish_non_exhaustive ( )
154+ f. debug_tuple ( "LazyLock" )
155+ . field ( match self . get ( ) {
156+ Some ( v) => v,
157+ None => & "Uninit" ,
158+ } )
159+ . finish ( )
107160 }
108161}
109162
110163// We never create a `&F` from a `&LazyLock<T, F>` so it is fine
111164// 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.
115165#[ unstable( feature = "once_cell" , issue = "74465" ) ]
116- unsafe impl < T , F : Send > Sync for LazyLock < T , F > where OnceLock < T > : Sync { }
166+ unsafe impl < T : Sync + Send , F : Send > Sync for LazyLock < T , F > { }
117167// auto-derived `Send` impl is OK.
118168
119169#[ unstable( feature = "once_cell" , issue = "74465" ) ]
120- impl < T , F : UnwindSafe > RefUnwindSafe for LazyLock < T , F > where OnceLock < T > : RefUnwindSafe { }
170+ impl < T : RefUnwindSafe + UnwindSafe , F : UnwindSafe > RefUnwindSafe for LazyLock < T , F > { }
121171#[ unstable( feature = "once_cell" , issue = "74465" ) ]
122- impl < T , F : UnwindSafe > UnwindSafe for LazyLock < T , F > where OnceLock < T > : UnwindSafe { }
172+ impl < T : UnwindSafe , F : UnwindSafe > UnwindSafe for LazyLock < T , F > { }
123173
124174#[ cfg( test) ]
125175mod tests;
0 commit comments