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