atomiq/
atom.rs

1use core::fmt::Debug;
2use crate::prelude::*;
3use cfg_if::cfg_if;
4
5cfg_if!(
6    if #[cfg(feature = "loom")] {
7        use loom::sync::atomic as a;
8        pub use loom::sync::Arc;
9    } else {
10        use core::sync::atomic as a;
11        #[cfg(feature = "alloc")]
12        pub use alloc::sync::Arc;
13    }
14);
15pub use a::fence;
16
17/// A primitive atomizable value.
18pub trait Atom: Sized + Clone + Copy + Debug {
19    /// The provider of the atomic operations.
20    type Provider: From<Self> + Debug + Default;
21
22    #[doc(hidden)]
23    fn load(provider: &Self::Provider, ordering: Ordering) -> Self;
24    #[doc(hidden)]
25    fn store(provider: &Self::Provider, value: Self, ordering: Ordering);
26    #[doc(hidden)]
27    fn swap(provider: &Self::Provider, value: Self, ordering: Ordering) -> Self;
28    #[doc(hidden)]
29    fn compare_exchange(
30        provider: &Self::Provider,
31        current: Self,
32        new: Self,
33        success: Ordering,
34        failure: Ordering,
35    ) -> Result<Self, Self>;
36    #[doc(hidden)]
37    fn compare_exchange_weak(
38        provider: &Self::Provider,
39        current: Self,
40        new: Self,
41        success: Ordering,
42        failure: Ordering,
43    ) -> Result<Self, Self>;
44    #[doc(hidden)]
45    fn fetch_update<F>(
46        provider: &Self::Provider,
47        set_ordering: Ordering,
48        fetch_ordering: Ordering,
49        f: F,
50    ) -> Result<Self, Self>
51    where
52        F: FnMut(Self) -> Option<Self>;
53}
54
55/// A primitive atomizable bit value.
56pub trait BitAtom: Atom {
57    #[doc(hidden)]
58    fn fetch_and(provider: &Self::Provider, value: Self, ordering: Ordering) -> Self;
59    #[doc(hidden)]
60    fn fetch_nand(provider: &Self::Provider, value: Self, ordering: Ordering) -> Self;
61    // Loom does not support this yet, as it was only recently stabilized.
62    // https://github.com/tokio-rs/loom/issues/371
63    // fn fetch_not(provider: &Self::Provider, ordering: Ordering) -> Self;
64    #[doc(hidden)]
65    fn fetch_or(provider: &Self::Provider, value: Self, ordering: Ordering) -> Self;
66    #[doc(hidden)]
67    fn fetch_xor(provider: &Self::Provider, value: Self, ordering: Ordering) -> Self;
68}
69
70/// A primitive atomizable integer value.
71pub trait IntAtom: Atom {
72    #[doc(hidden)]
73    fn fetch_add(provider: &Self::Provider, value: Self, ordering: Ordering) -> Self;
74    #[doc(hidden)]
75    fn fetch_sub(provider: &Self::Provider, value: Self, ordering: Ordering) -> Self;
76    #[doc(hidden)]
77    fn fetch_min(provider: &Self::Provider, value: Self, ordering: Ordering) -> Self;
78    #[doc(hidden)]
79    fn fetch_max(provider: &Self::Provider, value: Self, ordering: Ordering) -> Self;
80}
81
82macro_rules! or_def {
83    ($value:tt or $default:tt) => {
84        $value
85    };
86    (or $default:tt) => {
87        $default
88    };
89}
90
91macro_rules! atom_impl {
92    ($atom:ty => $provider:ident $length:literal) => {
93        #[cfg(target_has_atomic = $length)]
94        use a::$provider;
95
96        #[cfg(target_has_atomic = $length)]
97        impl Atom for $atom {
98            type Provider = $provider;
99
100            fn load(provider: &$provider, ordering: Ordering) -> Self {
101                provider.load(ordering)
102            }
103
104            fn store(provider: &$provider, value: Self, ordering: Ordering) {
105                provider.store(value, ordering)
106            }
107
108            fn swap(provider: &$provider, value: Self, ordering: Ordering) -> Self {
109                provider.swap(value, ordering)
110            }
111
112            fn compare_exchange(provider: &$provider, current: Self, new: Self, success: Ordering, failure: Ordering) -> Result<Self, Self> {
113                provider.compare_exchange(current, new, success, failure)
114            }
115
116            fn compare_exchange_weak(provider: &$provider, current: Self, new: Self, success: Ordering, failure: Ordering) -> Result<Self, Self> {
117                provider.compare_exchange_weak(current, new, success, failure)
118            }
119
120            fn fetch_update<F>(
121                provider: &$provider,
122                set_ordering: Ordering,
123                fetch_ordering: Ordering,
124                mut f: F,
125            ) -> Result<Self, Self>
126            where
127                F: FnMut(Self) -> Option<Self>
128            {
129                provider.fetch_update(set_ordering, fetch_ordering, |value| f(value))
130            }
131        }
132    };
133    ($atom:ty => $provider:ident $length:literal bit) => {
134        atom_impl!($atom => $provider $length);
135
136        #[cfg(target_has_atomic = $length)]
137        impl BitAtom for $atom {
138            fn fetch_and(provider: &$provider, value: Self, ordering: Ordering) -> Self {
139                provider.fetch_and(value, ordering)
140            }
141
142            fn fetch_nand(provider: &$provider, value: Self, ordering: Ordering) -> Self {
143                provider.fetch_nand(value, ordering)
144            }
145
146            fn fetch_or(provider: &$provider, value: Self, ordering: Ordering) -> Self {
147                provider.fetch_or(value, ordering)
148            }
149
150            fn fetch_xor(provider: &$provider, value: Self, ordering: Ordering) -> Self {
151                provider.fetch_xor(value, ordering)
152            }
153        }
154    };
155    ($atom:ty => $provider:ident $length:literal int) => {
156        atom_impl!($atom => $provider $length bit);
157
158        #[cfg(target_has_atomic = $length)]
159        impl IntAtom for $atom {
160            fn fetch_add(provider: &$provider, value: Self, ordering: Ordering) -> Self {
161                provider.fetch_add(value, ordering)
162            }
163
164            fn fetch_sub(provider: &$provider, value: Self, ordering: Ordering) -> Self {
165                provider.fetch_sub(value, ordering)
166            }
167
168            fn fetch_min(provider: &$provider, value: Self, ordering: Ordering) -> Self {
169                provider.fetch_min(value, ordering)
170            }
171
172            fn fetch_max(provider: &$provider, value: Self, ordering: Ordering) -> Self {
173                provider.fetch_max(value, ordering)
174            }
175        }
176    };
177}
178
179macro_rules! atom_impls {
180    ($($atom:ty => $provider:ident $length:literal $($s:ident)?;)+) => {
181        $(
182            atom_impl!($atom => $provider $length $($s)?);
183        )+
184    };
185}
186
187atom_impls!(
188    bool => AtomicBool "8" bit;
189    u8 => AtomicU8 "8" int;
190    u16 => AtomicU16 "16" int;
191    u32 => AtomicU32 "32" int;
192    u64 => AtomicU64 "64" int;
193    // u128 => AtomicU128 "128" int;
194    usize => AtomicUsize "ptr" int;
195    i8 => AtomicI8 "8" int;
196    i16 => AtomicI16 "16" int;
197    i32 => AtomicI32 "32" int;
198    i64 => AtomicI64 "64" int;
199    // i128 => AtomicI128 "128" int;
200    isize => AtomicIsize "ptr" int;
201);