exclusive_cell/
lib.rs

1//! This crate provides two thread-safe, non-blocking, no-std synchronization primitives: [`ExclusiveCell`] and [`CallOnce`].
2//!
3//! [`ExclusiveCell`] can be accessed at most once and provides mutable access to the stored contents:
4//!
5//! ```
6//! use exclusive_cell::ExclusiveCell;
7//!
8//! static EXCLUSIVE_CELL: ExclusiveCell<usize> = ExclusiveCell::new(5);
9//!
10//! let number = EXCLUSIVE_CELL.take().unwrap();
11//! assert_eq!(number, &mut 5);
12//!
13//! assert!(EXCLUSIVE_CELL.take().is_none());
14//! ```
15//!
16//! [`CallOnce`] can only be called once sucessfully:
17//!
18//! ```
19//! use exclusive_cell::CallOnce;
20//!
21//! static CALL_ONCE: CallOnce = CallOnce::new();
22//!
23//! assert!(CALL_ONCE.call_once().is_ok());
24//! assert!(CALL_ONCE.call_once().is_err());
25//! ```
26
27#![no_std]
28
29use core::{
30    cell::UnsafeCell,
31    fmt,
32    sync::atomic::{AtomicBool, Ordering},
33};
34
35/// A synchronization primitive that can only be called once sucessfully.
36///
37/// It behaves similarily to `ExclusiveCell<()>` but with a more descriptive API.
38///
39/// # Examples
40///
41/// ```
42/// use exclusive_cell::CallOnce;
43///
44/// static CALL_ONCE: CallOnce = CallOnce::new();
45///
46/// assert!(CALL_ONCE.call_once().is_ok());
47/// assert!(CALL_ONCE.call_once().is_err());
48/// ```
49#[derive(Default, Debug)]
50pub struct CallOnce {
51    called: AtomicBool,
52}
53
54impl CallOnce {
55    /// Creates a new `CallOnce`.
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// use exclusive_cell::CallOnce;
61    ///
62    /// let call_once = CallOnce::new();
63    /// ```
64    #[inline]
65    pub const fn new() -> Self {
66        Self {
67            called: AtomicBool::new(false),
68        }
69    }
70
71    /// Mark this `CallOnce` as called.
72    ///
73    /// Only the first call returns `Ok`.
74    /// All subsequent calls return `Err`.
75    ///
76    /// # Examples
77    ///
78    /// ```
79    /// use exclusive_cell::CallOnce;
80    ///
81    /// let call_once = CallOnce::new();
82    ///
83    /// assert!(call_once.call_once().is_ok());
84    /// assert!(call_once.call_once().is_err());
85    /// ```
86    #[inline]
87    pub fn call_once(&self) -> Result<(), CallOnceError> {
88        self.called
89            .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
90            .map(drop)
91            .map_err(|_| CallOnceError)
92    }
93
94    /// Returns `true` if `call_once` has been called.
95    ///
96    /// # Examples
97    ///
98    /// ```
99    /// use exclusive_cell::CallOnce;
100    ///
101    /// let call_once = CallOnce::new();
102    /// assert!(!call_once.was_called());
103    ///
104    /// call_once.call_once().unwrap();
105    /// assert!(call_once.was_called());
106    /// ```
107    #[inline]
108    pub fn was_called(&self) -> bool {
109        self.called.load(Ordering::Relaxed)
110    }
111}
112
113/// The `CallOnceError` error indicates that [`CallOnce::call_once`] has been called more than once.
114#[derive(Debug)]
115pub struct CallOnceError;
116
117impl fmt::Display for CallOnceError {
118    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119        f.write_str("call_once was executed more than once")
120    }
121}
122
123/// A synchronization primitive which can be accessed only once.
124///
125/// This type is a thread-safe cell, and can be used in statics.
126/// `ExclusiveCell` provides a mutable reference to the contents without RAII guards, but only on the first try.
127///
128/// # Relation with other types
129///
130/// `ExclusiveCell` is complementary to `OnceCell` with regards to `Mutex` and `RwLock`:
131///
132/// | `C`           | `Mutex`      | `RwLock`                        | `OnceCell` | `ExclusiveCell` |
133/// | ------------- | ------------ | ------------------------------- | ---------- | --------------- |
134/// | `&C` provides | `MutexGuard` | `RwLock{Read,Write}Guard`       | `&T`       | `&mut`          |
135///
136/// A `OnceCell` can be emulated using a `RwLock` by only ever calling `try_read` and leaking the `RwLockReadGuard`.
137/// Similarily, `ExclusiveCell` can be emulated using a `RwLock` by only ever calling `try_write` and leaking the `RwLockWriteGuard`.
138///
139/// In contrast to `OnceCell` but similarly to `Mutex` and `RwLock`, the contents of a `ExclusiveCell` have to be initialized at creation.
140///
141/// # Similarities with `cortex_m::singleton`
142///
143/// `ExclusiveCell` can be used similarily to [`cortex_m::singleton`] to create a mutable reference to a statically allocated value.
144/// In contrast to `cortex_m::singleton`, `ExclusiveCell` is thread safe and does not require using macros.
145///
146/// [`cortex_m::singleton`]: https://docs.rs/cortex-m/0.7.6/cortex_m/macro.singleton.html
147///
148/// # Examples
149///
150/// ```
151/// use exclusive_cell::ExclusiveCell;
152///
153/// static EXCLUSIVE_CELL: ExclusiveCell<usize> = ExclusiveCell::new(5);
154///
155/// let number = EXCLUSIVE_CELL.take().unwrap();
156/// assert_eq!(number, &mut 5);
157///
158/// assert!(EXCLUSIVE_CELL.take().is_none());
159/// ```
160#[derive(Debug)]
161pub struct ExclusiveCell<T: ?Sized> {
162    taken: CallOnce,
163    data: UnsafeCell<T>,
164}
165
166unsafe impl<T: ?Sized + Send> Send for ExclusiveCell<T> {}
167unsafe impl<T: ?Sized + Send> Sync for ExclusiveCell<T> {}
168
169impl<T> ExclusiveCell<T> {
170    /// Creates a new `ExclusiveCell` containing the given value.
171    ///
172    /// # Examples
173    ///
174    /// ```
175    /// use exclusive_cell::ExclusiveCell;
176    ///
177    /// let exclusive_cell = ExclusiveCell::new(5);
178    /// ```
179    #[inline]
180    pub const fn new(val: T) -> Self {
181        Self {
182            taken: CallOnce::new(),
183            data: UnsafeCell::new(val),
184        }
185    }
186
187    /// Unwraps the value.
188    ///
189    /// # Examples
190    ///
191    /// ```
192    /// use exclusive_cell::ExclusiveCell;
193    ///
194    /// let exclusive_cell = ExclusiveCell::new(5);
195    /// let number = exclusive_cell.into_inner();
196    ///
197    /// assert_eq!(number, 5);
198    /// ```
199    #[inline]
200    pub fn into_inner(self) -> T {
201        self.data.into_inner()
202    }
203}
204
205impl<T: ?Sized> ExclusiveCell<T> {
206    /// Takes the mutable reference to the wrapped value.
207    ///
208    /// Only the first call returns `Some`.
209    /// All subsequent calls return `None`.
210    ///
211    /// # Examples
212    ///
213    /// ```
214    /// use exclusive_cell::ExclusiveCell;
215    ///
216    /// let exclusive_cell = ExclusiveCell::new(5);
217    ///
218    /// let number = exclusive_cell.take().unwrap();
219    /// assert_eq!(number, &mut 5);
220    ///
221    /// assert!(exclusive_cell.take().is_none());
222    /// ```
223    #[inline]
224    #[must_use]
225    pub fn take(&self) -> Option<&mut T> {
226        self.taken
227            .call_once()
228            .ok()
229            .map(|_| unsafe { &mut *self.data.get() })
230    }
231
232    /// Returns `true` if the mutable reference has been taken.
233    ///
234    /// # Examples
235    ///
236    /// ```
237    /// use exclusive_cell::ExclusiveCell;
238    ///
239    /// let exclusive_cell = ExclusiveCell::new(5);
240    /// assert!(!exclusive_cell.is_taken());
241    ///
242    /// let number = exclusive_cell.take().unwrap();
243    /// assert!(exclusive_cell.is_taken());
244    /// ```
245    #[inline]
246    pub fn is_taken(&self) -> bool {
247        self.taken.was_called()
248    }
249
250    /// Returns a mutable reference to the underlying data.
251    ///
252    /// Since this method borrows `ExclusiveCell` mutably, it is statically guaranteed
253    /// that no borrows to the underlying data exists.
254    ///
255    /// # Examples
256    ///
257    /// ```
258    /// use exclusive_cell::ExclusiveCell;
259    ///
260    /// let mut exclusive_cell = ExclusiveCell::new(5);
261    ///
262    /// let number = exclusive_cell.get_mut();
263    /// assert_eq!(number, &mut 5);
264    ///
265    /// assert!(!exclusive_cell.is_taken());
266    /// ```
267    #[inline]
268    pub fn get_mut(&mut self) -> &mut T {
269        unsafe { &mut *self.data.get() }
270    }
271}
272
273impl<T: Default> Default for ExclusiveCell<T> {
274    fn default() -> Self {
275        Self::new(Default::default())
276    }
277}
278
279impl<T> From<T> for ExclusiveCell<T> {
280    fn from(value: T) -> Self {
281        Self::new(value)
282    }
283}