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}