Skip to main content

relaxed_atomic/
lib.rs

1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#![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/// A wrapper around an atomic primitive providing relaxed memory ordering operations.
16#[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            /// Creates a new relaxed atomic initialized with `val`.
24            pub const fn new(val: $primitive_type) -> Self {
25                Self($atomic_type::new(val))
26            }
27
28            /// Loads the value with relaxed memory ordering.
29            #[inline]
30            pub fn load(&self) -> $primitive_type {
31                self.0.load(Ordering::Relaxed)
32            }
33
34            /// Stores a value with relaxed memory ordering.
35            #[inline]
36            pub fn store(&self, val: $primitive_type) {
37                self.0.store(val, Ordering::Relaxed);
38            }
39
40            /// Swaps a value with relaxed memory ordering.
41            #[inline]
42            pub fn swap(&self, val: $primitive_type) -> $primitive_type {
43                self.0.swap(val, Ordering::Relaxed)
44            }
45
46            /// Performs compare-and-exchange with relaxed memory ordering.
47            #[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            /// Performs weak compare-and-exchange with relaxed memory ordering.
57            #[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            /// Adds to the value with relaxed memory ordering.
80            #[inline]
81            pub fn fetch_add(&self, val: $primitive_type) -> $primitive_type {
82                self.0.fetch_add(val, Ordering::Relaxed)
83            }
84
85            /// Subtracts from the value with relaxed memory ordering.
86            #[inline]
87            pub fn fetch_sub(&self, val: $primitive_type) -> $primitive_type {
88                self.0.fetch_sub(val, Ordering::Relaxed)
89            }
90
91            /// Bitwise ANDs the value with relaxed memory ordering.
92            #[inline]
93            pub fn fetch_and(&self, val: $primitive_type) -> $primitive_type {
94                self.0.fetch_and(val, Ordering::Relaxed)
95            }
96
97            /// Bitwise NANDs the value with relaxed memory ordering.
98            #[inline]
99            pub fn fetch_nand(&self, val: $primitive_type) -> $primitive_type {
100                self.0.fetch_nand(val, Ordering::Relaxed)
101            }
102
103            /// Bitwise ORs the value with relaxed memory ordering.
104            #[inline]
105            pub fn fetch_or(&self, val: $primitive_type) -> $primitive_type {
106                self.0.fetch_or(val, Ordering::Relaxed)
107            }
108
109            /// Bitwise XORs the value with relaxed memory ordering.
110            #[inline]
111            pub fn fetch_xor(&self, val: $primitive_type) -> $primitive_type {
112                self.0.fetch_xor(val, Ordering::Relaxed)
113            }
114
115            /// Computes maximum with relaxed memory ordering.
116            #[inline]
117            pub fn fetch_max(&self, val: $primitive_type) -> $primitive_type {
118                self.0.fetch_max(val, Ordering::Relaxed)
119            }
120
121            /// Computes minimum with relaxed memory ordering.
122            #[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/// Relaxed atomic unit tests.
144#[unittest::suite(name = "relaxed_atomic_tests")]
145mod tests {
146    use super::{RelaxedAtomicBool, RelaxedAtomicI32, RelaxedAtomicU64};
147
148    /// Tests boolean relaxed atomic operations.
149    #[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    /// Tests numeric relaxed atomic operations.
160    #[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}