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}