1use std::sync::atomic::*;
37
38use num_traits::{FromPrimitive, ToPrimitive};
39
40pub use atomic_enum::AtomicEnum;
41pub use atomic_option::AtomicOption;
42
43mod atomic_enum;
44mod atomic_option;
45
46pub trait AtomicValue {
48 type Inner;
49
50 fn get(&self) -> Self::Inner;
51 fn set(&self, value: Self::Inner);
52}
53
54macro_rules! std_atomic_impl {
55 ($x: path, $inner: ident) => {
56 impl AtomicValue for $x {
57 type Inner = $inner;
58
59 #[inline]
60 fn get(&self) -> Self::Inner {
61 self.load(Ordering::Relaxed)
62 }
63
64 #[inline]
65 fn set(&self, value: Self::Inner) {
66 self.store(value, Ordering::Relaxed)
67 }
68 }
69 };
70}
71
72std_atomic_impl!(AtomicU8, u8);
73std_atomic_impl!(AtomicU16, u16);
74std_atomic_impl!(AtomicU32, u32);
75std_atomic_impl!(AtomicU64, u64);
76std_atomic_impl!(AtomicUsize, usize);
77std_atomic_impl!(AtomicI8, i8);
78std_atomic_impl!(AtomicI16, i16);
79std_atomic_impl!(AtomicI32, i32);
80std_atomic_impl!(AtomicI64, i64);
81std_atomic_impl!(AtomicBool, bool);
82
83pub trait AtomicFloatRepresentable: Sized {
84 type AtomicType: AtomicValue<Inner = Self> + From<Self>;
85}
86
87macro_rules! atomic_float {
88 ($name: ident, $backing: ident, $inner: ident) => {
89 #[cfg_attr(
93 not(target_arch = "wasm32"),
94 derive(serde_derive::Serialize, serde_derive::Deserialize)
95 )]
96 pub struct $name {
97 atomic: $backing,
98 }
99
100 impl $name {
101 #[inline]
103 pub fn new(value: $inner) -> Self {
104 Self {
105 atomic: $backing::new(value.to_bits()),
106 }
107 }
108
109 #[inline]
111 pub fn get(&self) -> $inner {
112 $inner::from_bits(self.atomic.load(Ordering::Relaxed))
113 }
114
115 #[inline]
117 pub fn set(&self, value: $inner) {
118 self.atomic.store(value.to_bits(), Ordering::Relaxed)
119 }
120
121 #[inline]
123 pub fn load(&self, ordering: Ordering) -> $inner {
124 $inner::from_bits(self.atomic.load(ordering))
125 }
126
127 #[inline]
129 pub fn store(&self, value: $inner, ordering: Ordering) {
130 self.atomic.store(value.to_bits(), ordering)
131 }
132 }
133
134 impl Default for $name {
135 #[inline]
136 fn default() -> Self {
137 Self::new(0.0)
138 }
139 }
140
141 impl std::fmt::Debug for $name {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 std::fmt::Debug::fmt(&self.get(), f)
144 }
145 }
146
147 impl std::fmt::Display for $name {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 std::fmt::Display::fmt(&self.get(), f)
150 }
151 }
152
153 impl PartialEq for $name {
154 fn eq(&self, rhs: &Self) -> bool {
155 self.get() == rhs.get()
156 }
157 }
158
159 impl Clone for $name {
160 #[inline]
161 fn clone(&self) -> Self {
162 $name::from(self.get())
163 }
164 }
165
166 impl From<$inner> for $name {
167 #[inline]
168 fn from(value: $inner) -> Self {
169 $name::new(value)
170 }
171 }
172
173 impl From<$name> for $inner {
174 #[inline]
175 fn from(value: $name) -> Self {
176 value.get()
177 }
178 }
179
180 impl AtomicValue for $name {
181 type Inner = $inner;
182
183 #[inline]
184 fn get(&self) -> Self::Inner {
185 $name::get(self)
186 }
187
188 #[inline]
189 fn set(&self, value: Self::Inner) {
190 $name::set(self, value)
191 }
192 }
193
194 impl AtomicFloatRepresentable for $inner {
195 type AtomicType = $name;
196 }
197 };
198}
199
200atomic_float!(AtomicF32, AtomicU32, f32);
201atomic_float!(AtomicF64, AtomicU64, f64);
202
203impl<T: ToPrimitive + FromPrimitive> AtomicValue for AtomicEnum<T> {
204 type Inner = T;
205
206 #[inline]
207 fn get(&self) -> Self::Inner {
208 Self::get(self)
209 }
210
211 #[inline]
212 fn set(&self, value: Self::Inner) {
213 Self::set(self, value)
214 }
215}
216
217#[cfg(test)]
218mod test {
219 use super::*;
220
221 #[test]
222 fn test_f32_doesnt_lose_precision() {
223 let value = 9.977_324_5_f32;
224 let a_value = AtomicF32::new(value);
225 assert!((a_value.get() - value) < f32::EPSILON);
226 }
227}