utils_atomics/trait.rs
1#[allow(unused_imports)]
2use core::sync::atomic::Ordering::{self, *};
3use docfg::docfg;
4
5#[allow(non_camel_case_types)]
6pub type Atomic_c_char = <core::ffi::c_char as HasAtomic>::Atomic;
7#[allow(non_camel_case_types)]
8pub type Atomic_c_schar = <core::ffi::c_schar as HasAtomic>::Atomic;
9#[allow(non_camel_case_types)]
10pub type Atomic_c_uchar = <core::ffi::c_uchar as HasAtomic>::Atomic;
11#[allow(non_camel_case_types)]
12pub type Atomic_c_short = <core::ffi::c_short as HasAtomic>::Atomic;
13#[allow(non_camel_case_types)]
14pub type Atomic_c_ushort = <core::ffi::c_ushort as HasAtomic>::Atomic;
15#[allow(non_camel_case_types)]
16pub type Atomic_c_int = <core::ffi::c_int as HasAtomic>::Atomic;
17#[allow(non_camel_case_types)]
18pub type Atomic_c_uint = <core::ffi::c_uint as HasAtomic>::Atomic;
19#[allow(non_camel_case_types)]
20pub type Atomic_c_long = <core::ffi::c_long as HasAtomic>::Atomic;
21#[allow(non_camel_case_types)]
22pub type Atomic_c_ulong = <core::ffi::c_ulong as HasAtomic>::Atomic;
23#[allow(non_camel_case_types)]
24pub type Atomic_c_longlong = <core::ffi::c_longlong as HasAtomic>::Atomic;
25#[allow(non_camel_case_types)]
26pub type Atomic_c_ulonglong = <core::ffi::c_ulonglong as HasAtomic>::Atomic;
27#[docfg(feature = "nightly")]
28#[allow(non_camel_case_types)]
29pub type Atomic_c_size_t = <core::ffi::c_size_t as HasAtomic>::Atomic;
30#[docfg(feature = "nightly")]
31#[allow(non_camel_case_types)]
32pub type Atomic_c_ssize_t = <core::ffi::c_ssize_t as HasAtomic>::Atomic;
33#[docfg(feature = "nightly")]
34#[allow(non_camel_case_types)]
35pub type Atomic_c_ptrdiff_t = <core::ffi::c_ptrdiff_t as HasAtomic>::Atomic;
36
37/// A trait representing types that have an associated atomic type.
38pub trait HasAtomic {
39 type Atomic: Atomic<Primitive = Self>;
40}
41
42#[allow(clippy::missing_errors_doc)]
43/// A trait representing atomic types.
44/// # Safety
45/// - `Self` must have the same size and alignment as [`Primitive`](`Atomic::Primitive`)
46pub unsafe trait Atomic: Send + Sync {
47 type Primitive: HasAtomic<Atomic = Self>;
48
49 /// Creates a new atomic integer.
50 fn new(v: Self::Primitive) -> Self;
51
52 /// Returns a mutable reference to the underlying integer.
53 ///
54 /// This is safe because the mutable reference guarantees that no other threads are
55 /// concurrently accessing the atomic data.
56 fn get_mut(&mut self) -> &mut Self::Primitive;
57 /// Consumes the atomic and returns the contained value.
58 ///
59 /// This is safe because passing `self` by value guarantees that no other threads are
60 /// concurrently accessing the atomic data.
61 fn into_inner(self) -> Self::Primitive;
62 /// Loads a value from the atomic integer.
63 ///
64 /// `load` takes an [`Ordering`] argument which describes the memory ordering of this operation.
65 /// Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
66 ///
67 /// # Panics
68 ///
69 /// Panics if `order` is [`Release`] or [`AcqRel`].
70 fn load(&self, order: Ordering) -> Self::Primitive;
71 /// Stores a value into the atomic integer.
72 ///
73 /// `store` takes an [`Ordering`] argument which describes the memory ordering of this operation.
74 /// Possible values are [`SeqCst`], [`Release`] and [`Relaxed`].
75 ///
76 /// # Panics
77 ///
78 /// Panics if `order` is [`Acquire`] or [`AcqRel`].
79 fn store(&self, val: Self::Primitive, order: Ordering);
80 /// Stores a value into the atomic integer, returning the previous value.
81 ///
82 /// `swap` takes an [`Ordering`] argument which describes the memory ordering
83 /// of this operation. All ordering modes are possible. Note that using
84 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
85 /// using [`Release`] makes the load part [`Relaxed`].
86 fn swap(&self, val: Self::Primitive, order: Ordering) -> Self::Primitive;
87
88 /// Stores a value into the atomic integer if the current value is the same as
89 /// the `current` value.
90 ///
91 /// The return value is a result indicating whether the new value was written and
92 /// containing the previous value. On success this value is guaranteed to be equal to
93 /// `current`.
94 ///
95 /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
96 /// ordering of this operation. `success` describes the required ordering for the
97 /// read-modify-write operation that takes place if the comparison with `current` succeeds.
98 /// `failure` describes the required ordering for the load operation that takes place when
99 /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
100 /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
101 /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
102 fn compare_exchange(
103 &self,
104 current: Self::Primitive,
105 new: Self::Primitive,
106 success: Ordering,
107 failure: Ordering,
108 ) -> Result<Self::Primitive, Self::Primitive>;
109
110 /// Stores a value into the atomic integer if the current value is the same as
111 /// the `current` value.
112 ///
113 /// Unlike [`compare_exchange`](Atomic::compare_exchange), this function is allowed to spuriously fail even
114 /// when the comparison succeeds, which can result in more efficient code on some
115 /// platforms. The return value is a result indicating whether the new value was
116 /// written and containing the previous value.
117 ///
118 /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
119 /// ordering of this operation. `success` describes the required ordering for the
120 /// read-modify-write operation that takes place if the comparison with `current` succeeds.
121 /// `failure` describes the required ordering for the load operation that takes place when
122 /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
123 /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
124 /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
125 fn compare_exchange_weak(
126 &self,
127 current: Self::Primitive,
128 new: Self::Primitive,
129 success: Ordering,
130 failure: Ordering,
131 ) -> Result<Self::Primitive, Self::Primitive>;
132
133 /// Fetches the value, and applies a function to it that returns an optional
134 /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
135 /// `Err(previous_value)`.
136 ///
137 /// Note: This may call the function multiple times if the value has been changed from other threads in
138 /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied
139 /// only once to the stored value.
140 ///
141 /// `fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
142 /// The first describes the required ordering for when the operation finally succeeds while the second
143 /// describes the required ordering for loads. These correspond to the success and failure orderings of
144 /// [`compare_exchange`](Atomic::compare_exchange) respectively.
145 ///
146 /// Using [`Acquire`] as success ordering makes the store part
147 /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
148 /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
149 ///
150 /// # Considerations
151 ///
152 /// This method is not magic; it is not provided by the hardware.
153 /// It is implemented in terms of [`compare_exchange_weak`](Atomic::compare_exchange_weak),
154 /// and suffers from the same drawbacks.
155 /// In particular, this method will not circumvent the [ABA Problem].
156 ///
157 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
158 fn fetch_update<F: FnMut(Self::Primitive) -> Option<Self::Primitive>>(
159 &self,
160 set_order: Ordering,
161 fetch_ordering: Ordering,
162 f: F,
163 ) -> Result<Self::Primitive, Self::Primitive>;
164}
165
166/// A trait representing atomic types that can be constructed in a "const" context.
167#[cfg_attr(docsrs, doc(cfg(feature = "const")))]
168#[cfg(feature = "const")]
169#[const_trait]
170pub trait AtomicConstNew: Atomic {
171 fn new(v: Self::Primitive) -> Self;
172}
173
174/// A trait representing atomic types that support addition operations.
175pub trait AtomicAdd<T = <Self as Atomic>::Primitive>: Atomic {
176 /// Adds to the current value, returning the previous value.
177 ///
178 /// This operation wraps around on overflow.
179 ///
180 /// `fetch_add` takes an [`Ordering`] argument which describes the memory ordering
181 /// of this operation. All ordering modes are possible. Note that using
182 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
183 /// using [`Release`] makes the load part [`Relaxed`].
184 fn fetch_add(&self, val: T, order: Ordering) -> Self::Primitive;
185}
186
187/// A trait representing atomic types that support subtraction operations.
188pub trait AtomicSub<T = <Self as Atomic>::Primitive>: Atomic {
189 /// Subtracts from the current value, returning the previous value.
190 ///
191 /// This operation wraps around on overflow.
192 ///
193 /// `fetch_sub` takes an [`Ordering`] argument which describes the memory ordering
194 /// of this operation. All ordering modes are possible. Note that using
195 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
196 /// using [`Release`] makes the load part [`Relaxed`].
197 fn fetch_sub(&self, val: T, order: Ordering) -> Self::Primitive;
198}
199
200/// A trait representing atomic types that support subtraction operations.
201pub trait AtomicBitAnd<T = <Self as Atomic>::Primitive>: Atomic {
202 /// Bitwise "and" with the current value.
203 ///
204 /// Performs a bitwise "and" operation on the current value and the argument `val`, and
205 /// sets the new value to the result.
206 ///
207 /// Returns the previous value.
208 ///
209 /// `fetch_and` takes an [`Ordering`] argument which describes the memory ordering
210 /// of this operation. All ordering modes are possible. Note that using
211 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
212 /// using [`Release`] makes the load part [`Relaxed`].
213 fn fetch_and(&self, val: T, order: Ordering) -> Self::Primitive;
214 /// Bitwise "nand" with the current value.
215 ///
216 /// Performs a bitwise "nand" operation on the current value and the argument `val`, and
217 /// sets the new value to the result.
218 ///
219 /// Returns the previous value.
220 ///
221 /// `fetch_nand` takes an [`Ordering`] argument which describes the memory ordering
222 /// of this operation. All ordering modes are possible. Note that using
223 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
224 /// using [`Release`] makes the load part [`Relaxed`].
225 fn fetch_nand(&self, val: T, order: Ordering) -> Self::Primitive;
226}
227
228/// A trait representing atomic types that support bitwise OR operations.
229pub trait AtomicBitOr<T = <Self as Atomic>::Primitive>: Atomic {
230 /// Bitwise "or" with the current value.
231 ///
232 /// Performs a bitwise "or" operation on the current value and the argument `val`, and
233 /// sets the new value to the result.
234 ///
235 /// Returns the previous value.
236 ///
237 /// `fetch_or` takes an [`Ordering`] argument which describes the memory ordering
238 /// of this operation. All ordering modes are possible. Note that using
239 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
240 /// using [`Release`] makes the load part [`Relaxed`].
241 fn fetch_or(&self, val: T, order: Ordering) -> Self::Primitive;
242}
243
244/// A trait representing atomic types that support bitwise XOR operations.
245pub trait AtomicBitXor<T = <Self as Atomic>::Primitive>: Atomic {
246 /// Bitwise "xor" with the current value.
247 ///
248 /// Performs a bitwise "xor" operation on the current value and the argument `val`, and
249 /// sets the new value to the result.
250 ///
251 /// Returns the previous value.
252 ///
253 /// `fetch_xor` takes an [`Ordering`] argument which describes the memory ordering
254 /// of this operation. All ordering modes are possible. Note that using
255 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
256 /// using [`Release`] makes the load part [`Relaxed`].
257 fn fetch_xor(&self, val: T, order: Ordering) -> Self::Primitive;
258}
259
260/// A trait representing atomic types that support minimum operations.
261pub trait AtomicMin<T = <Self as Atomic>::Primitive>: Atomic {
262 /// Minimum with the current value.
263 ///
264 /// Finds the minimum of the current value and the argument `val`, and
265 /// sets the new value to the result.
266 ///
267 /// Returns the previous value.
268 ///
269 /// `fetch_min` takes an [`Ordering`] argument which describes the memory ordering
270 /// of this operation. All ordering modes are possible. Note that using
271 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
272 /// using [`Release`] makes the load part [`Relaxed`].
273 fn fetch_min(&self, val: T, order: Ordering) -> Self::Primitive;
274}
275
276/// A trait representing atomic types that support maximum operations.
277pub trait AtomicMax<T = <Self as Atomic>::Primitive>: Atomic {
278 /// Maximum with the current value.
279 ///
280 /// Finds the maximum of the current value and the argument `val`, and
281 /// sets the new value to the result.
282 ///
283 /// Returns the previous value.
284 ///
285 /// `fetch_max` takes an [`Ordering`] argument which describes the memory ordering
286 /// of this operation. All ordering modes are possible. Note that using
287 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
288 /// using [`Release`] makes the load part [`Relaxed`].
289 fn fetch_max(&self, val: T, order: Ordering) -> Self::Primitive;
290}
291
292/* MARKER TRAITS */
293
294/// A marker trait representing types that have an associated atomic integer type.
295pub trait HasAtomicInt: HasAtomic {
296 type AtomicInt: AtomicInt<Primitive = Self>;
297}
298/// A marker trait representing atomic types that support numerical operations.
299pub trait AtomicNumOps<T = <Self as Atomic>::Primitive>:
300 Atomic + AtomicAdd<T> + AtomicSub<T>
301{
302}
303/// A marker trait representing atomic types that support bitwise operations.
304pub trait AtomicBitOps<T = <Self as Atomic>::Primitive>:
305 Atomic + AtomicBitAnd<T> + AtomicBitOr<T> + AtomicBitXor<T>
306{
307}
308/// A marker trait representing atomic types that support ordering operations.
309pub trait AtomicOrd<T = <Self as Atomic>::Primitive>: Atomic + AtomicMin<T> + AtomicMax<T> {}
310/// A marker trait representing atomic types that support numerical and ordering operations.
311pub trait AtomicNum: AtomicNumOps + AtomicOrd {}
312/// A marker trait representing atomic types that support numerical and ordering operations.
313pub trait AtomicInt: AtomicNum + AtomicBitOps {}
314
315impl<T: HasAtomic> HasAtomicInt for T
316where
317 T::Atomic: AtomicInt<Primitive = T>,
318{
319 type AtomicInt = <T as HasAtomic>::Atomic;
320}
321impl<T, U> AtomicNumOps<T> for U where U: Atomic + AtomicAdd<T> + AtomicSub<T> {}
322impl<T, U> AtomicBitOps<T> for U where U: Atomic + AtomicBitAnd<T> + AtomicBitOr<T> + AtomicBitXor<T>
323{}
324impl<T, U> AtomicOrd<T> for U where U: Atomic + AtomicMin<T> + AtomicMax<T> {}
325impl<T> AtomicNum for T where T: AtomicNumOps + AtomicOrd {}
326impl<T> AtomicInt for T where T: AtomicNum + AtomicBitOps {}
327
328// IMPLEMENTATION
329
330macro_rules! impl_atomic {
331 ($($len:literal: $prim:ty => $atomic:ty),+) => {
332 $(
333 #[docfg(target_has_atomic = $len)]
334 impl HasAtomic for $prim {
335 type Atomic = $atomic;
336 }
337
338 #[docfg(target_has_atomic = $len)]
339 unsafe impl Atomic for $atomic {
340 type Primitive = $prim;
341
342 #[inline]
343 fn new (v: Self::Primitive) -> Self {
344 <$atomic>::new(v)
345 }
346
347 #[inline]
348 fn get_mut (&mut self) -> &mut Self::Primitive {
349 <$atomic>::get_mut(self)
350 }
351
352 #[inline]
353 fn into_inner (self) -> Self::Primitive {
354 <$atomic>::into_inner(self)
355 }
356
357 #[inline]
358 fn load (&self, order: Ordering) -> Self::Primitive {
359 <$atomic>::load(self, order)
360 }
361
362 #[inline]
363 fn store (&self, val: Self::Primitive, order: Ordering) {
364 <$atomic>::store(self, val, order)
365 }
366
367 #[inline]
368 fn swap (&self, val: Self::Primitive, order: Ordering) -> Self::Primitive {
369 <$atomic>::swap(self, val, order)
370 }
371
372 #[inline]
373 fn compare_exchange (&self, current: Self::Primitive, new: Self::Primitive, success: Ordering, failure: Ordering) -> Result<Self::Primitive, Self::Primitive> {
374 <$atomic>::compare_exchange(self, current, new, success, failure)
375 }
376
377 #[inline]
378 fn compare_exchange_weak (&self, current: Self::Primitive, new: Self::Primitive, success: Ordering, failure: Ordering) -> Result<Self::Primitive, Self::Primitive> {
379 <$atomic>::compare_exchange_weak(self, current, new, success, failure)
380 }
381
382 #[inline]
383 fn fetch_update<F: FnMut(Self::Primitive) -> Option<Self::Primitive>> (&self, set_order: Ordering, fetch_ordering: Ordering, f: F) -> Result<Self::Primitive, Self::Primitive> {
384 <$atomic>::fetch_update(self, set_order, fetch_ordering, f)
385 }
386 }
387
388 cfg_if::cfg_if! {
389 if #[cfg(feature = "const")] {
390 #[cfg_attr(docsrs, doc(cfg(feature = "const")))]
391 impl const AtomicConstNew for $atomic {
392 #[inline]
393 fn new (v: Self::Primitive) -> Self {
394 <$atomic>::new(v)
395 }
396 }
397 }
398 }
399 )+
400 };
401}
402
403macro_rules! impl_int {
404 ($($len:literal: ($int:ty, $uint:ty) => ($iatomic:ty, $uatomic:ty)),+) => {
405 $(
406 impl_int!($len: $int => $iatomic);
407 impl_int!($len: $uint => $uatomic);
408 )+
409 };
410
411 ($($len:literal: $prim:ty => $atomic:ty),+) => {
412 $(
413 impl_atomic!($len: $prim => $atomic);
414
415 #[docfg(target_has_atomic = $len)]
416 impl AtomicAdd for $atomic {
417 #[inline]
418 fn fetch_add(&self, val: $prim, order: Ordering) -> $prim {
419 <$atomic>::fetch_add(self, val, order)
420 }
421 }
422
423 #[docfg(target_has_atomic = $len)]
424 impl AtomicSub for $atomic {
425 #[inline]
426 fn fetch_sub(&self, val: $prim, order: Ordering) -> $prim {
427 <$atomic>::fetch_sub(self, val, order)
428 }
429 }
430
431 #[docfg(target_has_atomic = $len)]
432 impl AtomicBitAnd for $atomic {
433 #[inline]
434 fn fetch_and(&self, val: $prim, order: Ordering) -> $prim {
435 <$atomic>::fetch_and(self, val, order)
436 }
437
438 #[inline]
439 fn fetch_nand(&self, val: $prim, order: Ordering) -> $prim {
440 <$atomic>::fetch_nand(self, val, order)
441 }
442 }
443
444 #[docfg(target_has_atomic = $len)]
445 impl AtomicBitOr for $atomic {
446 #[inline]
447 fn fetch_or(&self, val: $prim, order: Ordering) -> $prim {
448 <$atomic>::fetch_or(self, val, order)
449 }
450 }
451
452 #[docfg(target_has_atomic = $len)]
453 impl AtomicBitXor for $atomic {
454 #[inline]
455 fn fetch_xor(&self, val: $prim, order: Ordering) -> $prim {
456 <$atomic>::fetch_xor(self, val, order)
457 }
458 }
459
460 #[docfg(target_has_atomic = $len)]
461 impl AtomicMin for $atomic {
462 #[inline]
463 fn fetch_min(&self, val: $prim, order: Ordering) -> $prim {
464 <$atomic>::fetch_min(self, val, order)
465 }
466 }
467
468 #[docfg(target_has_atomic = $len)]
469 impl AtomicMax for $atomic {
470 #[inline]
471 fn fetch_max(&self, val: $prim, order: Ordering) -> $prim {
472 <$atomic>::fetch_max(self, val, order)
473 }
474 }
475 )+
476 };
477}
478
479impl_int! {
480 "8": (u8, i8) => (core::sync::atomic::AtomicU8, core::sync::atomic::AtomicI8),
481 "16": (u16, i16) => (core::sync::atomic::AtomicU16, core::sync::atomic::AtomicI16),
482 "32": (u32, i32) => (core::sync::atomic::AtomicU32, core::sync::atomic::AtomicI32),
483 "64": (u64, i64) => (core::sync::atomic::AtomicU64, core::sync::atomic::AtomicI64),
484 "ptr": (usize, isize) => (core::sync::atomic::AtomicUsize, core::sync::atomic::AtomicIsize)
485 //"128": (u128, i128) => (core::sync::atomic::AtomicU128, core::sync::atomic::AtomicI128)
486}
487
488impl_atomic! {
489 "8": bool => core::sync::atomic::AtomicBool
490}
491
492#[docfg(target_has_atomic = "ptr")]
493impl<T> HasAtomic for *mut T {
494 type Atomic = core::sync::atomic::AtomicPtr<T>;
495}
496
497#[docfg(target_has_atomic = "ptr")]
498unsafe impl<T> Atomic for core::sync::atomic::AtomicPtr<T> {
499 type Primitive = *mut T;
500
501 #[inline]
502 fn new(v: Self::Primitive) -> Self {
503 core::sync::atomic::AtomicPtr::new(v)
504 }
505
506 #[inline]
507 fn get_mut(&mut self) -> &mut Self::Primitive {
508 core::sync::atomic::AtomicPtr::get_mut(self)
509 }
510
511 #[inline]
512 fn into_inner(self) -> Self::Primitive {
513 core::sync::atomic::AtomicPtr::into_inner(self)
514 }
515
516 #[inline]
517 fn load(&self, order: Ordering) -> Self::Primitive {
518 core::sync::atomic::AtomicPtr::load(self, order)
519 }
520
521 #[inline]
522 fn store(&self, val: Self::Primitive, order: Ordering) {
523 core::sync::atomic::AtomicPtr::store(self, val, order)
524 }
525
526 #[inline]
527 fn swap(&self, val: Self::Primitive, order: Ordering) -> Self::Primitive {
528 core::sync::atomic::AtomicPtr::swap(self, val, order)
529 }
530
531 #[inline]
532 fn compare_exchange(
533 &self,
534 current: Self::Primitive,
535 new: Self::Primitive,
536 success: Ordering,
537 failure: Ordering,
538 ) -> Result<Self::Primitive, Self::Primitive> {
539 core::sync::atomic::AtomicPtr::compare_exchange(self, current, new, success, failure)
540 }
541
542 #[inline]
543 fn compare_exchange_weak(
544 &self,
545 current: Self::Primitive,
546 new: Self::Primitive,
547 success: Ordering,
548 failure: Ordering,
549 ) -> Result<Self::Primitive, Self::Primitive> {
550 core::sync::atomic::AtomicPtr::compare_exchange_weak(self, current, new, success, failure)
551 }
552
553 #[inline]
554 fn fetch_update<F: FnMut(Self::Primitive) -> Option<Self::Primitive>>(
555 &self,
556 set_order: Ordering,
557 fetch_ordering: Ordering,
558 f: F,
559 ) -> Result<Self::Primitive, Self::Primitive> {
560 core::sync::atomic::AtomicPtr::fetch_update(self, set_order, fetch_ordering, f)
561 }
562}