atomicell/
cell.rs

1use core::{
2    cell::UnsafeCell,
3    cmp,
4    fmt::{self, Debug, Display},
5    sync::atomic::Ordering,
6};
7
8use crate::{
9    borrow::{is_borrowed, is_writing, new_lock, AtomicBorrow, AtomicBorrowMut, Lock},
10    refs::{Ref, RefMut},
11};
12
13/// A mutable memory location with dynamically checked borrow rules
14/// This type behaves mostly like [`core::cell::RefCell`].
15/// The main difference is that this type uses atomic operations for borrowing.
16/// Thus allowing to use it in multi-threaded environment.
17///
18/// [`AtomicCell<T>`] implements [`Send`] if `T: Send`.
19/// [`AtomicCell<T>`] implements [`Sync`] if `T: Send + Sync`.
20pub struct AtomicCell<T: ?Sized> {
21    lock: Lock,
22    value: UnsafeCell<T>,
23}
24
25/// `AtomicCell` can be sent to another thread if value can be sent.
26/// Sending can occur on owned cell or mutable reference to it.
27/// Either way it is not borrowed, so it is impossible to share stored value this way.
28unsafe impl<T> Send for AtomicCell<T> where T: Send {}
29
30/// `AtomicCell` can be shared across threads if value can be sent and shared.
31/// Requires `T: Send` because mutable borrow can occur in another thread.
32/// Requires `T: Sync` because immutable borrows could occur concurrently in different threads.
33unsafe impl<T> Sync for AtomicCell<T> where T: Send + Sync {}
34
35impl<T> AtomicCell<T> {
36    /// Creates a new [`AtomicCell`] containing value.
37    ///
38    /// # Examples
39    ///
40    /// ```
41    /// use atomicell::AtomicCell;
42    ///
43    /// let cell = AtomicCell::new(5);
44    /// ```
45    #[inline]
46    pub const fn new(value: T) -> Self {
47        AtomicCell {
48            value: UnsafeCell::new(value),
49            lock: new_lock(),
50        }
51    }
52
53    /// Consumes the [`AtomicCell`], returning the wrapped value.
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// use atomicell::AtomicCell;
59    ///
60    /// let c = AtomicCell::new(5);
61    ///
62    /// let five = c.into_inner();
63    /// ```
64    #[inline(always)]
65    pub fn into_inner(self) -> T {
66        // TODO: Add `const` when `UnsafeCell::into_inner` is stabilized as const.
67        self.value.into_inner()
68    }
69
70    /// Replaces the wrapped value with a new one, returning the old value, without deinitializing either one.
71    ///
72    /// This function corresponds to [core::mem::replace].
73    ///
74    /// # Panics
75    ///
76    /// Panics if the value is currently borrowed.
77    ///
78    /// # Examples
79    ///
80    /// ```
81    /// use atomicell::AtomicCell;
82    /// let cell = AtomicCell::new(5);
83    /// let old_value = cell.replace(6);
84    /// assert_eq!(old_value, 5);
85    /// assert_eq!(cell, AtomicCell::new(6));
86    /// ```
87    #[inline(always)]
88    pub fn replace(&self, t: T) -> T {
89        core::mem::replace(&mut *self.borrow_mut(), t)
90    }
91
92    /// Replaces the wrapped value with a new one computed from f,
93    /// returning the old value,
94    /// without deinitializing either one.
95    ///
96    /// # Panics
97    ///
98    /// Panics if the value is currently borrowed.
99    ///
100    /// # Examples
101    ///
102    /// ```
103    /// use atomicell::AtomicCell;
104    /// let cell = AtomicCell::new(5);
105    /// let old_value = cell.replace_with(|&mut old| old + 1);
106    /// assert_eq!(old_value, 5);
107    /// assert_eq!(cell, AtomicCell::new(6));
108    /// ```
109    #[inline]
110    pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T {
111        match self.try_borrow_mut() {
112            None => failed_to_borrow_mut(),
113            Some(mut borrow) => {
114                let t = f(&mut *borrow);
115                core::mem::replace(&mut *borrow, t)
116            }
117        }
118    }
119
120    /// Swaps the wrapped value of self with the wrapped value of other,
121    /// without deinitializing either one.
122    ///
123    /// This function corresponds to [core::mem::swap].
124    ///
125    /// # Panics
126    ///
127    /// Panics if the value in either AtomicCell is currently borrowed.
128    ///
129    /// # Examples
130    ///
131    /// ```
132    /// use atomicell::AtomicCell;
133    /// let c = AtomicCell::new(5);
134    /// let d = AtomicCell::new(6);
135    /// c.swap(&d);
136    /// assert_eq!(c, AtomicCell::new(6));
137    /// assert_eq!(d, AtomicCell::new(5));
138    /// ```
139    #[inline]
140    pub fn swap(&self, other: &Self) {
141        match self.try_borrow_mut() {
142            None => failed_to_borrow_mut(),
143            Some(mut borrow) => match other.try_borrow_mut() {
144                None => failed_to_borrow_mut(),
145                Some(mut other_borrow) => {
146                    core::mem::swap(&mut *borrow, &mut *other_borrow);
147                }
148            },
149        }
150    }
151}
152
153impl<T> AtomicCell<T>
154where
155    T: ?Sized,
156{
157    /// Immutably borrows the wrapped value,
158    /// returning [`None`] if the value is currently mutably borrowed.
159    ///
160    /// The borrow lasts until the returned [`Ref`], all [`Ref`]s derived from it and all its clones exit scope.
161    ///
162    /// Multiple immutable borrows can be taken out at the same time.
163    ///
164    /// This is the non-panicking variant of borrow.
165    ///
166    /// # Examples
167    ///
168    /// ```
169    /// use atomicell::AtomicCell;
170    /// let c = AtomicCell::new(5);
171    ///
172    /// {
173    ///     let m = c.borrow_mut();
174    ///     assert!(c.try_borrow().is_none());
175    /// }
176    ///
177    /// {
178    ///     let m = c.borrow();
179    ///     assert!(c.try_borrow().is_some());
180    /// }
181    /// ```
182    #[inline]
183    pub fn try_borrow(&self) -> Option<Ref<'_, T>> {
184        // Acquire shared borrow.
185        match AtomicBorrow::try_new(&self.lock) {
186            None => None,
187            Some(borrow) => {
188                // It is now safe to construct immutable borrow.
189                let r = unsafe {
190                    // Locking mechanism ensures that mutable aliasing is impossible.
191                    &*self.value.get()
192                };
193
194                Some(Ref::with_borrow(r, borrow))
195            }
196        }
197    }
198
199    /// Immutably borrows the wrapped value.
200    ///
201    /// The borrow lasts until the returned [`Ref`], all [`Ref`]s derived from it and all its clones exit scope.
202    ///
203    /// Multiple immutable borrows can be taken out at the same time.
204    ///
205    /// # Panics
206    ///
207    /// Panics if the value is currently mutably borrowed. For a non-panicking variant, use [`try_borrow`].
208    ///
209    /// # Examples
210    ///
211    /// [`try_borrow`]: #method.try_borrow
212    ///
213    /// ```
214    /// use atomicell::AtomicCell;
215    ///
216    /// let c = AtomicCell::new(5);
217    ///
218    /// let borrowed_five = c.borrow();
219    /// let borrowed_five2 = c.borrow();
220    /// ```
221    ///
222    /// An example of panic:
223    ///
224    /// ```should_panic
225    /// use atomicell::AtomicCell;
226    ///
227    /// let c = AtomicCell::new(5);
228    ///
229    /// let m = c.borrow_mut();
230    /// let b = c.borrow(); // this causes a panic
231    /// ```
232    #[inline(always)]
233    #[track_caller]
234    pub fn borrow(&self) -> Ref<'_, T> {
235        // Try to borrow the value and panic on failure.
236        // Panic is put into separate non-inlineable cold function
237        // in order to not pollute this function
238        // and hit compiler that this branch is unlikely.
239        match self.try_borrow() {
240            None => failed_to_borrow(),
241            Some(r) => r,
242        }
243    }
244
245    /// Mutably borrows the wrapped value, returning an error if the value is currently borrowed.
246    ///
247    /// The borrow lasts until the returned [`RefMut`] or all [`RefMut`]s derived from it exit scope.
248    ///
249    /// The value cannot be borrowed while this borrow is active.
250    ///
251    /// This is the non-panicking variant of borrow_mut.
252    ///
253    /// # Examples
254    ///
255    /// ```
256    /// use atomicell::AtomicCell;
257    ///
258    /// let c = AtomicCell::new(5);
259    ///
260    /// {
261    ///     let m = c.borrow();
262    ///     assert!(c.try_borrow_mut().is_none());
263    /// }
264    ///
265    /// assert!(c.try_borrow_mut().is_some());
266    /// ```
267    #[inline]
268    pub fn try_borrow_mut(&self) -> Option<RefMut<'_, T>> {
269        // Acquire shared borrow.
270        match AtomicBorrowMut::try_new(&self.lock) {
271            None => None,
272            Some(borrow) => {
273                // It is now safe to construct mutable borrow.
274                let r = unsafe {
275                    // Locking mechanism ensures that mutable aliasing is impossible.
276                    &mut *self.value.get()
277                };
278
279                Some(RefMut::with_borrow(r, borrow))
280            }
281        }
282    }
283    /// Mutably borrows the wrapped value.
284    ///
285    /// The borrow lasts until the returned [`RefMut`] or all [`RefMut`]s derived from it exit scope.
286    ///
287    /// The value cannot be borrowed while this borrow is active.
288    ///
289    /// # Panics
290    ///
291    /// Panics if the value is currently borrowed. For a non-panicking variant, use try_borrow_mut.
292    ///
293    /// # Examples
294    ///
295    /// ```
296    /// use atomicell::AtomicCell;
297    ///
298    /// let c = AtomicCell::new("hello".to_owned());
299    ///
300    /// *c.borrow_mut() = "bonjour".to_owned();
301    ///
302    /// assert_eq!(&*c.borrow(), "bonjour");
303    /// ```
304    ///
305    /// An example of panic:
306    ///
307    /// ```should_panic
308    /// use atomicell::AtomicCell;
309    ///
310    /// let c = AtomicCell::new(5);
311    /// let m = c.borrow();
312    ///
313    /// let b = c.borrow_mut(); // this causes a panic
314    /// ```
315    #[inline(always)]
316    #[track_caller]
317    pub fn borrow_mut(&self) -> RefMut<'_, T> {
318        // Try to borrow the value and panic on failure.
319        // Panic is put into separate non-inlineable cold function
320        // in order to not pollute this function
321        // and hit compiler that this branch is unlikely.
322        match self.try_borrow_mut() {
323            None => failed_to_borrow_mut(),
324            Some(r) => r,
325        }
326    }
327
328    /// Returns a raw pointer to the underlying data in this cell.
329    ///
330    /// # Examples
331    ///
332    /// ```
333    /// use atomicell::AtomicCell;
334    ///
335    /// let c = AtomicCell::new(5);
336    ///
337    /// let ptr = c.as_ptr();
338    /// ```
339    #[inline]
340    pub const fn as_ptr(&self) -> *mut T {
341        self.value.get()
342    }
343
344    /// Returns a mutable reference to the underlying data.
345    ///
346    /// This call borrows [`AtomicCell`] mutably (at compile-time) so there is no need for dynamic checks.
347    ///
348    /// However be cautious: this method expects self to be mutable,
349    /// which is generally not the case when using a [`AtomicCell`].
350    /// Take a look at the [borrow_mut] method instead if self isn’t mutable.
351    ///
352    /// Also, please be aware that this method is only for special circumstances
353    /// and is usually not what you want. In case of doubt, use borrow_mut instead.
354    ///
355    /// [borrow_mut]: #method.borrow_mut
356    ///
357    /// # Examples
358    ///
359    /// ```
360    /// use atomicell::AtomicCell;
361    ///
362    /// let mut c = AtomicCell::new(5);
363    /// *c.get_mut() += 1;
364    ///
365    /// assert_eq!(c, AtomicCell::new(6));
366    /// ```
367    #[inline]
368    pub fn get_mut(&mut self) -> &mut T {
369        self.value.get_mut()
370    }
371
372    /// Undo the effect of leaked guards on the borrow state of the [`AtomicCell`].
373    ///
374    /// This call is similar to get_mut but more specialized.
375    /// It borrows [`AtomicCell`] mutably to ensure no borrows exist and then resets the state tracking shared borrows.
376    /// This is relevant if some Ref or RefMut borrows have been leaked.
377    ///
378    /// # Examples
379    ///
380    /// ```
381    /// use atomicell::AtomicCell;
382    ///
383    /// let mut c = AtomicCell::new(0);
384    /// core::mem::forget(c.borrow_mut());
385    ///
386    /// assert!(c.try_borrow().is_none());
387    /// c.undo_leak();
388    /// assert!(c.try_borrow().is_some());
389    /// ```
390    #[inline]
391    pub fn undo_leak(&mut self) -> &mut T {
392        *self.lock.get_mut() = 0;
393        self.value.get_mut()
394    }
395
396    /// Immutably borrows the wrapped value, returning [`None`] if the value is currently mutably borrowed.
397    ///
398    /// # Safety
399    ///
400    /// Unlike [borrow], this method is unsafe because it does not return a [`Ref`],
401    /// thus leaving the borrow flag untouched.
402    ///
403    /// Mutably borrowing the [`AtomicCell`] while the reference returned by this method is alive is undefined behaviour.
404    ///
405    /// [borrow]: #method.borrow
406    ///
407    /// # Examples
408    ///
409    /// ```
410    /// use atomicell::AtomicCell;
411    ///
412    /// let c = AtomicCell::new(5);
413    ///
414    /// {
415    ///     assert!(unsafe { c.try_borrow_unguarded() }.is_some());
416    ///     let m = c.borrow_mut();
417    ///     assert!(unsafe { c.try_borrow_unguarded() }.is_none());
418    /// }
419    ///
420    /// {
421    ///     let m = c.borrow();
422    ///     assert!(unsafe { c.try_borrow_unguarded() }.is_some());
423    /// }
424    /// ```
425    #[inline]
426    pub unsafe fn try_borrow_unguarded(&self) -> Option<&T> {
427        if is_writing(self.lock.load(Ordering::Relaxed)) {
428            None
429        } else {
430            // SAFETY: We check that nobody is actively writing now, but it is
431            // the caller's responsibility to ensure that nobody writes until
432            // the returned reference is no longer in use.
433            Some(&*self.value.get())
434        }
435    }
436
437    /// Mutably borrows the wrapped value, returning [`None`] if the value is currently mutably borrowed.
438    ///
439    /// # Safety
440    ///
441    /// Unlike [borrow_mut], this method is unsafe because it does not return a [`Ref`],
442    /// and leaves the borrow flag untouched.
443    ///
444    /// Borrowing the [`AtomicCell`] while the reference returned by this method is alive is undefined behaviour.
445    ///
446    /// [borrow_mut]: #method.borrow_mut
447    ///
448    /// # Examples
449    ///
450    /// ```
451    /// use atomicell::AtomicCell;
452    ///
453    /// let c = AtomicCell::new(5);
454    ///
455    /// {
456    ///     assert!(unsafe { c.try_borrow_unguarded_mut() }.is_some());
457    ///     let m = c.borrow();
458    ///     assert!(unsafe { c.try_borrow_unguarded_mut() }.is_none());
459    /// }
460    /// ```
461    #[inline]
462    pub unsafe fn try_borrow_unguarded_mut(&self) -> Option<&mut T> {
463        let val = self.lock.load(Ordering::Relaxed);
464        if is_borrowed(val) {
465            None
466        } else {
467            // SAFETY: We check that nobody is actively reading or writing now, but it is
468            // the caller's responsibility to ensure that nobody writes until
469            // the returned reference is no longer in use.
470            Some(&mut *self.value.get())
471        }
472    }
473}
474
475impl<T> AtomicCell<T>
476where
477    T: Default,
478{
479    /// Takes the wrapped value, leaving [`Default::default()`] in its place.
480    ///
481    /// # Panics
482    ///
483    /// Panics if the value is currently borrowed.
484    ///
485    /// # Examples
486    ///
487    /// ```
488    /// use atomicell::AtomicCell;
489    ///
490    /// let c = AtomicCell::new(5);
491    /// let five = c.take();
492    ///
493    /// assert_eq!(five, 5);
494    /// assert_eq!(c.into_inner(), 0);
495    /// ```
496    #[inline]
497    pub fn take(&self) -> T {
498        let mut r = self.borrow_mut();
499        core::mem::take(&mut *r)
500    }
501}
502
503impl<T> Clone for AtomicCell<T>
504where
505    T: Clone,
506{
507    #[inline]
508    fn clone(&self) -> Self {
509        let r = self.borrow();
510        let t = Clone::clone(&*r);
511        AtomicCell::new(t)
512    }
513
514    #[inline]
515    fn clone_from(&mut self, other: &Self) {
516        self.get_mut().clone_from(&other.borrow());
517    }
518}
519
520impl<T> Debug for AtomicCell<T>
521where
522    T: Debug,
523{
524    #[inline]
525    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
526        Debug::fmt(&*self.borrow(), f)
527    }
528}
529
530impl<T> Display for AtomicCell<T>
531where
532    T: Display,
533{
534    #[inline]
535    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
536        Display::fmt(&*self.borrow(), f)
537    }
538}
539
540impl<T> From<T> for AtomicCell<T> {
541    #[inline]
542    fn from(t: T) -> Self {
543        AtomicCell::new(t)
544    }
545}
546
547impl<T, U> PartialEq<AtomicCell<U>> for AtomicCell<T>
548where
549    T: PartialEq<U>,
550{
551    fn eq(&self, other: &AtomicCell<U>) -> bool {
552        self.borrow().eq(&other.borrow())
553    }
554}
555
556impl<T> Eq for AtomicCell<T> where T: Eq {}
557
558impl<T, U> PartialOrd<AtomicCell<U>> for AtomicCell<T>
559where
560    T: PartialOrd<U>,
561{
562    fn partial_cmp(&self, other: &AtomicCell<U>) -> Option<cmp::Ordering> {
563        self.borrow().partial_cmp(&other.borrow())
564    }
565}
566
567impl<T> Ord for AtomicCell<T>
568where
569    T: Ord,
570{
571    fn cmp(&self, other: &AtomicCell<T>) -> cmp::Ordering {
572        self.borrow().cmp(&other.borrow())
573    }
574}
575
576#[inline(never)]
577#[track_caller]
578#[cold]
579const fn failed_to_borrow() -> ! {
580    panic!("Failed to borrow AtomicCell immutably");
581}
582
583#[inline(never)]
584#[track_caller]
585#[cold]
586const fn failed_to_borrow_mut() -> ! {
587    panic!("Failed to borrow AtomicCell mutably");
588}