1#![no_std]
8
9use core::sync::atomic::{
10 AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicU8, AtomicU16,
11 AtomicU32, AtomicU64, AtomicUsize, Ordering,
12};
13use paste::paste;
14
15#[repr(transparent)]
17#[derive(Debug, Default)]
18pub struct RelaxedAtomic<T>(T);
19
20macro_rules! impl_relaxed_atomic {
21 ($atomic_type:ident, $primitive_type:ident) => {
22 impl $crate::RelaxedAtomic<$atomic_type> {
23 pub const fn new(val: $primitive_type) -> Self {
25 Self($atomic_type::new(val))
26 }
27
28 #[inline]
30 pub fn load(&self) -> $primitive_type {
31 self.0.load(Ordering::Relaxed)
32 }
33
34 #[inline]
36 pub fn store(&self, val: $primitive_type) {
37 self.0.store(val, Ordering::Relaxed);
38 }
39
40 #[inline]
42 pub fn swap(&self, val: $primitive_type) -> $primitive_type {
43 self.0.swap(val, Ordering::Relaxed)
44 }
45
46 #[inline]
48 pub fn compare_exchange(
49 &self,
50 current: $primitive_type,
51 new: $primitive_type,
52 ) -> Result<$primitive_type, $primitive_type> {
53 self.0.compare_exchange(current, new, Ordering::Relaxed, Ordering::Relaxed)
54 }
55
56 #[inline]
58 pub fn compare_exchange_weak(
59 &self,
60 current: $primitive_type,
61 new: $primitive_type,
62 ) -> Result<$primitive_type, $primitive_type> {
63 self.0.compare_exchange_weak(current, new, Ordering::Relaxed, Ordering::Relaxed)
64 }
65 }
66
67 paste! {
68 #[doc = concat!("Alias for `RelaxedAtomic<", stringify!($atomic_type), ">`.")]
69 pub type [<Relaxed $atomic_type>] = $crate::RelaxedAtomic<$atomic_type>;
70 }
71 };
72}
73
74macro_rules! impl_relaxed_atomic_numeric {
75 ($atomic_type:ident, $primitive_type:ident) => {
76 impl_relaxed_atomic!($atomic_type, $primitive_type);
77
78 impl $crate::RelaxedAtomic<$atomic_type> {
79 #[inline]
81 pub fn fetch_add(&self, val: $primitive_type) -> $primitive_type {
82 self.0.fetch_add(val, Ordering::Relaxed)
83 }
84
85 #[inline]
87 pub fn fetch_sub(&self, val: $primitive_type) -> $primitive_type {
88 self.0.fetch_sub(val, Ordering::Relaxed)
89 }
90
91 #[inline]
93 pub fn fetch_and(&self, val: $primitive_type) -> $primitive_type {
94 self.0.fetch_and(val, Ordering::Relaxed)
95 }
96
97 #[inline]
99 pub fn fetch_nand(&self, val: $primitive_type) -> $primitive_type {
100 self.0.fetch_nand(val, Ordering::Relaxed)
101 }
102
103 #[inline]
105 pub fn fetch_or(&self, val: $primitive_type) -> $primitive_type {
106 self.0.fetch_or(val, Ordering::Relaxed)
107 }
108
109 #[inline]
111 pub fn fetch_xor(&self, val: $primitive_type) -> $primitive_type {
112 self.0.fetch_xor(val, Ordering::Relaxed)
113 }
114
115 #[inline]
117 pub fn fetch_max(&self, val: $primitive_type) -> $primitive_type {
118 self.0.fetch_max(val, Ordering::Relaxed)
119 }
120
121 #[inline]
123 pub fn fetch_min(&self, val: $primitive_type) -> $primitive_type {
124 self.0.fetch_min(val, Ordering::Relaxed)
125 }
126 }
127 };
128}
129
130impl_relaxed_atomic!(AtomicBool, bool);
131impl_relaxed_atomic_numeric!(AtomicI8, i8);
132impl_relaxed_atomic_numeric!(AtomicI16, i16);
133impl_relaxed_atomic_numeric!(AtomicI32, i32);
134impl_relaxed_atomic_numeric!(AtomicI64, i64);
135impl_relaxed_atomic_numeric!(AtomicIsize, isize);
136impl_relaxed_atomic_numeric!(AtomicU8, u8);
137impl_relaxed_atomic_numeric!(AtomicU16, u16);
138impl_relaxed_atomic_numeric!(AtomicU32, u32);
139impl_relaxed_atomic_numeric!(AtomicU64, u64);
140impl_relaxed_atomic_numeric!(AtomicUsize, usize);
141
142#[cfg(ktest)]
143#[unittest::suite(name = "relaxed_atomic_tests")]
145mod tests {
146 use super::{RelaxedAtomicBool, RelaxedAtomicI32, RelaxedAtomicU64};
147
148 #[test]
150 fn test_relaxed_atomic_bool() {
151 let val = RelaxedAtomicBool::new(false);
152 unittest::expect_false!(val.load());
153 val.store(true);
154 unittest::expect_true!(val.load());
155 unittest::expect_true!(val.swap(false));
156 unittest::expect_false!(val.load());
157 }
158
159 #[test]
161 fn test_relaxed_atomic_numeric_ops() {
162 let val = RelaxedAtomicI32::new(10);
163 unittest::expect_eq!(val.load(), 10);
164 unittest::expect_eq!(val.fetch_add(5), 10);
165 unittest::expect_eq!(val.load(), 15);
166 unittest::expect_eq!(val.fetch_sub(3), 15);
167 unittest::expect_eq!(val.load(), 12);
168
169 let uval = RelaxedAtomicU64::new(100);
170 unittest::expect_true!(uval.compare_exchange(100, 200) == Ok(100));
171 unittest::expect_eq!(uval.load(), 200);
172 }
173}