1f6121a04Sopenharmony_ci// Original work Copyright (c) 2014 The Rust Project Developers
2f6121a04Sopenharmony_ci// Modified work Copyright (c) 2016-2018 Nikita Pekin and the lazycell contributors
3f6121a04Sopenharmony_ci// See the README.md file at the top-level directory of this distribution.
4f6121a04Sopenharmony_ci//
5f6121a04Sopenharmony_ci// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6f6121a04Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7f6121a04Sopenharmony_ci// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8f6121a04Sopenharmony_ci// option. This file may not be copied, modified, or distributed
9f6121a04Sopenharmony_ci// except according to those terms.
10f6121a04Sopenharmony_ci
11f6121a04Sopenharmony_ci#![cfg_attr(not(test), no_std)]
12f6121a04Sopenharmony_ci
13f6121a04Sopenharmony_ci#![deny(missing_docs)]
14f6121a04Sopenharmony_ci#![cfg_attr(feature = "nightly", feature(plugin))]
15f6121a04Sopenharmony_ci#![cfg_attr(feature = "clippy", plugin(clippy))]
16f6121a04Sopenharmony_ci
17f6121a04Sopenharmony_ci//! This crate provides a `LazyCell` struct which acts as a lazily filled
18f6121a04Sopenharmony_ci//! `Cell`.
19f6121a04Sopenharmony_ci//!
20f6121a04Sopenharmony_ci//! With a `RefCell`, the inner contents cannot be borrowed for the lifetime of
21f6121a04Sopenharmony_ci//! the entire object, but only of the borrows returned. A `LazyCell` is a
22f6121a04Sopenharmony_ci//! variation on `RefCell` which allows borrows to be tied to the lifetime of
23f6121a04Sopenharmony_ci//! the outer object.
24f6121a04Sopenharmony_ci//!
25f6121a04Sopenharmony_ci//! # Example
26f6121a04Sopenharmony_ci//!
27f6121a04Sopenharmony_ci//! The following example shows a quick example of the basic functionality of
28f6121a04Sopenharmony_ci//! `LazyCell`.
29f6121a04Sopenharmony_ci//!
30f6121a04Sopenharmony_ci//! ```
31f6121a04Sopenharmony_ci//! use lazycell::LazyCell;
32f6121a04Sopenharmony_ci//!
33f6121a04Sopenharmony_ci//! let lazycell = LazyCell::new();
34f6121a04Sopenharmony_ci//!
35f6121a04Sopenharmony_ci//! assert_eq!(lazycell.borrow(), None);
36f6121a04Sopenharmony_ci//! assert!(!lazycell.filled());
37f6121a04Sopenharmony_ci//! lazycell.fill(1).ok();
38f6121a04Sopenharmony_ci//! assert!(lazycell.filled());
39f6121a04Sopenharmony_ci//! assert_eq!(lazycell.borrow(), Some(&1));
40f6121a04Sopenharmony_ci//! assert_eq!(lazycell.into_inner(), Some(1));
41f6121a04Sopenharmony_ci//! ```
42f6121a04Sopenharmony_ci//!
43f6121a04Sopenharmony_ci//! `AtomicLazyCell` is a variant that uses an atomic variable to manage
44f6121a04Sopenharmony_ci//! coordination in a thread-safe fashion. The limitation of an `AtomicLazyCell`
45f6121a04Sopenharmony_ci//! is that after it is initialized, it can't be modified.
46f6121a04Sopenharmony_ci
47f6121a04Sopenharmony_ci
48f6121a04Sopenharmony_ci#[cfg(not(test))]
49f6121a04Sopenharmony_ci#[macro_use]
50f6121a04Sopenharmony_ciextern crate core as std;
51f6121a04Sopenharmony_ci
52f6121a04Sopenharmony_ciuse std::cell::UnsafeCell;
53f6121a04Sopenharmony_ciuse std::mem;
54f6121a04Sopenharmony_ciuse std::sync::atomic::{AtomicUsize, Ordering};
55f6121a04Sopenharmony_ci
56f6121a04Sopenharmony_ci/// A lazily filled `Cell`, with mutable contents.
57f6121a04Sopenharmony_ci///
58f6121a04Sopenharmony_ci/// A `LazyCell` is completely frozen once filled, **unless** you have `&mut`
59f6121a04Sopenharmony_ci/// access to it, in which case `LazyCell::borrow_mut` may be used to mutate the
60f6121a04Sopenharmony_ci/// contents.
61f6121a04Sopenharmony_ci#[derive(Debug, Default)]
62f6121a04Sopenharmony_cipub struct LazyCell<T> {
63f6121a04Sopenharmony_ci    inner: UnsafeCell<Option<T>>,
64f6121a04Sopenharmony_ci}
65f6121a04Sopenharmony_ci
66f6121a04Sopenharmony_ciimpl<T> LazyCell<T> {
67f6121a04Sopenharmony_ci    /// Creates a new, empty, `LazyCell`.
68f6121a04Sopenharmony_ci    pub fn new() -> LazyCell<T> {
69f6121a04Sopenharmony_ci        LazyCell { inner: UnsafeCell::new(None) }
70f6121a04Sopenharmony_ci    }
71f6121a04Sopenharmony_ci
72f6121a04Sopenharmony_ci    /// Put a value into this cell.
73f6121a04Sopenharmony_ci    ///
74f6121a04Sopenharmony_ci    /// This function will return `Err(value)` is the cell is already full.
75f6121a04Sopenharmony_ci    pub fn fill(&self, value: T) -> Result<(), T> {
76f6121a04Sopenharmony_ci        let slot = unsafe { &mut *self.inner.get() };
77f6121a04Sopenharmony_ci        if slot.is_some() {
78f6121a04Sopenharmony_ci            return Err(value);
79f6121a04Sopenharmony_ci        }
80f6121a04Sopenharmony_ci        *slot = Some(value);
81f6121a04Sopenharmony_ci
82f6121a04Sopenharmony_ci        Ok(())
83f6121a04Sopenharmony_ci    }
84f6121a04Sopenharmony_ci
85f6121a04Sopenharmony_ci    /// Put a value into this cell.
86f6121a04Sopenharmony_ci    ///
87f6121a04Sopenharmony_ci    /// Note that this function is infallible but requires `&mut self`. By
88f6121a04Sopenharmony_ci    /// requiring `&mut self` we're guaranteed that no active borrows to this
89f6121a04Sopenharmony_ci    /// cell can exist so we can always fill in the value. This may not always
90f6121a04Sopenharmony_ci    /// be usable, however, as `&mut self` may not be possible to borrow.
91f6121a04Sopenharmony_ci    ///
92f6121a04Sopenharmony_ci    /// # Return value
93f6121a04Sopenharmony_ci    ///
94f6121a04Sopenharmony_ci    /// This function returns the previous value, if any.
95f6121a04Sopenharmony_ci    pub fn replace(&mut self, value: T) -> Option<T> {
96f6121a04Sopenharmony_ci        mem::replace(unsafe { &mut *self.inner.get() }, Some(value))
97f6121a04Sopenharmony_ci    }
98f6121a04Sopenharmony_ci
99f6121a04Sopenharmony_ci    /// Test whether this cell has been previously filled.
100f6121a04Sopenharmony_ci    pub fn filled(&self) -> bool {
101f6121a04Sopenharmony_ci        self.borrow().is_some()
102f6121a04Sopenharmony_ci    }
103f6121a04Sopenharmony_ci
104f6121a04Sopenharmony_ci    /// Borrows the contents of this lazy cell for the duration of the cell
105f6121a04Sopenharmony_ci    /// itself.
106f6121a04Sopenharmony_ci    ///
107f6121a04Sopenharmony_ci    /// This function will return `Some` if the cell has been previously
108f6121a04Sopenharmony_ci    /// initialized, and `None` if it has not yet been initialized.
109f6121a04Sopenharmony_ci    pub fn borrow(&self) -> Option<&T> {
110f6121a04Sopenharmony_ci        unsafe { &*self.inner.get() }.as_ref()
111f6121a04Sopenharmony_ci    }
112f6121a04Sopenharmony_ci
113f6121a04Sopenharmony_ci    /// Borrows the contents of this lazy cell mutably for the duration of the cell
114f6121a04Sopenharmony_ci    /// itself.
115f6121a04Sopenharmony_ci    ///
116f6121a04Sopenharmony_ci    /// This function will return `Some` if the cell has been previously
117f6121a04Sopenharmony_ci    /// initialized, and `None` if it has not yet been initialized.
118f6121a04Sopenharmony_ci    pub fn borrow_mut(&mut self) -> Option<&mut T> {
119f6121a04Sopenharmony_ci        unsafe { &mut *self.inner.get() }.as_mut()
120f6121a04Sopenharmony_ci    }
121f6121a04Sopenharmony_ci
122f6121a04Sopenharmony_ci    /// Borrows the contents of this lazy cell for the duration of the cell
123f6121a04Sopenharmony_ci    /// itself.
124f6121a04Sopenharmony_ci    ///
125f6121a04Sopenharmony_ci    /// If the cell has not yet been filled, the cell is first filled using the
126f6121a04Sopenharmony_ci    /// function provided.
127f6121a04Sopenharmony_ci    ///
128f6121a04Sopenharmony_ci    /// # Panics
129f6121a04Sopenharmony_ci    ///
130f6121a04Sopenharmony_ci    /// Panics if the cell becomes filled as a side effect of `f`.
131f6121a04Sopenharmony_ci    pub fn borrow_with<F: FnOnce() -> T>(&self, f: F) -> &T {
132f6121a04Sopenharmony_ci        if let Some(value) = self.borrow() {
133f6121a04Sopenharmony_ci            return value;
134f6121a04Sopenharmony_ci        }
135f6121a04Sopenharmony_ci        let value = f();
136f6121a04Sopenharmony_ci        if self.fill(value).is_err() {
137f6121a04Sopenharmony_ci            panic!("borrow_with: cell was filled by closure")
138f6121a04Sopenharmony_ci        }
139f6121a04Sopenharmony_ci        self.borrow().unwrap()
140f6121a04Sopenharmony_ci    }
141f6121a04Sopenharmony_ci
142f6121a04Sopenharmony_ci    /// Borrows the contents of this `LazyCell` mutably for the duration of the
143f6121a04Sopenharmony_ci    /// cell itself.
144f6121a04Sopenharmony_ci    ///
145f6121a04Sopenharmony_ci    /// If the cell has not yet been filled, the cell is first filled using the
146f6121a04Sopenharmony_ci    /// function provided.
147f6121a04Sopenharmony_ci    ///
148f6121a04Sopenharmony_ci    /// # Panics
149f6121a04Sopenharmony_ci    ///
150f6121a04Sopenharmony_ci    /// Panics if the cell becomes filled as a side effect of `f`.
151f6121a04Sopenharmony_ci    pub fn borrow_mut_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
152f6121a04Sopenharmony_ci        if !self.filled() {
153f6121a04Sopenharmony_ci            let value = f();
154f6121a04Sopenharmony_ci            if self.fill(value).is_err() {
155f6121a04Sopenharmony_ci                panic!("borrow_mut_with: cell was filled by closure")
156f6121a04Sopenharmony_ci            }
157f6121a04Sopenharmony_ci        }
158f6121a04Sopenharmony_ci
159f6121a04Sopenharmony_ci        self.borrow_mut().unwrap()
160f6121a04Sopenharmony_ci    }
161f6121a04Sopenharmony_ci
162f6121a04Sopenharmony_ci    /// Same as `borrow_with`, but allows the initializing function to fail.
163f6121a04Sopenharmony_ci    ///
164f6121a04Sopenharmony_ci    /// # Panics
165f6121a04Sopenharmony_ci    ///
166f6121a04Sopenharmony_ci    /// Panics if the cell becomes filled as a side effect of `f`.
167f6121a04Sopenharmony_ci    pub fn try_borrow_with<E, F>(&self, f: F) -> Result<&T, E>
168f6121a04Sopenharmony_ci        where F: FnOnce() -> Result<T, E>
169f6121a04Sopenharmony_ci    {
170f6121a04Sopenharmony_ci        if let Some(value) = self.borrow() {
171f6121a04Sopenharmony_ci            return Ok(value);
172f6121a04Sopenharmony_ci        }
173f6121a04Sopenharmony_ci        let value = f()?;
174f6121a04Sopenharmony_ci        if self.fill(value).is_err() {
175f6121a04Sopenharmony_ci            panic!("try_borrow_with: cell was filled by closure")
176f6121a04Sopenharmony_ci        }
177f6121a04Sopenharmony_ci        Ok(self.borrow().unwrap())
178f6121a04Sopenharmony_ci    }
179f6121a04Sopenharmony_ci
180f6121a04Sopenharmony_ci    /// Same as `borrow_mut_with`, but allows the initializing function to fail.
181f6121a04Sopenharmony_ci    ///
182f6121a04Sopenharmony_ci    /// # Panics
183f6121a04Sopenharmony_ci    ///
184f6121a04Sopenharmony_ci    /// Panics if the cell becomes filled as a side effect of `f`.
185f6121a04Sopenharmony_ci    pub fn try_borrow_mut_with<E, F>(&mut self, f: F) -> Result<&mut T, E>
186f6121a04Sopenharmony_ci        where F: FnOnce() -> Result<T, E>
187f6121a04Sopenharmony_ci    {
188f6121a04Sopenharmony_ci        if self.filled() {
189f6121a04Sopenharmony_ci            return Ok(self.borrow_mut().unwrap());
190f6121a04Sopenharmony_ci        }
191f6121a04Sopenharmony_ci        let value = f()?;
192f6121a04Sopenharmony_ci        if self.fill(value).is_err() {
193f6121a04Sopenharmony_ci            panic!("try_borrow_mut_with: cell was filled by closure")
194f6121a04Sopenharmony_ci        }
195f6121a04Sopenharmony_ci        Ok(self.borrow_mut().unwrap())
196f6121a04Sopenharmony_ci    }
197f6121a04Sopenharmony_ci
198f6121a04Sopenharmony_ci    /// Consumes this `LazyCell`, returning the underlying value.
199f6121a04Sopenharmony_ci    pub fn into_inner(self) -> Option<T> {
200f6121a04Sopenharmony_ci        // Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe
201f6121a04Sopenharmony_ci        // function. This unsafe can be removed when supporting Rust older than
202f6121a04Sopenharmony_ci        // 1.25 is not needed.
203f6121a04Sopenharmony_ci        #[allow(unused_unsafe)]
204f6121a04Sopenharmony_ci        unsafe { self.inner.into_inner() }
205f6121a04Sopenharmony_ci    }
206f6121a04Sopenharmony_ci}
207f6121a04Sopenharmony_ci
208f6121a04Sopenharmony_ciimpl<T: Copy> LazyCell<T> {
209f6121a04Sopenharmony_ci    /// Returns a copy of the contents of the lazy cell.
210f6121a04Sopenharmony_ci    ///
211f6121a04Sopenharmony_ci    /// This function will return `Some` if the cell has been previously initialized,
212f6121a04Sopenharmony_ci    /// and `None` if it has not yet been initialized.
213f6121a04Sopenharmony_ci    pub fn get(&self) -> Option<T> {
214f6121a04Sopenharmony_ci        unsafe { *self.inner.get() }
215f6121a04Sopenharmony_ci    }
216f6121a04Sopenharmony_ci}
217f6121a04Sopenharmony_ci
218f6121a04Sopenharmony_ciimpl <T: Clone> Clone for LazyCell<T> {
219f6121a04Sopenharmony_ci    /// Create a clone of this `LazyCell`
220f6121a04Sopenharmony_ci    ///
221f6121a04Sopenharmony_ci    /// If self has not been initialized, returns an uninitialized `LazyCell`
222f6121a04Sopenharmony_ci    /// otherwise returns a `LazyCell` already initialized with a clone of the
223f6121a04Sopenharmony_ci    /// contents of self.
224f6121a04Sopenharmony_ci    fn clone(&self) -> LazyCell<T> {
225f6121a04Sopenharmony_ci        LazyCell { inner: UnsafeCell::new(self.borrow().map(Clone::clone) ) }
226f6121a04Sopenharmony_ci    }
227f6121a04Sopenharmony_ci}
228f6121a04Sopenharmony_ci
229f6121a04Sopenharmony_ci// Tracks the AtomicLazyCell inner state
230f6121a04Sopenharmony_ciconst NONE: usize = 0;
231f6121a04Sopenharmony_ciconst LOCK: usize = 1;
232f6121a04Sopenharmony_ciconst SOME: usize = 2;
233f6121a04Sopenharmony_ci
234f6121a04Sopenharmony_ci/// A lazily filled and thread-safe `Cell`, with frozen contents.
235f6121a04Sopenharmony_ci#[derive(Debug, Default)]
236f6121a04Sopenharmony_cipub struct AtomicLazyCell<T> {
237f6121a04Sopenharmony_ci    inner: UnsafeCell<Option<T>>,
238f6121a04Sopenharmony_ci    state: AtomicUsize,
239f6121a04Sopenharmony_ci}
240f6121a04Sopenharmony_ci
241f6121a04Sopenharmony_ciimpl<T> AtomicLazyCell<T> {
242f6121a04Sopenharmony_ci    /// An empty `AtomicLazyCell`.
243f6121a04Sopenharmony_ci    pub const NONE: Self = Self {
244f6121a04Sopenharmony_ci        inner: UnsafeCell::new(None),
245f6121a04Sopenharmony_ci        state: AtomicUsize::new(NONE),
246f6121a04Sopenharmony_ci    };
247f6121a04Sopenharmony_ci
248f6121a04Sopenharmony_ci    /// Creates a new, empty, `AtomicLazyCell`.
249f6121a04Sopenharmony_ci    pub fn new() -> AtomicLazyCell<T> {
250f6121a04Sopenharmony_ci        Self::NONE
251f6121a04Sopenharmony_ci    }
252f6121a04Sopenharmony_ci
253f6121a04Sopenharmony_ci    /// Put a value into this cell.
254f6121a04Sopenharmony_ci    ///
255f6121a04Sopenharmony_ci    /// This function will return `Err(value)` is the cell is already full.
256f6121a04Sopenharmony_ci    pub fn fill(&self, t: T) -> Result<(), T> {
257f6121a04Sopenharmony_ci        if NONE != self.state.compare_and_swap(NONE, LOCK, Ordering::Acquire) {
258f6121a04Sopenharmony_ci            return Err(t);
259f6121a04Sopenharmony_ci        }
260f6121a04Sopenharmony_ci
261f6121a04Sopenharmony_ci        unsafe { *self.inner.get() = Some(t) };
262f6121a04Sopenharmony_ci
263f6121a04Sopenharmony_ci        if LOCK != self.state.compare_and_swap(LOCK, SOME, Ordering::Release) {
264f6121a04Sopenharmony_ci            panic!("unable to release lock");
265f6121a04Sopenharmony_ci        }
266f6121a04Sopenharmony_ci
267f6121a04Sopenharmony_ci        Ok(())
268f6121a04Sopenharmony_ci    }
269f6121a04Sopenharmony_ci
270f6121a04Sopenharmony_ci    /// Put a value into this cell.
271f6121a04Sopenharmony_ci    ///
272f6121a04Sopenharmony_ci    /// Note that this function is infallible but requires `&mut self`. By
273f6121a04Sopenharmony_ci    /// requiring `&mut self` we're guaranteed that no active borrows to this
274f6121a04Sopenharmony_ci    /// cell can exist so we can always fill in the value. This may not always
275f6121a04Sopenharmony_ci    /// be usable, however, as `&mut self` may not be possible to borrow.
276f6121a04Sopenharmony_ci    ///
277f6121a04Sopenharmony_ci    /// # Return value
278f6121a04Sopenharmony_ci    ///
279f6121a04Sopenharmony_ci    /// This function returns the previous value, if any.
280f6121a04Sopenharmony_ci    pub fn replace(&mut self, value: T) -> Option<T> {
281f6121a04Sopenharmony_ci        match mem::replace(self.state.get_mut(), SOME) {
282f6121a04Sopenharmony_ci            NONE | SOME => {}
283f6121a04Sopenharmony_ci            _ => panic!("cell in inconsistent state"),
284f6121a04Sopenharmony_ci        }
285f6121a04Sopenharmony_ci        mem::replace(unsafe { &mut *self.inner.get() }, Some(value))
286f6121a04Sopenharmony_ci    }
287f6121a04Sopenharmony_ci
288f6121a04Sopenharmony_ci    /// Test whether this cell has been previously filled.
289f6121a04Sopenharmony_ci    pub fn filled(&self) -> bool {
290f6121a04Sopenharmony_ci        self.state.load(Ordering::Acquire) == SOME
291f6121a04Sopenharmony_ci    }
292f6121a04Sopenharmony_ci
293f6121a04Sopenharmony_ci    /// Borrows the contents of this lazy cell for the duration of the cell
294f6121a04Sopenharmony_ci    /// itself.
295f6121a04Sopenharmony_ci    ///
296f6121a04Sopenharmony_ci    /// This function will return `Some` if the cell has been previously
297f6121a04Sopenharmony_ci    /// initialized, and `None` if it has not yet been initialized.
298f6121a04Sopenharmony_ci    pub fn borrow(&self) -> Option<&T> {
299f6121a04Sopenharmony_ci        match self.state.load(Ordering::Acquire) {
300f6121a04Sopenharmony_ci            SOME => unsafe { &*self.inner.get() }.as_ref(),
301f6121a04Sopenharmony_ci            _ => None,
302f6121a04Sopenharmony_ci        }
303f6121a04Sopenharmony_ci    }
304f6121a04Sopenharmony_ci
305f6121a04Sopenharmony_ci    /// Consumes this `LazyCell`, returning the underlying value.
306f6121a04Sopenharmony_ci    pub fn into_inner(self) -> Option<T> {
307f6121a04Sopenharmony_ci        // Rust 1.25 changed UnsafeCell::into_inner() from unsafe to safe
308f6121a04Sopenharmony_ci        // function. This unsafe can be removed when supporting Rust older than
309f6121a04Sopenharmony_ci        // 1.25 is not needed.
310f6121a04Sopenharmony_ci        #[allow(unused_unsafe)]
311f6121a04Sopenharmony_ci        unsafe { self.inner.into_inner() }
312f6121a04Sopenharmony_ci    }
313f6121a04Sopenharmony_ci}
314f6121a04Sopenharmony_ci
315f6121a04Sopenharmony_ciimpl<T: Copy> AtomicLazyCell<T> {
316f6121a04Sopenharmony_ci    /// Returns a copy of the contents of the lazy cell.
317f6121a04Sopenharmony_ci    ///
318f6121a04Sopenharmony_ci    /// This function will return `Some` if the cell has been previously initialized,
319f6121a04Sopenharmony_ci    /// and `None` if it has not yet been initialized.
320f6121a04Sopenharmony_ci    pub fn get(&self) -> Option<T> {
321f6121a04Sopenharmony_ci        match self.state.load(Ordering::Acquire) {
322f6121a04Sopenharmony_ci            SOME => unsafe { *self.inner.get() },
323f6121a04Sopenharmony_ci            _ => None,
324f6121a04Sopenharmony_ci        }
325f6121a04Sopenharmony_ci    }
326f6121a04Sopenharmony_ci}
327f6121a04Sopenharmony_ci
328f6121a04Sopenharmony_ciimpl<T: Clone> Clone for AtomicLazyCell<T> {
329f6121a04Sopenharmony_ci    /// Create a clone of this `AtomicLazyCell`
330f6121a04Sopenharmony_ci    ///
331f6121a04Sopenharmony_ci    /// If self has not been initialized, returns an uninitialized `AtomicLazyCell`
332f6121a04Sopenharmony_ci    /// otherwise returns an `AtomicLazyCell` already initialized with a clone of the
333f6121a04Sopenharmony_ci    /// contents of self.
334f6121a04Sopenharmony_ci    fn clone(&self) -> AtomicLazyCell<T> {
335f6121a04Sopenharmony_ci        self.borrow().map_or(
336f6121a04Sopenharmony_ci            Self::NONE,
337f6121a04Sopenharmony_ci            |v| AtomicLazyCell {
338f6121a04Sopenharmony_ci                inner: UnsafeCell::new(Some(v.clone())),
339f6121a04Sopenharmony_ci                state: AtomicUsize::new(SOME),
340f6121a04Sopenharmony_ci            }
341f6121a04Sopenharmony_ci        )
342f6121a04Sopenharmony_ci    }
343f6121a04Sopenharmony_ci}
344f6121a04Sopenharmony_ci
345f6121a04Sopenharmony_ciunsafe impl<T: Sync + Send> Sync for AtomicLazyCell<T> {}
346f6121a04Sopenharmony_ci
347f6121a04Sopenharmony_ciunsafe impl<T: Send> Send for AtomicLazyCell<T> {}
348f6121a04Sopenharmony_ci
349f6121a04Sopenharmony_ci#[cfg(test)]
350f6121a04Sopenharmony_cimod tests {
351f6121a04Sopenharmony_ci    use super::{AtomicLazyCell, LazyCell};
352f6121a04Sopenharmony_ci
353f6121a04Sopenharmony_ci    #[test]
354f6121a04Sopenharmony_ci    fn test_borrow_from_empty() {
355f6121a04Sopenharmony_ci        let lazycell: LazyCell<usize> = LazyCell::new();
356f6121a04Sopenharmony_ci
357f6121a04Sopenharmony_ci        let value = lazycell.borrow();
358f6121a04Sopenharmony_ci        assert_eq!(value, None);
359f6121a04Sopenharmony_ci
360f6121a04Sopenharmony_ci        let value = lazycell.get();
361f6121a04Sopenharmony_ci        assert_eq!(value, None);
362f6121a04Sopenharmony_ci    }
363f6121a04Sopenharmony_ci
364f6121a04Sopenharmony_ci    #[test]
365f6121a04Sopenharmony_ci    fn test_fill_and_borrow() {
366f6121a04Sopenharmony_ci        let lazycell = LazyCell::new();
367f6121a04Sopenharmony_ci
368f6121a04Sopenharmony_ci        assert!(!lazycell.filled());
369f6121a04Sopenharmony_ci        lazycell.fill(1).unwrap();
370f6121a04Sopenharmony_ci        assert!(lazycell.filled());
371f6121a04Sopenharmony_ci
372f6121a04Sopenharmony_ci        let value = lazycell.borrow();
373f6121a04Sopenharmony_ci        assert_eq!(value, Some(&1));
374f6121a04Sopenharmony_ci
375f6121a04Sopenharmony_ci        let value = lazycell.get();
376f6121a04Sopenharmony_ci        assert_eq!(value, Some(1));
377f6121a04Sopenharmony_ci    }
378f6121a04Sopenharmony_ci
379f6121a04Sopenharmony_ci    #[test]
380f6121a04Sopenharmony_ci    fn test_borrow_mut() {
381f6121a04Sopenharmony_ci        let mut lazycell = LazyCell::new();
382f6121a04Sopenharmony_ci        assert!(lazycell.borrow_mut().is_none());
383f6121a04Sopenharmony_ci
384f6121a04Sopenharmony_ci        lazycell.fill(1).unwrap();
385f6121a04Sopenharmony_ci        assert_eq!(lazycell.borrow_mut(), Some(&mut 1));
386f6121a04Sopenharmony_ci
387f6121a04Sopenharmony_ci        *lazycell.borrow_mut().unwrap() = 2;
388f6121a04Sopenharmony_ci        assert_eq!(lazycell.borrow_mut(), Some(&mut 2));
389f6121a04Sopenharmony_ci
390f6121a04Sopenharmony_ci        // official way to reset the cell
391f6121a04Sopenharmony_ci        lazycell = LazyCell::new();
392f6121a04Sopenharmony_ci        assert!(lazycell.borrow_mut().is_none());
393f6121a04Sopenharmony_ci    }
394f6121a04Sopenharmony_ci
395f6121a04Sopenharmony_ci    #[test]
396f6121a04Sopenharmony_ci    fn test_already_filled_error() {
397f6121a04Sopenharmony_ci        let lazycell = LazyCell::new();
398f6121a04Sopenharmony_ci
399f6121a04Sopenharmony_ci        lazycell.fill(1).unwrap();
400f6121a04Sopenharmony_ci        assert_eq!(lazycell.fill(1), Err(1));
401f6121a04Sopenharmony_ci    }
402f6121a04Sopenharmony_ci
403f6121a04Sopenharmony_ci    #[test]
404f6121a04Sopenharmony_ci    fn test_borrow_with() {
405f6121a04Sopenharmony_ci        let lazycell = LazyCell::new();
406f6121a04Sopenharmony_ci
407f6121a04Sopenharmony_ci        let value = lazycell.borrow_with(|| 1);
408f6121a04Sopenharmony_ci        assert_eq!(&1, value);
409f6121a04Sopenharmony_ci    }
410f6121a04Sopenharmony_ci
411f6121a04Sopenharmony_ci    #[test]
412f6121a04Sopenharmony_ci    fn test_borrow_with_already_filled() {
413f6121a04Sopenharmony_ci        let lazycell = LazyCell::new();
414f6121a04Sopenharmony_ci        lazycell.fill(1).unwrap();
415f6121a04Sopenharmony_ci
416f6121a04Sopenharmony_ci        let value = lazycell.borrow_with(|| 1);
417f6121a04Sopenharmony_ci        assert_eq!(&1, value);
418f6121a04Sopenharmony_ci    }
419f6121a04Sopenharmony_ci
420f6121a04Sopenharmony_ci    #[test]
421f6121a04Sopenharmony_ci    fn test_borrow_with_not_called_when_filled() {
422f6121a04Sopenharmony_ci        let lazycell = LazyCell::new();
423f6121a04Sopenharmony_ci
424f6121a04Sopenharmony_ci        lazycell.fill(1).unwrap();
425f6121a04Sopenharmony_ci
426f6121a04Sopenharmony_ci        let value = lazycell.borrow_with(|| 2);
427f6121a04Sopenharmony_ci        assert_eq!(&1, value);
428f6121a04Sopenharmony_ci    }
429f6121a04Sopenharmony_ci
430f6121a04Sopenharmony_ci    #[test]
431f6121a04Sopenharmony_ci    #[should_panic]
432f6121a04Sopenharmony_ci    fn test_borrow_with_sound_with_reentrancy() {
433f6121a04Sopenharmony_ci        // Kudos to dbaupp for discovering this issue
434f6121a04Sopenharmony_ci        // https://www.reddit.com/r/rust/comments/5vs9rt/lazycell_a_rust_library_providing_a_lazilyfilled/de527xm/
435f6121a04Sopenharmony_ci        let lazycell: LazyCell<Box<i32>> = LazyCell::new();
436f6121a04Sopenharmony_ci
437f6121a04Sopenharmony_ci        let mut reference: Option<&i32> = None;
438f6121a04Sopenharmony_ci
439f6121a04Sopenharmony_ci        lazycell.borrow_with(|| {
440f6121a04Sopenharmony_ci            let _ = lazycell.fill(Box::new(1));
441f6121a04Sopenharmony_ci            reference = lazycell.borrow().map(|r| &**r);
442f6121a04Sopenharmony_ci            Box::new(2)
443f6121a04Sopenharmony_ci        });
444f6121a04Sopenharmony_ci    }
445f6121a04Sopenharmony_ci
446f6121a04Sopenharmony_ci    #[test]
447f6121a04Sopenharmony_ci    fn test_borrow_mut_with() {
448f6121a04Sopenharmony_ci        let mut lazycell = LazyCell::new();
449f6121a04Sopenharmony_ci
450f6121a04Sopenharmony_ci        {
451f6121a04Sopenharmony_ci            let value = lazycell.borrow_mut_with(|| 1);
452f6121a04Sopenharmony_ci            assert_eq!(&mut 1, value);
453f6121a04Sopenharmony_ci            *value = 2;
454f6121a04Sopenharmony_ci        }
455f6121a04Sopenharmony_ci        assert_eq!(&2, lazycell.borrow().unwrap());
456f6121a04Sopenharmony_ci    }
457f6121a04Sopenharmony_ci
458f6121a04Sopenharmony_ci    #[test]
459f6121a04Sopenharmony_ci    fn test_borrow_mut_with_already_filled() {
460f6121a04Sopenharmony_ci        let mut lazycell = LazyCell::new();
461f6121a04Sopenharmony_ci        lazycell.fill(1).unwrap();
462f6121a04Sopenharmony_ci
463f6121a04Sopenharmony_ci        let value = lazycell.borrow_mut_with(|| 1);
464f6121a04Sopenharmony_ci        assert_eq!(&1, value);
465f6121a04Sopenharmony_ci    }
466f6121a04Sopenharmony_ci
467f6121a04Sopenharmony_ci    #[test]
468f6121a04Sopenharmony_ci    fn test_borrow_mut_with_not_called_when_filled() {
469f6121a04Sopenharmony_ci        let mut lazycell = LazyCell::new();
470f6121a04Sopenharmony_ci
471f6121a04Sopenharmony_ci        lazycell.fill(1).unwrap();
472f6121a04Sopenharmony_ci
473f6121a04Sopenharmony_ci        let value = lazycell.borrow_mut_with(|| 2);
474f6121a04Sopenharmony_ci        assert_eq!(&1, value);
475f6121a04Sopenharmony_ci    }
476f6121a04Sopenharmony_ci
477f6121a04Sopenharmony_ci    #[test]
478f6121a04Sopenharmony_ci    fn test_try_borrow_with_ok() {
479f6121a04Sopenharmony_ci        let lazycell = LazyCell::new();
480f6121a04Sopenharmony_ci        let result = lazycell.try_borrow_with::<(), _>(|| Ok(1));
481f6121a04Sopenharmony_ci        assert_eq!(result, Ok(&1));
482f6121a04Sopenharmony_ci    }
483f6121a04Sopenharmony_ci
484f6121a04Sopenharmony_ci    #[test]
485f6121a04Sopenharmony_ci    fn test_try_borrow_with_err() {
486f6121a04Sopenharmony_ci        let lazycell = LazyCell::<()>::new();
487f6121a04Sopenharmony_ci        let result = lazycell.try_borrow_with(|| Err(1));
488f6121a04Sopenharmony_ci        assert_eq!(result, Err(1));
489f6121a04Sopenharmony_ci    }
490f6121a04Sopenharmony_ci
491f6121a04Sopenharmony_ci    #[test]
492f6121a04Sopenharmony_ci    fn test_try_borrow_with_already_filled() {
493f6121a04Sopenharmony_ci        let lazycell = LazyCell::new();
494f6121a04Sopenharmony_ci        lazycell.fill(1).unwrap();
495f6121a04Sopenharmony_ci        let result = lazycell.try_borrow_with::<(), _>(|| unreachable!());
496f6121a04Sopenharmony_ci        assert_eq!(result, Ok(&1));
497f6121a04Sopenharmony_ci    }
498f6121a04Sopenharmony_ci
499f6121a04Sopenharmony_ci    #[test]
500f6121a04Sopenharmony_ci    #[should_panic]
501f6121a04Sopenharmony_ci    fn test_try_borrow_with_sound_with_reentrancy() {
502f6121a04Sopenharmony_ci        let lazycell: LazyCell<Box<i32>> = LazyCell::new();
503f6121a04Sopenharmony_ci
504f6121a04Sopenharmony_ci        let mut reference: Option<&i32> = None;
505f6121a04Sopenharmony_ci
506f6121a04Sopenharmony_ci        let _ = lazycell.try_borrow_with::<(), _>(|| {
507f6121a04Sopenharmony_ci            let _ = lazycell.fill(Box::new(1));
508f6121a04Sopenharmony_ci            reference = lazycell.borrow().map(|r| &**r);
509f6121a04Sopenharmony_ci            Ok(Box::new(2))
510f6121a04Sopenharmony_ci        });
511f6121a04Sopenharmony_ci    }
512f6121a04Sopenharmony_ci
513f6121a04Sopenharmony_ci    #[test]
514f6121a04Sopenharmony_ci    fn test_try_borrow_mut_with_ok() {
515f6121a04Sopenharmony_ci        let mut lazycell = LazyCell::new();
516f6121a04Sopenharmony_ci        {
517f6121a04Sopenharmony_ci            let result = lazycell.try_borrow_mut_with::<(), _>(|| Ok(1));
518f6121a04Sopenharmony_ci            assert_eq!(result, Ok(&mut 1));
519f6121a04Sopenharmony_ci            *result.unwrap() = 2;
520f6121a04Sopenharmony_ci        }
521f6121a04Sopenharmony_ci        assert_eq!(&mut 2, lazycell.borrow().unwrap());
522f6121a04Sopenharmony_ci    }
523f6121a04Sopenharmony_ci
524f6121a04Sopenharmony_ci    #[test]
525f6121a04Sopenharmony_ci    fn test_try_borrow_mut_with_err() {
526f6121a04Sopenharmony_ci        let mut lazycell = LazyCell::<()>::new();
527f6121a04Sopenharmony_ci        let result = lazycell.try_borrow_mut_with(|| Err(1));
528f6121a04Sopenharmony_ci        assert_eq!(result, Err(1));
529f6121a04Sopenharmony_ci    }
530f6121a04Sopenharmony_ci
531f6121a04Sopenharmony_ci    #[test]
532f6121a04Sopenharmony_ci    fn test_try_borrow_mut_with_already_filled() {
533f6121a04Sopenharmony_ci        let mut lazycell = LazyCell::new();
534f6121a04Sopenharmony_ci        lazycell.fill(1).unwrap();
535f6121a04Sopenharmony_ci        let result = lazycell.try_borrow_mut_with::<(), _>(|| unreachable!());
536f6121a04Sopenharmony_ci        assert_eq!(result, Ok(&mut 1));
537f6121a04Sopenharmony_ci    }
538f6121a04Sopenharmony_ci
539f6121a04Sopenharmony_ci    #[test]
540f6121a04Sopenharmony_ci    fn test_into_inner() {
541f6121a04Sopenharmony_ci        let lazycell = LazyCell::new();
542f6121a04Sopenharmony_ci
543f6121a04Sopenharmony_ci        lazycell.fill(1).unwrap();
544f6121a04Sopenharmony_ci        let value = lazycell.into_inner();
545f6121a04Sopenharmony_ci        assert_eq!(value, Some(1));
546f6121a04Sopenharmony_ci    }
547f6121a04Sopenharmony_ci
548f6121a04Sopenharmony_ci    #[test]
549f6121a04Sopenharmony_ci    fn test_atomic_borrow_from_empty() {
550f6121a04Sopenharmony_ci        let lazycell: AtomicLazyCell<usize> = AtomicLazyCell::new();
551f6121a04Sopenharmony_ci
552f6121a04Sopenharmony_ci        let value = lazycell.borrow();
553f6121a04Sopenharmony_ci        assert_eq!(value, None);
554f6121a04Sopenharmony_ci
555f6121a04Sopenharmony_ci        let value = lazycell.get();
556f6121a04Sopenharmony_ci        assert_eq!(value, None);
557f6121a04Sopenharmony_ci    }
558f6121a04Sopenharmony_ci
559f6121a04Sopenharmony_ci    #[test]
560f6121a04Sopenharmony_ci    fn test_atomic_fill_and_borrow() {
561f6121a04Sopenharmony_ci        let lazycell = AtomicLazyCell::new();
562f6121a04Sopenharmony_ci
563f6121a04Sopenharmony_ci        assert!(!lazycell.filled());
564f6121a04Sopenharmony_ci        lazycell.fill(1).unwrap();
565f6121a04Sopenharmony_ci        assert!(lazycell.filled());
566f6121a04Sopenharmony_ci
567f6121a04Sopenharmony_ci        let value = lazycell.borrow();
568f6121a04Sopenharmony_ci        assert_eq!(value, Some(&1));
569f6121a04Sopenharmony_ci
570f6121a04Sopenharmony_ci        let value = lazycell.get();
571f6121a04Sopenharmony_ci        assert_eq!(value, Some(1));
572f6121a04Sopenharmony_ci    }
573f6121a04Sopenharmony_ci
574f6121a04Sopenharmony_ci    #[test]
575f6121a04Sopenharmony_ci    fn test_atomic_already_filled_panic() {
576f6121a04Sopenharmony_ci        let lazycell = AtomicLazyCell::new();
577f6121a04Sopenharmony_ci
578f6121a04Sopenharmony_ci        lazycell.fill(1).unwrap();
579f6121a04Sopenharmony_ci        assert_eq!(1, lazycell.fill(1).unwrap_err());
580f6121a04Sopenharmony_ci    }
581f6121a04Sopenharmony_ci
582f6121a04Sopenharmony_ci    #[test]
583f6121a04Sopenharmony_ci    fn test_atomic_into_inner() {
584f6121a04Sopenharmony_ci        let lazycell = AtomicLazyCell::new();
585f6121a04Sopenharmony_ci
586f6121a04Sopenharmony_ci        lazycell.fill(1).unwrap();
587f6121a04Sopenharmony_ci        let value = lazycell.into_inner();
588f6121a04Sopenharmony_ci        assert_eq!(value, Some(1));
589f6121a04Sopenharmony_ci    }
590f6121a04Sopenharmony_ci
591f6121a04Sopenharmony_ci    #[test]
592f6121a04Sopenharmony_ci    fn normal_replace() {
593f6121a04Sopenharmony_ci        let mut cell = LazyCell::new();
594f6121a04Sopenharmony_ci        assert_eq!(cell.fill(1), Ok(()));
595f6121a04Sopenharmony_ci        assert_eq!(cell.replace(2), Some(1));
596f6121a04Sopenharmony_ci        assert_eq!(cell.replace(3), Some(2));
597f6121a04Sopenharmony_ci        assert_eq!(cell.borrow(), Some(&3));
598f6121a04Sopenharmony_ci
599f6121a04Sopenharmony_ci        let mut cell = LazyCell::new();
600f6121a04Sopenharmony_ci        assert_eq!(cell.replace(2), None);
601f6121a04Sopenharmony_ci    }
602f6121a04Sopenharmony_ci
603f6121a04Sopenharmony_ci    #[test]
604f6121a04Sopenharmony_ci    fn atomic_replace() {
605f6121a04Sopenharmony_ci        let mut cell = AtomicLazyCell::new();
606f6121a04Sopenharmony_ci        assert_eq!(cell.fill(1), Ok(()));
607f6121a04Sopenharmony_ci        assert_eq!(cell.replace(2), Some(1));
608f6121a04Sopenharmony_ci        assert_eq!(cell.replace(3), Some(2));
609f6121a04Sopenharmony_ci        assert_eq!(cell.borrow(), Some(&3));
610f6121a04Sopenharmony_ci    }
611f6121a04Sopenharmony_ci
612f6121a04Sopenharmony_ci    #[test]
613f6121a04Sopenharmony_ci    fn clone() {
614f6121a04Sopenharmony_ci        let mut cell = LazyCell::new();
615f6121a04Sopenharmony_ci        let clone1 = cell.clone();
616f6121a04Sopenharmony_ci        assert_eq!(clone1.borrow(), None);
617f6121a04Sopenharmony_ci        assert_eq!(cell.fill(1), Ok(()));
618f6121a04Sopenharmony_ci        let mut clone2 = cell.clone();
619f6121a04Sopenharmony_ci        assert_eq!(clone1.borrow(), None);
620f6121a04Sopenharmony_ci        assert_eq!(clone2.borrow(), Some(&1));
621f6121a04Sopenharmony_ci        assert_eq!(cell.replace(2), Some(1));
622f6121a04Sopenharmony_ci        assert_eq!(clone1.borrow(), None);
623f6121a04Sopenharmony_ci        assert_eq!(clone2.borrow(), Some(&1));
624f6121a04Sopenharmony_ci        assert_eq!(clone1.fill(3), Ok(()));
625f6121a04Sopenharmony_ci        assert_eq!(clone2.replace(4), Some(1));
626f6121a04Sopenharmony_ci        assert_eq!(clone1.borrow(), Some(&3));
627f6121a04Sopenharmony_ci        assert_eq!(clone2.borrow(), Some(&4));
628f6121a04Sopenharmony_ci        assert_eq!(cell.borrow(), Some(&2));
629f6121a04Sopenharmony_ci    }
630f6121a04Sopenharmony_ci
631f6121a04Sopenharmony_ci    #[test]
632f6121a04Sopenharmony_ci    fn clone_atomic() {
633f6121a04Sopenharmony_ci        let mut cell = AtomicLazyCell::new();
634f6121a04Sopenharmony_ci        let clone1 = cell.clone();
635f6121a04Sopenharmony_ci        assert_eq!(clone1.borrow(), None);
636f6121a04Sopenharmony_ci        assert_eq!(cell.fill(1), Ok(()));
637f6121a04Sopenharmony_ci        let mut clone2 = cell.clone();
638f6121a04Sopenharmony_ci        assert_eq!(clone1.borrow(), None);
639f6121a04Sopenharmony_ci        assert_eq!(clone2.borrow(), Some(&1));
640f6121a04Sopenharmony_ci        assert_eq!(cell.replace(2), Some(1));
641f6121a04Sopenharmony_ci        assert_eq!(clone1.borrow(), None);
642f6121a04Sopenharmony_ci        assert_eq!(clone2.borrow(), Some(&1));
643f6121a04Sopenharmony_ci        assert_eq!(clone1.fill(3), Ok(()));
644f6121a04Sopenharmony_ci        assert_eq!(clone2.replace(4), Some(1));
645f6121a04Sopenharmony_ci        assert_eq!(clone1.borrow(), Some(&3));
646f6121a04Sopenharmony_ci        assert_eq!(clone2.borrow(), Some(&4));
647f6121a04Sopenharmony_ci        assert_eq!(cell.borrow(), Some(&2));
648f6121a04Sopenharmony_ci    }
649f6121a04Sopenharmony_ci}
650