@@ -15,12 +15,30 @@ use std::sync::{Once, ONCE_INIT};
15
15
#[ doc( hidden) ]
16
16
pub use std:: cell:: UnsafeCell as __UnsafeCell;
17
17
18
+ // This wrapper makes `Once` private to this crate,
19
+ // which helps to preserve soundness even if the
20
+ // user pokes the hidden `__` fields of the `Lazy`.
18
21
#[ doc( hidden) ]
19
- #[ cfg( feature = "parking_lot" ) ]
20
- pub use parking_lot:: ONCE_INIT as __ONCE_INIT;
21
- #[ doc( hidden) ]
22
- #[ cfg( not( feature = "parking_lot" ) ) ]
23
- pub use std:: sync:: ONCE_INIT as __ONCE_INIT;
22
+ #[ derive( Debug ) ]
23
+ pub struct __Once ( Once ) ;
24
+
25
+ impl __Once {
26
+ #[ doc( hidden) ]
27
+ pub const INIT : __Once = __Once ( ONCE_INIT ) ;
28
+
29
+ fn call_once < F : FnOnce ( ) > ( & self , f : F ) {
30
+ let once: & Once = & self . 0 ;
31
+
32
+ #[ cfg( not( feature = "parking_lot" ) ) ]
33
+ // Until rustc 1.29.0, `Once::call_once` required a `'static` bound.
34
+ // That bound was an accident, and https://github.com/rust-lang/rust/pull/52239
35
+ // removed it without changing implementation at all. To be able to support
36
+ // older rustc, we just cast to `&'static` here, which should be OK.
37
+ let once: & ' static Once = unsafe { & * ( once as * const Once ) } ;
38
+ once. call_once ( f) ;
39
+ }
40
+ }
41
+
24
42
25
43
/// A value which is initialized on the first access.
26
44
///
@@ -68,7 +86,7 @@ pub use std::sync::ONCE_INIT as __ONCE_INIT;
68
86
#[ derive( Debug ) ]
69
87
pub struct Lazy < T , F = fn ( ) -> T > {
70
88
#[ doc( hidden) ]
71
- pub __once : Once ,
89
+ pub __once : __Once ,
72
90
#[ doc( hidden) ]
73
91
pub __state : UnsafeCell < __State < T , F > > ,
74
92
}
@@ -109,7 +127,7 @@ impl<T, F: FnOnce() -> T> Lazy<T, F> {
109
127
#[ cfg( not( feature = "nightly" ) ) ]
110
128
pub fn new ( f : F ) -> Lazy < T , F > {
111
129
Lazy {
112
- __once : ONCE_INIT ,
130
+ __once : __Once :: INIT ,
113
131
__state : UnsafeCell :: new ( __State:: Uninit ( f) ) ,
114
132
}
115
133
}
@@ -119,7 +137,7 @@ impl<T, F: FnOnce() -> T> Lazy<T, F> {
119
137
#[ cfg( feature = "nightly" ) ]
120
138
pub const fn new ( f : F ) -> Lazy < T , F > {
121
139
Lazy {
122
- __once : ONCE_INIT ,
140
+ __once : __Once :: INIT ,
123
141
__state : UnsafeCell :: new ( __State:: Uninit ( f) ) ,
124
142
}
125
143
}
@@ -138,16 +156,7 @@ impl<T, F: FnOnce() -> T> Lazy<T, F> {
138
156
/// assert_eq!(&*lazy, &92);
139
157
/// ```
140
158
pub fn force ( this : & Lazy < T , F > ) -> & T {
141
- let once: & Once = & this. __once ;
142
-
143
- #[ cfg( not( feature = "parking_lot" ) ) ]
144
- // Until rustc 1.29.0, `Once::call_once` required a `'static` bound.
145
- // That bound was an accident, and https://github.com/rust-lang/rust/pull/52239
146
- // removed it without changing implementation at all. To be able to support
147
- // older rustc, we just cast to `&'static` here, which should be OK.
148
- let once: & ' static Once = unsafe { & * ( once as * const Once ) } ;
149
-
150
- once. call_once ( || {
159
+ this. __once . call_once ( || {
151
160
// safe, b/c call_once guarantees exclusive access.
152
161
let state: & mut __State < T , F > = unsafe { & mut * this. __state . get ( ) } ;
153
162
state. init ( ) ;
@@ -192,7 +201,7 @@ impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
192
201
macro_rules! sync_lazy {
193
202
( $( $block: tt) * ) => {
194
203
$crate:: Lazy {
195
- __once: $crate:: __ONCE_INIT ,
204
+ __once: $crate:: __Once :: INIT ,
196
205
__state: $crate:: __UnsafeCell:: new(
197
206
$crate:: __State:: Uninit ( || { $( $block) * } )
198
207
) ,
0 commit comments