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}