maybe_atomic/
lib.rs

1// MIT + Apache 2.0
2
3//! Rust atomic primitives that can be configured to not be atomic.
4
5#![forbid(unsafe_code)]
6#![warn(rust_2018_idioms)]
7#![no_std]
8
9#[cfg(not(feature = "atomic"))]
10use core::cell::Cell;
11#[cfg(feature = "atomic")]
12use core::sync::atomic::{
13    AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
14    AtomicU64, AtomicU8, AtomicUsize,
15};
16
17use core::sync::atomic::Ordering;
18use doc_comment::doc_comment;
19
20macro_rules! maybe_atomic_type {
21    ($tyname: ident: $atomic: ty | $unsync: ty) => {
22        doc_comment! {
23            concat!(
24                "An atomic structure that wraps either an ",
25                stringify!($atomic),
26                " or a ",
27                stringify!($unsync),
28                ", depending on if atomics are available."
29            ),
30            #[repr(transparent)]
31            pub struct $tyname {
32                #[cfg(feature = "atomic")]
33                atomic: $atomic,
34                #[cfg(not(feature = "atomic"))]
35                unsync: Cell<$unsync>,
36            }
37        }
38
39        impl $tyname {
40            doc_comment! {
41                concat!(
42                    "Creates a new instance of ",
43                    stringify!($tyname),
44                    "."
45                ),
46                #[inline]
47                pub fn new(inner: $unsync) -> Self {
48                    Self::new_impl(inner)
49                }
50            }
51
52            #[cfg(feature = "atomic")]
53            #[inline]
54            fn new_impl(inner: $unsync) -> Self {
55                Self {
56                    atomic: <$atomic>::new(inner),
57                }
58            }
59
60            #[cfg(not(feature = "atomic"))]
61            #[inline]
62            fn new_impl(inner: $unsync) -> Self {
63                Self {
64                    unsync: Cell::new(inner),
65                }
66            }
67
68            /// Get a mutable reference to the value contained within.
69            #[inline]
70            pub fn get_mut(&mut self) -> &mut $unsync {
71                self.get_mut_impl()
72            }
73
74            #[cfg(feature = "atomic")]
75            #[inline]
76            fn get_mut_impl(&mut self) -> &mut $unsync {
77                self.atomic.get_mut()
78            }
79
80            #[cfg(not(feature = "atomic"))]
81            #[inline]
82            fn get_mut_impl(&mut self) -> &mut $unsync {
83                self.unsync.get_mut()
84            }
85
86            /// Copy the value out of this container using the specified ordering.
87            #[inline]
88            pub fn load(&self, order: Ordering) -> $unsync {
89                self.load_impl(order)
90            }
91
92            #[cfg(feature = "atomic")]
93            #[inline]
94            fn load_impl(&self, order: Ordering) -> $unsync {
95                self.atomic.load(order)
96            }
97
98            #[cfg(not(feature = "atomic"))]
99            #[inline]
100            fn load_impl(&self, _order: Ordering) -> $unsync {
101                self.unsync.get()
102            }
103
104            /// Store a value in this container.
105            #[inline]
106            pub fn store(&self, val: $unsync, order: Ordering) {
107                self.store_impl(val, order);
108            }
109
110            #[cfg(feature = "atomic")]
111            #[inline]
112            fn store_impl(&self, val: $unsync, order: Ordering) {
113                self.atomic.store(val, order);
114            }
115
116            #[cfg(not(feature = "atomic"))]
117            #[inline]
118            fn store_impl(&self, val: $unsync, _order: Ordering) {
119                self.unsync.set(val);
120            }
121
122            /// Swap two values, returning the old value stored in this container.
123            #[inline]
124            pub fn swap(&self, val: $unsync, order: Ordering) -> $unsync {
125                self.swap_impl(val, order)
126            }
127
128            #[cfg(feature = "atomic")]
129            #[inline]
130            fn swap_impl(&self, val: $unsync, order: Ordering) -> $unsync {
131                self.atomic.swap(val, order)
132            }
133
134            #[cfg(not(feature = "atomic"))]
135            #[inline]
136            fn swap_impl(&self, val: $unsync, _order: Ordering) -> $unsync {
137                self.unsync.replace(val)
138            }
139        }
140    };
141}
142
143maybe_atomic_type! {MaybeAtomicBool: AtomicBool | bool}
144maybe_atomic_type! {MaybeAtomicU8: AtomicU8 | u8}
145maybe_atomic_type! {MaybeAtomicU16: AtomicU16 | u16}
146maybe_atomic_type! {MaybeAtomicU32: AtomicU32 | u32}
147maybe_atomic_type! {MaybeAtomicU64: AtomicU64 | u64}
148maybe_atomic_type! {MaybeAtomicUsize: AtomicUsize | usize}
149maybe_atomic_type! {MaybeAtomicI8: AtomicI8 | i8}
150maybe_atomic_type! {MaybeAtomicI16: AtomicI16 | i16}
151maybe_atomic_type! {MaybeAtomicI32: AtomicI32 | i32}
152maybe_atomic_type! {MaybeAtomicI64: AtomicI64 | i64}
153maybe_atomic_type! {MaybeAtomicIsize: AtomicIsize | isize}