]>
Commit | Line | Data |
---|---|---|
c34b1796 AL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
62682a34 | 11 | use cell::Cell; |
e9174d1e | 12 | use ptr; |
a7813a04 | 13 | use sync::Arc; |
e9174d1e | 14 | use sys_common; |
a7813a04 | 15 | use sys_common::mutex::Mutex; |
c34b1796 AL |
16 | |
17 | pub struct Lazy<T> { | |
a7813a04 | 18 | lock: Mutex, |
62682a34 SL |
19 | ptr: Cell<*mut Arc<T>>, |
20 | init: fn() -> Arc<T>, | |
c34b1796 AL |
21 | } |
22 | ||
23 | unsafe impl<T> Sync for Lazy<T> {} | |
24 | ||
c34b1796 | 25 | impl<T: Send + Sync + 'static> Lazy<T> { |
62682a34 SL |
26 | pub const fn new(init: fn() -> Arc<T>) -> Lazy<T> { |
27 | Lazy { | |
a7813a04 | 28 | lock: Mutex::new(), |
e9174d1e | 29 | ptr: Cell::new(ptr::null_mut()), |
62682a34 SL |
30 | init: init |
31 | } | |
32 | } | |
33 | ||
c34b1796 | 34 | pub fn get(&'static self) -> Option<Arc<T>> { |
c34b1796 | 35 | unsafe { |
a7813a04 XL |
36 | self.lock.lock(); |
37 | let ptr = self.ptr.get(); | |
38 | let ret = if ptr.is_null() { | |
c34b1796 AL |
39 | Some(self.init()) |
40 | } else if ptr as usize == 1 { | |
41 | None | |
42 | } else { | |
43 | Some((*ptr).clone()) | |
a7813a04 XL |
44 | }; |
45 | self.lock.unlock(); | |
46 | return ret | |
c34b1796 AL |
47 | } |
48 | } | |
49 | ||
50 | unsafe fn init(&'static self) -> Arc<T> { | |
51 | // If we successfully register an at exit handler, then we cache the | |
52 | // `Arc` allocation in our own internal box (it will get deallocated by | |
53 | // the at exit handler). Otherwise we just return the freshly allocated | |
54 | // `Arc`. | |
e9174d1e | 55 | let registered = sys_common::at_exit(move || { |
a7813a04 | 56 | self.lock.lock(); |
62682a34 SL |
57 | let ptr = self.ptr.get(); |
58 | self.ptr.set(1 as *mut _); | |
a7813a04 | 59 | self.lock.unlock(); |
c34b1796 AL |
60 | drop(Box::from_raw(ptr)) |
61 | }); | |
62 | let ret = (self.init)(); | |
63 | if registered.is_ok() { | |
62682a34 | 64 | self.ptr.set(Box::into_raw(Box::new(ret.clone()))); |
c34b1796 | 65 | } |
e9174d1e | 66 | ret |
c34b1796 AL |
67 | } |
68 | } |