radium/
lib.rs

1//! `radium` provides a series of helpers for a uniform API over both atomic
2//! types like [`AtomicUsize`], and non-atomic types like [`Cell<T>`].
3//!
4//! This crate is `#![no_std]`-compatible, and uses no non-core types.
5//!
6//! For details, see the documentation for [`Radium`].
7//!
8//! The `types` module provides type names that are atomic where the target
9//! supports it, and fall back to `Cell` when the target does not.
10//!
11//! The `if_atomic!` macro provides a means of conditional compilation based on
12//! the presence of atomic instructions. It is a substitute for the
13//! `cfg(target_has_atomic)` or `cfg(accessible)` attribute tests, which are not
14//! yet stabilized.
15//!
16//! ---
17//!
18//! **@kneecaw** - <https://twitter.com/kneecaw/status/1132695060812849154>
19//! > Feelin' lazy: Has someone already written a helper trait abstracting
20//! > operations over `AtomicUsize` and `Cell<usize>` for generic code which may
21//! > not care about atomicity?
22//!
23//! **@ManishEarth** - <https://twitter.com/ManishEarth/status/1132706585300496384>
24//! > no but call the crate radium
25//! >
26//! > (since people didn't care that it was radioactive and used it in everything)
27//!
28//! [`AtomicUsize`]: core::sync::atomic::AtomicUsize
29//! [`Cell<T>`]: core::cell::Cell
30
31#![no_std]
32#![deny(unconditional_recursion)]
33
34#[macro_use]
35mod macros;
36
37pub mod types;
38
39use core::cell::Cell;
40use core::sync::atomic::Ordering;
41
42if_atomic! {
43    if atomic(8) {
44        use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU8};
45    }
46    if atomic(16) {
47        use core::sync::atomic::{AtomicI16, AtomicU16};
48    }
49    if atomic(32) {
50        use core::sync::atomic::{AtomicI32, AtomicU32};
51    }
52    if atomic(64) {
53        use core::sync::atomic::{AtomicI64, AtomicU64};
54    }
55    if atomic(ptr) {
56        use core::sync::atomic::{AtomicIsize, AtomicPtr, AtomicUsize};
57    }
58}
59
60/// A maybe-atomic shared mutable fundamental type `T`.
61///
62/// This trait is implemented by both the [atomic wrapper] type for `T`, and by
63/// [`Cell<T>`], providing a consistent interface for interacting with the two
64/// types.
65///
66/// This trait provides methods predicated on marker traits for the underlying
67/// fundamental. Only types which can be viewed as sequences of bits may use the
68/// functions for bit-wise arithmetic, and only types which can be used as
69/// integers may use the functions for numeric arithmetic. Use of these methods
70/// on insufficient underlying types (for example, `Radium::fetch_and` on an
71/// atomic or cell-wrapped pointer) will cause a compiler error.
72///
73/// [atomic wrapper]: core::sync::atomic
74/// [`Cell<T>`]: core::cell::Cell
75pub trait Radium {
76    type Item;
77    /// Creates a new value of this type.
78    fn new(value: Self::Item) -> Self;
79
80    /// If the underlying value is atomic, calls [`fence`] with the given
81    /// [`Ordering`]. Otherwise, does nothing.
82    ///
83    /// [`Ordering`]: core::sync::atomic::Ordering
84    /// [`fence`]: core::sync::atomic::fence
85    fn fence(order: Ordering);
86
87    /// Returns a mutable reference to the underlying value.
88    ///
89    /// This is safe because the mutable reference to `self` guarantees that no
90    /// other references exist to this value.
91    fn get_mut(&mut self) -> &mut Self::Item;
92
93    /// Consumes the wrapper and returns the contained value.
94    ///
95    /// This is safe as passing by value ensures no other references exist.
96    fn into_inner(self) -> Self::Item;
97
98    /// Load a value from this object.
99    ///
100    /// Ordering values are ignored by non-atomic types.
101    ///
102    /// See also: [`AtomicUsize::load`].
103    ///
104    /// [`AtomicUsize::load`]: core::sync::atomic::AtomicUsize::load
105    fn load(&self, order: Ordering) -> Self::Item;
106
107    /// Store a value in this object.
108    ///
109    /// Ordering arguments are ignored by non-atomic types.
110    ///
111    /// See also: [`AtomicUsize::store`].
112    ///
113    /// [`AtomicUsize::store`]: core::sync::atomic::AtomicUsize::store
114    fn store(&self, value: Self::Item, order: Ordering);
115
116    /// Swap with the value stored in this object.
117    ///
118    /// Ordering arguments are ignored by non-atomic types.
119    ///
120    /// See also: [`AtomicUsize::swap`].
121    ///
122    /// [`AtomicUsize::swap`]: core::sync::atomic::AtomicUsize::swap
123    fn swap(&self, value: Self::Item, order: Ordering) -> Self::Item;
124
125    /// Stores a value into this object if the currently-stored value is the
126    /// same as the `current` value.
127    ///
128    /// The return value is always the previously-stored value. If it is equal to
129    /// `current`, then the value was updated with `new`.
130    ///
131    /// Ordering arguments are ignored by non-atomic types.
132    ///
133    /// See also: [`AtomicUsize::compare_and_swap`].
134    ///
135    /// [`AtomicUsize::compare_and_swap`]: core::sync::atomic::AtomicUsize::compare_and_swap
136    #[deprecated = "Use `compare_exchange` or `compare_exchange_weak` instead"]
137    fn compare_and_swap(&self, current: Self::Item, new: Self::Item, order: Ordering)
138        -> Self::Item;
139
140    /// Stores a value into this object if the currently-stored value is the
141    /// same as the `current` value.
142    ///
143    /// The return value is a `Result` indicating whether the new value was
144    /// written, and containing the previously-stored value. On success, this
145    /// value is guaranteed to be equal to `current`.
146    ///
147    /// Ordering arguments are ignored by non-atomic types.
148    ///
149    /// See also: [`AtomicUsize::compare_exchange`].
150    ///
151    /// [`AtomicUsize::compare_exchange`]: core::sync::atomic::AtomicUsize::compare_exchange
152    fn compare_exchange(
153        &self,
154        current: Self::Item,
155        new: Self::Item,
156        success: Ordering,
157        failure: Ordering,
158    ) -> Result<Self::Item, Self::Item>;
159
160    /// Stores a value into this object if the currently-stored value is the
161    /// same as the `current` value.
162    ///
163    /// Unlike `compare_exchange`, this function is allowed to spuriously fail
164    /// even when the comparison succeeds, which can result in more efficient
165    /// code on some platforms. The return value is a `Result` indicating
166    /// whether the new value was written, and containing the previously-stored
167    /// value.
168    ///
169    /// Ordering arguments are ignored by non-atomic types.
170    ///
171    /// See also: [`AtomicUsize::compare_exchange_weak`].
172    ///
173    /// [`AtomicUsize::compare_exchange_weak`]: core::sync::atomic::AtomicUsize::compare_exchange_weak
174    fn compare_exchange_weak(
175        &self,
176        current: Self::Item,
177        new: Self::Item,
178        success: Ordering,
179        failure: Ordering,
180    ) -> Result<Self::Item, Self::Item>;
181
182    /// Performs a bitwise "and" on the currently-stored value and the argument
183    /// `value`, and stores the result in `self`.
184    ///
185    /// Returns the previously-stored value.
186    ///
187    /// Ordering arguments are ignored by non-atomic types.
188    ///
189    /// See also: [`AtomicUsize::fetch_and`].
190    ///
191    /// [`AtomicUsize::fetch_and`]: core::sync::atomic::AtomicUsize::fetch_and
192    fn fetch_and(&self, value: Self::Item, order: Ordering) -> Self::Item
193    where
194        Self::Item: marker::BitOps;
195
196    /// Performs a bitwise "nand" on the currently-stored value and the argument
197    /// `value`, and stores the result in `self`.
198    ///
199    /// Returns the previously-stored value.
200    ///
201    /// Ordering arguments are ignored by non-atomic types.
202    ///
203    /// See also: [`AtomicUsize::fetch_nand`].
204    ///
205    /// [`AtomicUsize::fetch_nand`]: core::sync::atomic::AtomicUsize::fetch_nand
206    fn fetch_nand(&self, value: Self::Item, order: Ordering) -> Self::Item
207    where
208        Self::Item: marker::BitOps;
209
210    /// Performs a bitwise "or" on the currently-stored value and the argument
211    /// `value`, and stores the result in `self`.
212    ///
213    /// Returns the previously-stored value.
214    ///
215    /// Ordering arguments are ignored by non-atomic types.
216    ///
217    /// See also: [`AtomicUsize::fetch_or`].
218    ///
219    /// [`AtomicUsize::fetch_or`]: core::sync::atomic::AtomicUsize::fetch_or
220    fn fetch_or(&self, value: Self::Item, order: Ordering) -> Self::Item
221    where
222        Self::Item: marker::BitOps;
223
224    /// Performs a bitwise "xor" on the currently-stored value and the argument
225    /// `value`, and stores the result in `self`.
226    ///
227    /// Returns the previously-stored value.
228    ///
229    /// Ordering arguments are ignored by non-atomic types.
230    ///
231    /// See also: [`AtomicUsize::fetch_xor`].
232    ///
233    /// [`AtomicUsize::fetch_xor`]: core::sync::atomic::AtomicUsize::fetch_xor
234    fn fetch_xor(&self, value: Self::Item, order: Ordering) -> Self::Item
235    where
236        Self::Item: marker::BitOps;
237
238    /// Adds `value` to the currently-stored value, wrapping on overflow, and
239    /// stores the result in `self`.
240    ///
241    /// Returns the previously-stored value.
242    ///
243    /// Ordering arguments are ignored by non-atomic types.
244    ///
245    /// See also: [`AtomicUsize::fetch_add`].
246    ///
247    /// [`AtomicUsize::fetch_add`]: core::sync::atomic::AtomicUsize::fetch_add
248    fn fetch_add(&self, value: Self::Item, order: Ordering) -> Self::Item
249    where
250        Self::Item: marker::NumericOps;
251
252    /// Subtracts `value` from the currently-stored value, wrapping on
253    /// underflow, and stores the result in `self`.
254    ///
255    /// Returns the previously-stored value.
256    ///
257    /// Ordering arguments are ignored by non-atomic types.
258    ///
259    /// See also: [`AtomicUsize::fetch_sub`].
260    ///
261    /// [`AtomicUsize::fetch_sub`]: core::sync::atomic::AtomicUsize::fetch_sub
262    fn fetch_sub(&self, value: Self::Item, order: Ordering) -> Self::Item
263    where
264        Self::Item: marker::NumericOps;
265
266    /// Fetches the value, and applies a function to it that returns an
267    /// optional new value.
268    ///
269    /// Note: This may call the function multiple times if the value has been
270    /// changed from other threads in the meantime, as long as the function
271    /// returns `Some(_)`, but the function will have been applied only once to
272    /// the stored value.
273    ///
274    /// Returns a `Result` of `Ok(previous_value)` if the function returned
275    /// `Some(_)`, else `Err(previous_value)`.
276    ///
277    /// Ordering arguments are ignored by non-atomic types.
278    ///
279    /// See also: [`AtomicUsize::fetch_update`].
280    ///
281    /// [`AtomicUsize::fetch_update`]: core::sync::atomic::AtomicUsize::fetch_update
282    fn fetch_update<F>(
283        &self,
284        set_order: Ordering,
285        fetch_order: Ordering,
286        f: F,
287    ) -> Result<Self::Item, Self::Item>
288    where
289        F: FnMut(Self::Item) -> Option<Self::Item>;
290}
291
292/// Marker traits used by [`Radium`].
293pub mod marker {
294    /// Types supporting maybe-atomic bitwise operations.
295    ///
296    /// Types implementing this trait support the [`fetch_and`], [`fetch_nand`],
297    /// [`fetch_or`], and [`fetch_xor`] maybe-atomic operations.
298    ///
299    /// [`fetch_and`]: crate::Radium::fetch_and
300    /// [`fetch_nand`]: crate::Radium::fetch_nand
301    /// [`fetch_or`]: crate::Radium::fetch_or
302    /// [`fetch_xor`]: crate::Radium::fetch_xor
303    ///
304    /// `bool` and all integer fundamental types implement this.
305    ///
306    /// ```rust
307    /// # use core::sync::atomic::*;
308    /// # use radium::Radium;
309    /// let num: AtomicUsize = AtomicUsize::new(0);
310    /// Radium::fetch_or(&num, 2, Ordering::Relaxed);
311    /// ```
312    ///
313    /// Pointers do not. This will cause a compiler error.
314    ///
315    /// ```rust,compile_fail
316    /// # use core::sync::atomic::*;
317    /// # use radium::Radium;
318    /// # use core::ptr;
319    /// let ptr: AtomicPtr<usize> = Default::default();
320    /// Radium::fetch_or(&ptr, ptr::null_mut(), Ordering::Relaxed);
321    /// ```
322    pub trait BitOps {}
323
324    /// Types supporting maybe-atomic arithmetic operations.
325    ///
326    /// Types implementing this trait support the [`fetch_add`] and
327    /// [`fetch_sub`] maybe-atomic operations.
328    ///
329    /// [`fetch_add`]: crate::Radium::fetch_add
330    /// [`fetch_sub`]: crate::Radium::fetch_sub
331    ///
332    /// The integer types, such as `usize` and `i32`, implement this trait.
333    ///
334    /// ```rust
335    /// # use core::sync::atomic::*;
336    /// # use radium::Radium;
337    /// let num: AtomicUsize = AtomicUsize::new(2);
338    /// Radium::fetch_add(&num, 2, Ordering::Relaxed);
339    /// ```
340    ///
341    /// `bool` and pointers do not. This will cause a compiler error.
342    ///
343    /// ```rust,compile_fail
344    /// # use core::sync::atomic::*;
345    /// # use radium::Radium;
346    /// let bit: AtomicBool = AtomicBool::new(false);
347    /// Radium::fetch_add(&bit, true, Ordering::Relaxed);
348    /// ```
349    pub trait NumericOps: BitOps {}
350}
351
352macro_rules! radium {
353    // Emit the universal `Radium` trait function bodies for atomic types.
354    ( atom $base:ty ) => {
355        #[inline]
356        fn new(value: $base) -> Self {
357            Self::new(value)
358        }
359
360        #[inline]
361        fn fence(order: Ordering) {
362            core::sync::atomic::fence(order);
363        }
364
365        #[inline]
366        fn get_mut(&mut self) -> &mut $base {
367            self.get_mut()
368        }
369
370        #[inline]
371        fn into_inner(self) -> $base {
372            self.into_inner()
373        }
374
375        #[inline]
376        fn load(&self, order: Ordering) -> $base {
377            self.load(order)
378        }
379
380        #[inline]
381        fn store(&self, value: $base, order: Ordering) {
382            self.store(value, order);
383        }
384
385        #[inline]
386        fn swap(&self, value: $base, order: Ordering) -> $base {
387            self.swap(value, order)
388        }
389
390        #[inline]
391        #[allow(deprecated)]
392        fn compare_and_swap(&self, current: $base, new: $base, order: Ordering) -> $base {
393            self.compare_and_swap(current, new, order)
394        }
395
396        #[inline]
397        fn compare_exchange(
398            &self,
399            current: $base,
400            new: $base,
401            success: Ordering,
402            failure: Ordering,
403        ) -> Result<$base, $base> {
404            self.compare_exchange(current, new, success, failure)
405        }
406
407        #[inline]
408        fn compare_exchange_weak(
409            &self,
410            current: $base,
411            new: $base,
412            success: Ordering,
413            failure: Ordering,
414        ) -> Result<$base, $base> {
415            self.compare_exchange_weak(current, new, success, failure)
416        }
417
418        #[inline]
419        fn fetch_update<F>(
420            &self,
421            set_order: Ordering,
422            fetch_order: Ordering,
423            f: F,
424        ) -> Result<$base, $base>
425        where
426            F: FnMut($base) -> Option<$base>,
427        {
428            self.fetch_update(set_order, fetch_order, f)
429        }
430    };
431
432    // Emit the `Radium` trait function bodies for bit-wise types.
433    ( atom_bit $base:ty ) => {
434        #[inline]
435        fn fetch_and(&self, value: $base, order: Ordering) -> $base {
436            self.fetch_and(value, order)
437        }
438
439        #[inline]
440        fn fetch_nand(&self, value: $base, order: Ordering) -> $base {
441            self.fetch_nand(value, order)
442        }
443
444        #[inline]
445        fn fetch_or(&self, value: $base, order: Ordering) -> $base {
446            self.fetch_or(value, order)
447        }
448
449        #[inline]
450        fn fetch_xor(&self, value: $base, order: Ordering) -> $base {
451            self.fetch_xor(value, order)
452        }
453    };
454
455    // Emit the `Radium` trait function bodies for integral types.
456    ( atom_int $base:ty ) => {
457        #[inline]
458        fn fetch_add(&self, value: $base, order: Ordering) -> $base {
459            self.fetch_add(value, order)
460        }
461
462        #[inline]
463        fn fetch_sub(&self, value: $base, order: Ordering) -> $base {
464            self.fetch_sub(value, order)
465        }
466    };
467
468    // Emit the universal `Radium` trait function bodies for `Cell<_>`.
469    ( cell $base:ty ) => {
470        #[inline]
471        fn new(value: $base) -> Self {
472            Cell::new(value)
473        }
474
475        #[inline]
476        fn fence(_: Ordering) {}
477
478        #[inline]
479        fn get_mut(&mut self) -> &mut $base {
480            self.get_mut()
481        }
482
483        #[inline]
484        fn into_inner(self) -> $base {
485            self.into_inner()
486        }
487
488        #[inline]
489        fn load(&self, _: Ordering) -> $base {
490            self.get()
491        }
492
493        #[inline]
494        fn store(&self, value: $base, _: Ordering) {
495            self.set(value);
496        }
497
498        #[inline]
499        fn swap(&self, value: $base, _: Ordering) -> $base {
500            self.replace(value)
501        }
502
503        #[inline]
504        fn compare_and_swap(&self, current: $base, new: $base, _: Ordering) -> $base {
505            if self.get() == current {
506                self.replace(new)
507            } else {
508                self.get()
509            }
510        }
511
512        #[inline]
513        fn compare_exchange(
514            &self,
515            current: $base,
516            new: $base,
517            _: Ordering,
518            _: Ordering,
519        ) -> Result<$base, $base> {
520            if self.get() == current {
521                Ok(self.replace(new))
522            } else {
523                Err(self.get())
524            }
525        }
526
527        #[inline]
528        fn compare_exchange_weak(
529            &self,
530            current: $base,
531            new: $base,
532            success: Ordering,
533            failure: Ordering,
534        ) -> Result<$base, $base> {
535            Radium::compare_exchange(self, current, new, success, failure)
536        }
537
538        #[inline]
539        fn fetch_update<F>(&self, _: Ordering, _: Ordering, mut f: F) -> Result<$base, $base>
540        where
541            F: FnMut($base) -> Option<$base>,
542        {
543            match f(self.get()) {
544                Some(x) => Ok(self.replace(x)),
545                None => Err(self.get()),
546            }
547        }
548    };
549
550    // Emit the `Radium` trait function bodies for bit-wise types.
551    ( cell_bit $base:ty ) => {
552        #[inline]
553        fn fetch_and(&self, value: $base, _: Ordering) -> $base {
554            self.replace(self.get() & value)
555        }
556
557        #[inline]
558        fn fetch_nand(&self, value: $base, _: Ordering) -> $base {
559            self.replace(!(self.get() & value))
560        }
561
562        #[inline]
563        fn fetch_or(&self, value: $base, _: Ordering) -> $base {
564            self.replace(self.get() | value)
565        }
566
567        #[inline]
568        fn fetch_xor(&self, value: $base, _: Ordering) -> $base {
569            self.replace(self.get() ^ value)
570        }
571    };
572
573    // Emit the `Radium` trait function bodies for integral types.
574    ( cell_int $base:ty ) => {
575        #[inline]
576        fn fetch_add(&self, value: $base, _: Ordering) -> $base {
577            self.replace(self.get().wrapping_add(value))
578        }
579
580        #[inline]
581        fn fetch_sub(&self, value: $base, _: Ordering) -> $base {
582            self.replace(self.get().wrapping_sub(value))
583        }
584    };
585}
586
587macro_rules! radium_int {
588    ( $( $width:tt: $base:ty , $atom:ty ; )* ) => { $(
589        impl marker::BitOps for $base {}
590        impl marker::NumericOps for $base {}
591
592        if_atomic!(if atomic($width) {
593            impl Radium for $atom {
594                type Item = $base;
595
596                radium!(atom $base);
597                radium!(atom_bit $base);
598                radium!(atom_int $base);
599            }
600        });
601
602        impl Radium for Cell<$base> {
603            type Item = $base;
604
605            radium!(cell $base);
606            radium!(cell_bit $base);
607            radium!(cell_int $base);
608        }
609    )* };
610}
611
612radium_int! {
613    8: i8, AtomicI8;
614    8: u8, AtomicU8;
615    16: i16, AtomicI16;
616    16: u16, AtomicU16;
617    32: i32, AtomicI32;
618    32: u32, AtomicU32;
619    64: i64, AtomicI64;
620    64: u64, AtomicU64;
621    size: isize, AtomicIsize;
622    size: usize, AtomicUsize;
623}
624
625impl marker::BitOps for bool {}
626
627if_atomic!(if atomic(bool) {
628    impl Radium for AtomicBool {
629        type Item = bool;
630
631        radium!(atom bool);
632        radium!(atom_bit bool);
633
634        /// ```compile_fail
635        /// # use std::{ptr, sync::atomic::*, cell::*};
636        /// # use radium::*;
637        /// let atom = AtomicBool::new(false);
638        /// Radium::fetch_add(&atom, true, Ordering::Relaxed);
639        /// ```
640        #[doc(hidden)]
641        fn fetch_add(&self, _value: bool, _order: Ordering) -> bool {
642            unreachable!("This method statically cannot be called")
643        }
644
645        /// ```compile_fail
646        /// # use std::{ptr, sync::atomic::*, cell::*};
647        /// # use radium::*;
648        /// let atom = AtomicBool::new(false);
649        /// Radium::fetch_sub(&atom, true, Ordering::Relaxed);
650        /// ```
651        #[doc(hidden)]
652        fn fetch_sub(&self, _value: bool, _order: Ordering) -> bool {
653            unreachable!("This method statically cannot be called")
654        }
655    }
656});
657
658impl Radium for Cell<bool> {
659    type Item = bool;
660
661    radium!(cell bool);
662    radium!(cell_bit bool);
663
664    /// ```compile_fail
665    /// # use std::{ptr, sync::atomic::*, cell::*};
666    /// # use radium::*;
667    /// let cell = Cell::<bool>::new(false);
668    /// Radium::fetch_add(&cell, true, Ordering::Relaxed);
669    /// ```
670    #[doc(hidden)]
671    fn fetch_add(&self, _value: bool, _order: Ordering) -> bool {
672        unreachable!("This method statically cannot be called")
673    }
674
675    /// ```compile_fail
676    /// # use std::{ptr, sync::atomic::*, cell::*};
677    /// # use radium::*;
678    /// let cell = Cell::<bool>::new(false);
679    /// Radium::fetch_sub(&cell, true, Ordering::Relaxed);
680    /// ```
681    #[doc(hidden)]
682    fn fetch_sub(&self, _value: bool, _order: Ordering) -> bool {
683        unreachable!("This method statically cannot be called")
684    }
685}
686
687if_atomic!(if atomic(ptr) {
688    impl<T> Radium for AtomicPtr<T> {
689        type Item = *mut T;
690
691        radium!(atom *mut T);
692
693        /// ```compile_fail
694        /// # use std::{ptr, sync::atomic::*, cell::*};
695        /// # use radium::*;
696        /// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
697        /// Radium::fetch_and(&atom, ptr::null_mut(), Ordering::Relaxed);
698        /// ```
699        #[doc(hidden)]
700        fn fetch_and(&self, _value: *mut T, _order: Ordering) -> *mut T {
701            unreachable!("This method statically cannot be called")
702        }
703
704        /// ```compile_fail
705        /// # use std::{ptr, sync::atomic::*, cell::*};
706        /// # use radium::*;
707        /// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
708        /// Radium::fetch_nand(&atom, ptr::null_mut(), Ordering::Relaxed);
709        /// ```
710        #[doc(hidden)]
711        fn fetch_nand(&self, _value: *mut T, _order: Ordering) -> *mut T {
712            unreachable!("This method statically cannot be called")
713        }
714
715        /// ```compile_fail
716        /// # use std::{ptr, sync::atomic::*, cell::*};
717        /// # use radium::*;
718        /// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
719        /// Radium::fetch_or(&atom, ptr::null_mut(), Ordering::Relaxed);
720        /// ```
721        #[doc(hidden)]
722        fn fetch_or(&self, _value: *mut T, _order: Ordering) -> *mut T {
723            unreachable!("This method statically cannot be called")
724        }
725
726        /// ```compile_fail
727        /// # use std::{ptr, sync::atomic::*, cell::*};
728        /// # use radium::*;
729        /// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
730        /// Radium::fetch_xor(&atom, ptr::null_mut(), Ordering::Relaxed);
731        /// ```
732        #[doc(hidden)]
733        fn fetch_xor(&self, _value: *mut T, _order: Ordering) -> *mut T {
734            unreachable!("This method statically cannot be called")
735        }
736
737        /// ```compile_fail
738        /// # use std::{ptr, sync::atomic::*, cell::*};
739        /// # use radium::*;
740        /// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
741        /// Radium::fetch_add(&atom, ptr::null_mut(), Ordering::Relaxed);
742        /// ```
743        #[doc(hidden)]
744        fn fetch_add(&self, _value: *mut T, _order: Ordering) -> *mut T {
745            unreachable!("This method statically cannot be called")
746        }
747
748        /// ```compile_fail
749        /// # use std::{ptr, sync::atomic::*, cell::*};
750        /// # use radium::*;
751        /// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
752        /// Radium::fetch_sub(&atom, ptr::null_mut(), Ordering::Relaxed);
753        /// ```
754        #[doc(hidden)]
755        fn fetch_sub(&self, _value: *mut T, _order: Ordering) -> *mut T {
756            unreachable!("This method statically cannot be called")
757        }
758    }
759});
760
761impl<T> Radium for Cell<*mut T> {
762    type Item = *mut T;
763
764    radium!(cell *mut T);
765
766    /// ```compile_fail
767    /// # use std::{ptr, sync::atomic::*, cell::*};
768    /// # use radium::*;
769    /// let cell = Cell::<*mut u8>::new(ptr::null_mut());
770    /// Radium::fetch_and(&cell, ptr::null_mut(), Ordering::Relaxed);
771    /// ```
772    #[doc(hidden)]
773    fn fetch_and(&self, _value: *mut T, _order: Ordering) -> *mut T {
774        unreachable!("This method statically cannot be called")
775    }
776
777    /// ```compile_fail
778    /// # use std::{ptr, sync::atomic::*, cell::*};
779    /// # use radium::*;
780    /// let cell = Cell::<*mut u8>::new(ptr::null_mut());
781    /// Radium::fetch_nand(&cell, ptr::null_mut(), Ordering::Relaxed);
782    /// ```
783    #[doc(hidden)]
784    fn fetch_nand(&self, _value: *mut T, _order: Ordering) -> *mut T {
785        unreachable!("This method statically cannot be called")
786    }
787
788    /// ```compile_fail
789    /// # use std::{ptr, sync::atomic::*, cell::*};
790    /// # use radium::*;
791    /// let cell = Cell::<*mut u8>::new(ptr::null_mut());
792    /// Radium::fetch_or(&cell, ptr::null_mut(), Ordering::Relaxed);
793    /// ```
794    #[doc(hidden)]
795    fn fetch_or(&self, _value: *mut T, _order: Ordering) -> *mut T {
796        unreachable!("This method statically cannot be called")
797    }
798
799    /// ```compile_fail
800    /// # use std::{ptr, sync::atomic::*, cell::*};
801    /// # use radium::*;
802    /// let cell = Cell::<*mut u8>::new(ptr::null_mut());
803    /// Radium::fetch_xor(&cell, ptr::null_mut(), Ordering::Relaxed);
804    /// ```
805    #[doc(hidden)]
806    fn fetch_xor(&self, _value: *mut T, _order: Ordering) -> *mut T {
807        unreachable!("This method statically cannot be called")
808    }
809
810    /// ```compile_fail
811    /// # use std::{ptr, sync::atomic::*, cell::*};
812    /// # use radium::*;
813    /// let cell = Cell::<*mut u8>::new(ptr::null_mut());
814    /// Radium::fetch_add(&cell, ptr::null_mut(), Ordering::Relaxed);
815    /// ```
816    #[doc(hidden)]
817    fn fetch_add(&self, _value: *mut T, _order: Ordering) -> *mut T {
818        unreachable!("This method statically cannot be called")
819    }
820
821    /// ```compile_fail
822    /// # use std::{ptr, sync::atomic::*, cell::*};
823    /// # use radium::*;
824    /// let cell = Cell::<*mut u8>::new(ptr::null_mut());
825    /// Radium::fetch_sub(&cell, ptr::null_mut(), Ordering::Relaxed);
826    /// ```
827    #[doc(hidden)]
828    fn fetch_sub(&self, _value: *mut T, _order: Ordering) -> *mut T {
829        unreachable!("This method statically cannot be called")
830    }
831}
832
833#[cfg(test)]
834mod tests {
835    use super::*;
836    use core::cell::Cell;
837
838    #[test]
839    fn absent_traits() {
840        static_assertions::assert_not_impl_any!(bool: marker::NumericOps);
841        static_assertions::assert_not_impl_any!(*mut u8: marker::BitOps, marker::NumericOps);
842    }
843
844    #[test]
845    fn present_traits() {
846        static_assertions::assert_impl_all!(bool: marker::BitOps);
847        static_assertions::assert_impl_all!(usize: marker::BitOps, marker::NumericOps);
848    }
849
850    #[test]
851    fn always_cell() {
852        static_assertions::assert_impl_all!(Cell<bool>: Radium<Item = bool>);
853        static_assertions::assert_impl_all!(Cell<i8>: Radium<Item = i8>);
854        static_assertions::assert_impl_all!(Cell<u8>: Radium<Item = u8>);
855        static_assertions::assert_impl_all!(Cell<i16>: Radium<Item = i16>);
856        static_assertions::assert_impl_all!(Cell<u16>: Radium<Item = u16>);
857        static_assertions::assert_impl_all!(Cell<i32>: Radium<Item = i32>);
858        static_assertions::assert_impl_all!(Cell<u32>: Radium<Item = u32>);
859        static_assertions::assert_impl_all!(Cell<i64>: Radium<Item = i64>);
860        static_assertions::assert_impl_all!(Cell<u64>: Radium<Item = u64>);
861        static_assertions::assert_impl_all!(Cell<isize>: Radium<Item = isize>);
862        static_assertions::assert_impl_all!(Cell<usize>: Radium<Item = usize>);
863        static_assertions::assert_impl_all!(Cell<*mut ()>: Radium<Item = *mut ()>);
864    }
865
866    #[test]
867    fn always_alias() {
868        static_assertions::assert_impl_all!(types::RadiumBool: Radium<Item = bool>);
869        static_assertions::assert_impl_all!(types::RadiumI8: Radium<Item = i8>);
870        static_assertions::assert_impl_all!(types::RadiumU8: Radium<Item = u8>);
871        static_assertions::assert_impl_all!(types::RadiumI16: Radium<Item = i16>);
872        static_assertions::assert_impl_all!(types::RadiumU16: Radium<Item = u16>);
873        static_assertions::assert_impl_all!(types::RadiumI32: Radium<Item = i32>);
874        static_assertions::assert_impl_all!(types::RadiumU32: Radium<Item = u32>);
875        static_assertions::assert_impl_all!(types::RadiumI64: Radium<Item = i64>);
876        static_assertions::assert_impl_all!(types::RadiumU64: Radium<Item = u64>);
877        static_assertions::assert_impl_all!(types::RadiumIsize: Radium<Item = isize>);
878        static_assertions::assert_impl_all!(types::RadiumUsize: Radium<Item = usize>);
879        static_assertions::assert_impl_all!(types::RadiumPtr<()>: Radium<Item = *mut ()>);
880    }
881
882    #[test]
883    fn maybe_atom() {
884        if_atomic! {
885            if atomic(bool) {
886                use core::sync::atomic::*;
887                static_assertions::assert_impl_all!(AtomicBool: Radium<Item = bool>);
888            }
889            if atomic(8) {
890                static_assertions::assert_impl_all!(AtomicI8: Radium<Item = i8>);
891                static_assertions::assert_impl_all!(AtomicU8: Radium<Item = u8>);
892            }
893            if atomic(16) {
894                static_assertions::assert_impl_all!(AtomicI16: Radium<Item = i16>);
895                static_assertions::assert_impl_all!(AtomicU16: Radium<Item = u16>);
896            }
897            if atomic(32) {
898                static_assertions::assert_impl_all!(AtomicI32: Radium<Item = i32>);
899                static_assertions::assert_impl_all!(AtomicU32: Radium<Item = u32>);
900            }
901            if atomic(64) {
902                static_assertions::assert_impl_all!(AtomicI64: Radium<Item = i64>);
903                static_assertions::assert_impl_all!(AtomicU64: Radium<Item = u64>);
904            }
905            if atomic(size) {
906                static_assertions::assert_impl_all!(AtomicIsize: Radium<Item = isize>);
907                static_assertions::assert_impl_all!(AtomicUsize: Radium<Item = usize>);
908            }
909            if atomic(ptr) {
910                static_assertions::assert_impl_all!(AtomicPtr<()>: Radium<Item = *mut ()>);
911            }
912        }
913    }
914}