5 use crate::sys_common
::mutex
::Mutex
;
8 // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly!
10 ptr
: Cell
<*mut Arc
<T
>>,
14 const fn done
<T
>() -> *mut Arc
<T
> {
18 unsafe impl<T
> Sync
for Lazy
<T
> {}
21 pub const fn new() -> Lazy
<T
> {
22 Lazy { lock: Mutex::new(), ptr: Cell::new(ptr::null_mut()) }
26 impl<T
: Send
+ Sync
+ '
static> Lazy
<T
> {
27 /// Safety: `init` must not call `get` on the variable that is being
29 pub unsafe fn get(&'
static self, init
: fn() -> Arc
<T
>) -> Option
<Arc
<T
>> {
30 let _guard
= self.lock
.lock();
31 let ptr
= self.ptr
.get();
34 } else if ptr
== done() {
41 // Must only be called with `lock` held
42 unsafe fn init(&'
static self, init
: fn() -> Arc
<T
>) -> Arc
<T
> {
43 // If we successfully register an at exit handler, then we cache the
44 // `Arc` allocation in our own internal box (it will get deallocated by
45 // the at exit handler). Otherwise we just return the freshly allocated
47 let registered
= sys_common
::at_exit(move || {
49 let _guard
= self.lock
.lock();
50 self.ptr
.replace(done())
52 drop(Box
::from_raw(ptr
))
54 // This could reentrantly call `init` again, which is a problem
55 // because our `lock` allows reentrancy!
56 // That's why `get` is unsafe and requires the caller to ensure no reentrancy happens.
58 if registered
.is_ok() {
59 self.ptr
.set(Box
::into_raw(Box
::new(ret
.clone())));