Skip to content

Commit dedd4b5

Browse files
committed
Hide Once
1 parent 7c7a41a commit dedd4b5

File tree

1 file changed

+28
-19
lines changed

1 file changed

+28
-19
lines changed

src/lib.rs

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,30 @@ use std::sync::{Once, ONCE_INIT};
1515
#[doc(hidden)]
1616
pub use std::cell::UnsafeCell as __UnsafeCell;
1717

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`.
1821
#[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+
2442

2543
/// A value which is initialized on the first access.
2644
///
@@ -68,7 +86,7 @@ pub use std::sync::ONCE_INIT as __ONCE_INIT;
6886
#[derive(Debug)]
6987
pub struct Lazy<T, F = fn() -> T> {
7088
#[doc(hidden)]
71-
pub __once: Once,
89+
pub __once: __Once,
7290
#[doc(hidden)]
7391
pub __state: UnsafeCell<__State<T, F>>,
7492
}
@@ -109,7 +127,7 @@ impl<T, F: FnOnce() -> T> Lazy<T, F> {
109127
#[cfg(not(feature = "nightly"))]
110128
pub fn new(f: F) -> Lazy<T, F> {
111129
Lazy {
112-
__once: ONCE_INIT,
130+
__once: __Once::INIT,
113131
__state: UnsafeCell::new(__State::Uninit(f)),
114132
}
115133
}
@@ -119,7 +137,7 @@ impl<T, F: FnOnce() -> T> Lazy<T, F> {
119137
#[cfg(feature = "nightly")]
120138
pub const fn new(f: F) -> Lazy<T, F> {
121139
Lazy {
122-
__once: ONCE_INIT,
140+
__once: __Once::INIT,
123141
__state: UnsafeCell::new(__State::Uninit(f)),
124142
}
125143
}
@@ -138,16 +156,7 @@ impl<T, F: FnOnce() -> T> Lazy<T, F> {
138156
/// assert_eq!(&*lazy, &92);
139157
/// ```
140158
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(|| {
151160
// safe, b/c call_once guarantees exclusive access.
152161
let state: &mut __State<T, F> = unsafe { &mut *this.__state.get() };
153162
state.init();
@@ -192,7 +201,7 @@ impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
192201
macro_rules! sync_lazy {
193202
($($block:tt)*) => {
194203
$crate::Lazy {
195-
__once: $crate::__ONCE_INIT,
204+
__once: $crate::__Once::INIT,
196205
__state: $crate::__UnsafeCell::new(
197206
$crate::__State::Uninit(|| { $($block)* })
198207
),

0 commit comments

Comments
 (0)