lazy_init/
lib.rs

1#![deny(missing_docs)]
2
3//! A crate for things that are
4//! 1) Lazily initialized
5//! 2) Expensive to create
6//! 3) Immutable after creation
7//! 4) Used on multiple threads
8//!
9//! `Lazy<T>` is better than `Mutex<Option<T>>` because after creation accessing
10//! `T` does not require any locking, just a single boolean load with
11//! `Ordering::Acquire` (which on x86 is just a compiler barrier, not an actual
12//! memory barrier).
13
14use std::cell::UnsafeCell;
15use std::fmt;
16use std::sync::atomic::{AtomicBool, Ordering};
17use std::sync::Mutex;
18
19#[derive(Clone)]
20enum ThisOrThat<T, U> {
21    This(T),
22    That(U),
23}
24
25/// `LazyTransform<T, U>` is a synchronized holder type, that holds a value of
26/// type T until it is lazily converted into a value of type U.
27pub struct LazyTransform<T, U> {
28    initialized: AtomicBool,
29    lock: Mutex<()>,
30    value: UnsafeCell<Option<ThisOrThat<T, U>>>,
31}
32
33// Implementation details.
34impl<T, U> LazyTransform<T, U> {
35    fn extract(&self) -> Option<&U> {
36        // Make sure we're initialized first!
37        match unsafe { (*self.value.get()).as_ref() } {
38            None => None,
39            Some(&ThisOrThat::This(_)) => panic!(), // Should already be initialized!
40            Some(&ThisOrThat::That(ref that)) => Some(that),
41        }
42    }
43}
44
45// Public API.
46impl<T, U> LazyTransform<T, U> {
47    /// Construct a new, untransformed `LazyTransform<T, U>` with an argument of
48    /// type T.
49    pub fn new(t: T) -> LazyTransform<T, U> {
50        LazyTransform {
51            initialized: AtomicBool::new(false),
52            lock: Mutex::new(()),
53            value: UnsafeCell::new(Some(ThisOrThat::This(t))),
54        }
55    }
56
57    /// Unwrap the contained value, returning `Ok(U)` if the `LazyTransform<T, U>` has been
58    /// transformed or `Err(T)` if it has not.
59    pub fn into_inner(self) -> Result<U, T> {
60        // We don't need to inspect `self.initialized` since `self` is owned
61        // so it is guaranteed that no other threads are accessing its data.
62        match self.value.into_inner().unwrap() {
63            ThisOrThat::This(t) => Err(t),
64            ThisOrThat::That(u) => Ok(u),
65        }
66    }
67}
68
69// Public API.
70impl<T, U> LazyTransform<T, U> {
71    /// Get a reference to the transformed value, invoking `f` to transform it
72    /// if the `LazyTransform<T, U>` has yet to be transformed.  It is
73    /// guaranteed that if multiple calls to `get_or_create` race, only one
74    /// will invoke its closure, and every call will receive a reference to the
75    /// newly transformed value.
76    ///
77    /// The closure can only ever be called once, so think carefully about what
78    /// transformation you want to apply!
79    pub fn get_or_create<F>(&self, f: F) -> &U
80    where
81        F: FnOnce(T) -> U,
82    {
83        // In addition to being correct, this pattern is vouched for by Hans Boehm
84        // (http://schd.ws/hosted_files/cppcon2016/74/HansWeakAtomics.pdf Page 27)
85        if !self.initialized.load(Ordering::Acquire) {
86            // We *may* not be initialized. We have to block to be certain.
87            let _lock = self.lock.lock().unwrap();
88            if !self.initialized.load(Ordering::Relaxed) {
89                // Ok, we're definitely uninitialized.
90                // Safe to fiddle with the UnsafeCell now, because we're locked,
91                // and there can't be any outstanding references.
92                let value = unsafe { &mut *self.value.get() };
93                let this = match value.take().unwrap() {
94                    ThisOrThat::This(t) => t,
95                    ThisOrThat::That(_) => panic!(), // Can't already be initialized!
96                };
97                *value = Some(ThisOrThat::That(f(this)));
98                self.initialized.store(true, Ordering::Release);
99            } else {
100                // We raced, and someone else initialized us. We can fall
101                // through now.
102            }
103        }
104
105        // We're initialized, our value is immutable, no synchronization needed.
106        self.extract().unwrap()
107    }
108
109    /// Get a reference to the transformed value, returning `Some(&U)` if the
110    /// `LazyTransform<T, U>` has been transformed or `None` if it has not.  It
111    /// is guaranteed that if a reference is returned it is to the transformed
112    /// value inside the the `LazyTransform<T>`.
113    pub fn get(&self) -> Option<&U> {
114        if self.initialized.load(Ordering::Acquire) {
115            // We're initialized, our value is immutable, no synchronization needed.
116            self.extract()
117        } else {
118            None
119        }
120    }
121}
122
123// As `T` is only ever accessed when locked, it's enough if it's `Send` for `Self` to be `Sync`.
124unsafe impl<T, U> Sync for LazyTransform<T, U>
125where
126    T: Send,
127    U: Send + Sync,
128{
129}
130
131impl<T, U> Clone for LazyTransform<T, U>
132where
133    T: Clone,
134    U: Clone,
135{
136    fn clone(&self) -> Self {
137        // Overall, this method is very similar to `get_or_create` and uses the same
138        // soundness reasoning.
139
140        if self.initialized.load(Ordering::Acquire) {
141            Self {
142                initialized: true.into(),
143                lock: Mutex::default(),
144                value: UnsafeCell::new(unsafe {
145                    // SAFETY:
146                    // Everything is initialized and immutable here, so lockless cloning is safe.
147                    (&*self.value.get()).clone()
148                }),
149            }
150        } else {
151            // We *may* not be initialized. We have to block here before accessing `value`,
152            // which also synchronises the `initialized` load.
153            let _lock = self.lock.lock().unwrap();
154            Self {
155                initialized: self.initialized.load(Ordering::Relaxed).into(),
156                lock: Mutex::default(),
157                value: UnsafeCell::new(unsafe {
158                    // SAFETY:
159                    // Exclusive access while `_lock` is held.
160                    (&*self.value.get()).clone()
161                }),
162            }
163        }
164    }
165
166    fn clone_from(&mut self, source: &Self) {
167        // Overall, this method is very similar to `get_or_create` and uses the same
168        // soundness reasoning. It's implemented explicitly here to avoid a `Mutex` drop/new.
169
170        if self.initialized.load(Ordering::Acquire) {
171            unsafe {
172                // SAFETY:
173                // Everything is initialized and immutable here, so lockless cloning is safe.
174                // It's still important to store `initialized` with correct ordering, though.
175                *self.value.get() = (&*source.value.get()).clone();
176                self.initialized.store(true, Ordering::Release);
177            }
178        } else {
179            // `source` *may* not be initialized. We have to block here before accessing `value`,
180            // which also synchronises the `initialized` load (and incidentally also the `initialized`
181            // store due to the exclusive reference to `self`, so that can be `Relaxed` here too).
182            let _lock = source.lock.lock().unwrap();
183            unsafe {
184                // SAFETY:
185                // Exclusive access to `source` while `_lock` is held.
186                *self.value.get() = (&*source.value.get()).clone();
187                self.initialized.store(
188                    source.initialized.load(Ordering::Relaxed),
189                    Ordering::Relaxed,
190                );
191            }
192        }
193    }
194}
195
196impl<T, U> Default for LazyTransform<T, U>
197where
198    T: Default,
199{
200    fn default() -> Self {
201        LazyTransform::new(T::default())
202    }
203}
204
205/// `Lazy<T>` is a lazily initialized synchronized holder type.  You can think
206/// of it as a `LazyTransform` where the initial type doesn't exist.
207#[derive(Clone)]
208pub struct Lazy<T> {
209    inner: LazyTransform<(), T>,
210}
211
212impl<T> Lazy<T> {
213    /// Construct a new, uninitialized `Lazy<T>`.
214    pub fn new() -> Lazy<T> {
215        Self::default()
216    }
217
218    /// Unwrap the contained value, returning `Some` if the `Lazy<T>` has been initialized
219    /// or `None` if it has not.
220    pub fn into_inner(self) -> Option<T> {
221        self.inner.into_inner().ok()
222    }
223}
224
225impl<T> Lazy<T> {
226    /// Get a reference to the contained value, invoking `f` to create it
227    /// if the `Lazy<T>` is uninitialized.  It is guaranteed that if multiple
228    /// calls to `get_or_create` race, only one will invoke its closure, and
229    /// every call will receive a reference to the newly created value.
230    ///
231    /// The value stored in the `Lazy<T>` is immutable after the closure returns
232    /// it, so think carefully about what you want to put inside!
233    pub fn get_or_create<F>(&self, f: F) -> &T
234    where
235        F: FnOnce() -> T,
236    {
237        self.inner.get_or_create(|_| f())
238    }
239
240    /// Get a reference to the contained value, returning `Some(ref)` if the
241    /// `Lazy<T>` has been initialized or `None` if it has not.  It is
242    /// guaranteed that if a reference is returned it is to the value inside
243    /// the `Lazy<T>`.
244    pub fn get(&self) -> Option<&T> {
245        self.inner.get()
246    }
247}
248
249// `#[derive(Default)]` automatically adds `T: Default` trait bound, but that
250// is too restrictive, because `Lazy<T>` always has a default value for any `T`.
251impl<T> Default for Lazy<T> {
252    fn default() -> Self {
253        Lazy {
254            inner: LazyTransform::new(()),
255        }
256    }
257}
258
259impl<T> fmt::Debug for Lazy<T>
260where
261    T: fmt::Debug,
262{
263    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
264        if let Some(v) = self.get() {
265            f.write_fmt(format_args!("Lazy({:?})", v))
266        } else {
267            f.write_str("Lazy(<uninitialized>)")
268        }
269    }
270}
271
272#[cfg(test)]
273extern crate rayon;
274
275#[cfg(test)]
276mod tests {
277
278    use super::{Lazy, LazyTransform};
279    use rayon::ThreadPoolBuilder;
280    use std::sync::atomic::{AtomicUsize, Ordering};
281    use std::{thread, time};
282
283    #[test]
284    fn test_lazy() {
285        let lazy_value: Lazy<u8> = Lazy::new();
286
287        assert_eq!(lazy_value.get(), None);
288
289        let n = AtomicUsize::new(0);
290
291        let pool = ThreadPoolBuilder::new().num_threads(100).build().unwrap();
292        pool.scope(|scope| {
293            for _ in 0..100 {
294                let lazy_ref = &lazy_value;
295                let n_ref = &n;
296                scope.spawn(move |_| {
297                    let ten_millis = time::Duration::from_millis(10);
298                    thread::sleep(ten_millis);
299
300                    let value = *lazy_ref.get_or_create(|| {
301                        // Make everybody else wait on me, because I'm a jerk.
302                        thread::sleep(ten_millis);
303
304                        // Make this relaxed so it doesn't interfere with
305                        // Lazy internals at all.
306                        n_ref.fetch_add(1, Ordering::Relaxed);
307
308                        42
309                    });
310                    assert_eq!(value, 42);
311
312                    let value = lazy_ref.get();
313                    assert_eq!(value, Some(&42));
314                });
315            }
316        });
317
318        assert_eq!(n.load(Ordering::SeqCst), 1);
319    }
320
321    #[test]
322    fn test_lazy_transform() {
323        let lazy_value: LazyTransform<u8, u8> = LazyTransform::new(21);
324
325        assert_eq!(lazy_value.get(), None);
326
327        let n = AtomicUsize::new(0);
328
329        let pool = ThreadPoolBuilder::new().num_threads(100).build().unwrap();
330        pool.scope(|scope| {
331            for _ in 0..100 {
332                let lazy_ref = &lazy_value;
333                let n_ref = &n;
334                scope.spawn(move |_| {
335                    let ten_millis = time::Duration::from_millis(10);
336                    thread::sleep(ten_millis);
337
338                    let value = *lazy_ref.get_or_create(|v| {
339                        // Make everybody else wait on me, because I'm a jerk.
340                        thread::sleep(ten_millis);
341
342                        // Make this relaxed so it doesn't interfere with
343                        // Lazy internals at all.
344                        n_ref.fetch_add(1, Ordering::Relaxed);
345
346                        v * 2
347                    });
348                    assert_eq!(value, 42);
349
350                    let value = lazy_ref.get();
351                    assert_eq!(value, Some(&42));
352                });
353            }
354        });
355
356        assert_eq!(n.load(Ordering::SeqCst), 1);
357    }
358}