portable_atomic/lib.rs
1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3/*!
4<!-- Note: Document from sync-markdown-to-rustdoc:start through sync-markdown-to-rustdoc:end
5 is synchronized from README.md. Any changes to that range are not preserved. -->
6<!-- tidy:sync-markdown-to-rustdoc:start -->
7
8Portable atomic types including support for 128-bit atomics, atomic float, etc.
9
10- Provide all atomic integer types (`Atomic{I,U}{8,16,32,64}`) for all targets that can use atomic CAS. (i.e., all targets that can use `std`, and most no-std targets)
11- Provide `AtomicI128` and `AtomicU128`.
12- Provide `AtomicF32` and `AtomicF64`. ([optional, requires the `float` feature](#optional-features-float))
13- Provide `AtomicF16` and `AtomicF128` for [unstable `f16` and `f128`](https://github.com/rust-lang/rust/issues/116909). ([optional, requires the `float` feature and unstable cfgs](#optional-features-float))
14- Provide atomic load/store for targets where atomic is not available at all in the standard library. (RISC-V without A-extension, MSP430, AVR)
15- Provide atomic CAS for targets where atomic CAS is not available in the standard library. (thumbv6m, pre-v6 Arm, RISC-V without A-extension, MSP430, AVR, Xtensa, etc.) (always enabled for MSP430 and AVR, [optional](#optional-features-critical-section) otherwise)
16- Make features that require newer compilers, such as [`fetch_{max,min}`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_max), [`fetch_update`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_update), [`as_ptr`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.as_ptr), [`from_ptr`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.from_ptr), [`AtomicBool::fetch_not`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicBool.html#method.fetch_not), [`AtomicPtr::fetch_*`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html#method.fetch_and), and [stronger CAS failure ordering](https://github.com/rust-lang/rust/pull/98383) available on Rust 1.34+.
17- Provide workaround for bugs in the standard library's atomic-related APIs, such as [rust-lang/rust#100650], `fence`/`compiler_fence` on MSP430 that cause LLVM error, etc.
18
19<!-- TODO:
20- mention Atomic{I,U}*::fetch_neg, Atomic{I*,U*,Ptr}::bit_*, etc.
21- mention optimizations not available in the standard library's equivalents
22-->
23
24portable-atomic version of `std::sync::Arc` and `std::task::Wake` is provided by the [portable-atomic-util] crate.
25
26## Usage
27
28Add this to your `Cargo.toml`:
29
30```toml
31[dependencies]
32portable-atomic = "1"
33```
34
35The default features are mainly for users who use atomics larger than the pointer width.
36If you don't need them, disabling the default features may reduce code size and compile time slightly.
37
38```toml
39[dependencies]
40portable-atomic = { version = "1", default-features = false }
41```
42
43If your crate supports no-std environment and requires atomic CAS, enabling the `require-cas` feature will allow the portable-atomic to display a [helpful error message](https://github.com/taiki-e/portable-atomic/pull/100) to users on targets requiring additional action on the user side to provide atomic CAS.
44
45```toml
46[dependencies]
47portable-atomic = { version = "1.3", default-features = false, features = ["require-cas"] }
48```
49
50(Since 1.8, portable-atomic can display a [helpful error message](https://github.com/taiki-e/portable-atomic/pull/181) even without the `require-cas` feature when the rustc version is 1.78+. However, the `require-cas` feature also allows rejecting builds at an earlier stage, we recommend enabling it unless enabling it causes [problems](https://github.com/matklad/once_cell/pull/267).)
51
52## 128-bit atomics support
53
54Native 128-bit atomic operations are available on x86_64 (Rust 1.59+), AArch64 (Rust 1.59+), riscv64 (Rust 1.59+), Arm64EC (Rust 1.84+), s390x (Rust 1.84+), and powerpc64 (Rust 1.95+), otherwise the fallback implementation is used.
55
56On x86_64, even if `cmpxchg16b` is not available at compile-time (Note: `cmpxchg16b` target feature is enabled by default only on Apple, Windows (except Windows 7), and Fuchsia targets), run-time detection checks whether `cmpxchg16b` is available. If `cmpxchg16b` is not available at either compile-time or run-time detection, the fallback implementation is used. See also [`portable_atomic_no_outline_atomics`](#optional-cfg-no-outline-atomics) cfg.
57
58They are usually implemented using inline assembly, and when using Miri or ThreadSanitizer that do not support inline assembly, core intrinsics are used instead of inline assembly if possible.
59
60See the [`atomic128` module's readme](https://github.com/taiki-e/portable-atomic/blob/HEAD/src/imp/atomic128/README.md) for details.
61
62## <a name="optional-features"></a><a name="optional-cfg"></a>Optional features/cfgs
63
64portable-atomic provides features and cfgs to allow enabling specific APIs and customizing its behavior.
65
66Some options have both a feature and a cfg. When both exist, it indicates that the feature does not follow Cargo's recommendation that [features should be additive](https://doc.rust-lang.org/nightly/cargo/reference/features.html#feature-unification). Therefore, the maintainer's recommendation is to use cfg instead of feature. However, in the embedded ecosystem, it is very common to use features in such places, so these options provide both so you can choose based on your preference.
67
68<details>
69<summary>How to enable cfg (click to show)</summary>
70
71One of the ways to enable cfg is to set [rustflags in the cargo config](https://doc.rust-lang.org/cargo/reference/config.html#targettriplerustflags):
72
73```toml
74# .cargo/config.toml
75[target.<target>]
76rustflags = ["--cfg", "portable_atomic_unsafe_assume_single_core"]
77```
78
79Or set environment variable:
80
81```sh
82RUSTFLAGS="--cfg portable_atomic_unsafe_assume_single_core" cargo ...
83```
84
85</details>
86
87- <a name="optional-features-fallback"></a>**`fallback` feature** *(enabled by default)*<br>
88 Enable fallback implementations.
89
90 This enables atomic types with larger than the width supported by atomic instructions available on the current target. If the current target [supports 128-bit atomics](#128-bit-atomics-support), this is no-op.
91
92 This uses fallback implementation that using global locks by default. The following features/cfgs change this behavior:
93 - [`unsafe-assume-single-core` feature / `portable_atomic_unsafe_assume_single_core` cfg](#optional-features-unsafe-assume-single-core): Use fallback implementations that disabling interrupts instead of using global locks.
94 - If your target is single-core and calling interrupt disable instructions is safe, this is a safer and more efficient option.
95 - [`unsafe-assume-privileged` feature / `portable_atomic_unsafe_assume_privileged` cfg](#optional-features-unsafe-assume-privileged): Use fallback implementations that using global locks with disabling interrupts.
96 - If your target is multi-core and calling interrupt disable instructions is safe, this is a safer option.
97
98- <a name="optional-features-float"></a>**`float` feature**<br>
99 Provide `AtomicF{32,64}`.
100
101 If you want atomic types for unstable float types ([`f16` and `f128`](https://github.com/rust-lang/rust/issues/116909)), enable unstable cfg (`portable_atomic_unstable_f16` cfg for `AtomicF16`, `portable_atomic_unstable_f128` cfg for `AtomicF128`, [there is no possibility that both feature and cfg will be provided for unstable options.](https://github.com/taiki-e/portable-atomic/pull/200#issuecomment-2682252991)).
102
103<div class="rustdoc-alert rustdoc-alert-note">
104
105> **ⓘ Note**
106>
107> - Atomic float's `fetch_{add,sub,min,max}` are usually implemented using CAS loops, which can be slower than equivalent operations of atomic integers. As an exception, AArch64 with FEAT_LSFE and GPU targets have atomic float instructions and we use them on AArch64 when `lsfe` target feature is available at compile-time. We [plan to use atomic float instructions for GPU targets as well in the future.](https://github.com/taiki-e/portable-atomic/issues/34)
108> - Unstable cfgs are outside of the normal semver guarantees and minor or patch versions of portable-atomic may make breaking changes to them at any time.
109
110</div>
111
112- <a name="optional-features-std"></a>**`std` feature**<br>
113 Use `std`.
114
115- <a name="optional-features-require-cas"></a>**`require-cas` feature**<br>
116 Emit compile error if atomic CAS is not available. See [Usage](#usage) section for usage of this feature.
117
118- <a name="optional-features-serde"></a>**`serde` feature**<br>
119 Implement `serde::{Serialize,Deserialize}` for atomic types.
120
121 Note:
122 - The MSRV when this feature is enabled depends on the MSRV of [serde].
123
124- <a name="optional-features-critical-section"></a>**`critical-section` feature**<br>
125 Use [critical-section] to provide atomic CAS for targets where atomic CAS is not available in the standard library.
126
127 `critical-section` support is useful to get atomic CAS when the [`unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)](#optional-features-unsafe-assume-single-core) can't be used,
128 such as multi-core targets, unprivileged code running under some RTOS, or environments where disabling interrupts
129 needs extra care due to e.g. real-time requirements.
130
131<div class="rustdoc-alert rustdoc-alert-note">
132
133> **ⓘ Note**
134>
135> - When enabling this feature, you should provide a suitable critical section implementation for the current target, see the [critical-section] documentation for details on how to do so.
136> - With this feature, critical sections are taken for all atomic operations, while with `unsafe-assume-single-core` feature [some operations](https://github.com/taiki-e/portable-atomic/blob/HEAD/src/imp/interrupt/README.md#no-disable-interrupts) don't require disabling interrupts. Therefore, for better performance, if all the `critical-section` implementation for your target does is disable interrupts, prefer using `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg) instead.
137> - It is usually **discouraged** to always enable this feature in libraries that depend on `portable-atomic`.
138>
139> Enabling this feature will prevent the end user from having the chance to take advantage of other (potentially) efficient implementations (implementations provided by `unsafe-assume-single-core` feature mentioned above, implementation proposed in [#60], etc.). Also, targets that are currently unsupported may be supported in the future.
140>
141> The recommended approach for libraries is to leave it up to the end user whether or not to enable this feature. (However, it may make sense to enable this feature by default for libraries specific to a platform where other implementations are known not to work.)
142>
143> See also [this comment](https://github.com/matklad/once_cell/issues/264#issuecomment-2352654806).
144>
145> As an example, the end-user's `Cargo.toml` that uses a crate that provides a critical-section implementation and a crate that depends on portable-atomic as an option would be expected to look like this:
146>
147> ```toml
148> [dependencies]
149> portable-atomic = { version = "1", default-features = false, features = ["critical-section"] }
150> crate-provides-critical-section-impl = "..."
151> crate-uses-portable-atomic-as-feature = { version = "...", features = ["portable-atomic"] }
152> ```
153>
154> - Enabling both this feature and `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg) will result in a compile error.
155> - Enabling both this feature and `unsafe-assume-privileged` feature (or `portable_atomic_unsafe_assume_privileged` cfg) will result in a compile error.
156> - The MSRV when this feature is enabled depends on the MSRV of [critical-section].
157
158</div>
159
160- <a name="optional-features-unsafe-assume-single-core"></a><a name="optional-cfg-unsafe-assume-single-core"></a>**`unsafe-assume-single-core` feature / `portable_atomic_unsafe_assume_single_core` cfg**<br>
161 Assume that the target is single-core and privileged instructions required to disable interrupts are available.
162
163 - When this feature/cfg is enabled, this crate provides atomic CAS for targets where atomic CAS is not available in the standard library by disabling interrupts.
164 - When both this feature/cfg and enabled-by-default `fallback` feature is enabled, this crate provides atomic types with larger than the width supported by native instructions by disabling interrupts.
165
166<div class="rustdoc-alert rustdoc-alert-warning">
167
168> **⚠ Warning**
169>
170> This feature/cfg is `unsafe`, and note the following safety requirements:
171> - Enabling this feature/cfg for multi-core systems is always **unsound**.
172>
173> - This uses privileged instructions to disable interrupts, so it usually doesn't work on unprivileged mode.
174>
175> Enabling this feature/cfg in an environment where privileged instructions are not available, or if the instructions used are not sufficient to disable interrupts in the system, it is also usually considered **unsound**, although the details are system-dependent.
176>
177> The following are known cases:
178> - On Arm (except for M-Profile architectures), this disables only IRQs by default. For many systems (e.g., GBA) this is enough. If the system need to disable both IRQs and FIQs, you need to enable the `disable-fiq` feature (or `portable_atomic_disable_fiq` cfg) together.
179> - On RISC-V, this generates code for machine-mode (M-mode) by default. If you enable the `s-mode` feature (or `portable_atomic_s_mode` cfg) together, this generates code for supervisor-mode (S-mode). In particular, `qemu-system-riscv*` uses [OpenSBI](https://github.com/riscv-software-src/opensbi) as the default firmware.
180
181</div>
182
183Consider using the [`unsafe-assume-privileged` feature (or `portable_atomic_unsafe_assume_privileged` cfg)](#optional-features-unsafe-assume-privileged) for multi-core systems with atomic CAS.
184
185Consider using the [`critical-section` feature](#optional-features-critical-section) for systems that cannot use this feature/cfg.
186
187See also the [`interrupt` module's readme](https://github.com/taiki-e/portable-atomic/blob/HEAD/src/imp/interrupt/README.md).
188
189<div class="rustdoc-alert rustdoc-alert-note">
190
191> **ⓘ Note**
192>
193> - It is **very strongly discouraged** to enable this feature/cfg in libraries that depend on `portable-atomic`.
194>
195> The recommended approach for libraries is to leave it up to the end user whether or not to enable this feature/cfg. (However, it may make sense to enable this feature/cfg by default for libraries specific to a platform where it is guaranteed to always be sound, for example in a hardware abstraction layer targeting a single-core chip.)
196> - Enabling this feature/cfg for unsupported architectures will result in a compile error.
197> - Arm, RISC-V, and Xtensa are currently supported. (Since all MSP430 and AVR are single-core, we always provide atomic CAS for them without this feature/cfg.)
198> - Feel free to [submit an issue](https://github.com/taiki-e/portable-atomic/issues/new) if your target is not supported yet.
199> - Enabling this feature/cfg for targets where privileged instructions are obviously unavailable (e.g., Linux) will result in a compile error.
200> - Feel free to [submit an issue](https://github.com/taiki-e/portable-atomic/issues/new) if your target supports privileged instructions but the build rejected.
201> - Enabling both this feature/cfg and `critical-section` feature will result in a compile error.
202> - When both this feature/cfg and `unsafe-assume-privileged` feature (or `portable_atomic_unsafe_assume_privileged` cfg) are enabled, this feature/cfg is preferred.
203
204</div>
205
206- <a name="optional-features-unsafe-assume-privileged"></a><a name="optional-cfg-unsafe-assume-privileged"></a>**`unsafe-assume-privileged` feature / `portable_atomic_unsafe_assume_privileged` cfg**<br>
207 Similar to `unsafe-assume-single-core` feature / `portable_atomic_unsafe_assume_single_core` cfg, but only assumes about availability of privileged instructions required to disable interrupts.
208
209 - When both this feature/cfg and enabled-by-default `fallback` feature is enabled, this crate provides atomic types with larger than the width supported by native instructions by using global locks with disabling interrupts.
210
211<div class="rustdoc-alert rustdoc-alert-warning">
212
213> **⚠ Warning**
214>
215> This feature/cfg is `unsafe`, and except for being sound in multi-core systems, this has the same safety requirements as [`unsafe-assume-single-core` feature / `portable_atomic_unsafe_assume_single_core` cfg](#optional-features-unsafe-assume-single-core).
216
217</div>
218
219<div class="rustdoc-alert rustdoc-alert-note">
220
221> **ⓘ Note**
222>
223> - It is **very strongly discouraged** to enable this feature/cfg in libraries that depend on `portable-atomic`.
224>
225> The recommended approach for libraries is to leave it up to the end user whether or not to enable this feature/cfg. (However, it may make sense to enable this feature/cfg by default for libraries specific to a platform where it is guaranteed to always be sound, for example in a hardware abstraction layer.)
226> - Enabling this feature/cfg for unsupported targets will result in a compile error.
227> - This requires atomic CAS (`cfg(target_has_atomic = "ptr")` or `cfg_no_atomic_cas!`).
228> - Arm, RISC-V, and Xtensa are currently supported.
229> - Feel free to [submit an issue](https://github.com/taiki-e/portable-atomic/issues/new) if your target is not supported yet.
230> - Enabling this feature/cfg for targets where privileged instructions are obviously unavailable (e.g., Linux) will result in a compile error.
231> - Feel free to [submit an issue](https://github.com/taiki-e/portable-atomic/issues/new) if your target supports privileged instructions but the build rejected.
232> - Enabling both this feature/cfg and `critical-section` feature will result in a compile error.
233> - When both this feature/cfg and `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg) are enabled, `unsafe-assume-single-core` is preferred.
234
235</div>
236
237- <a name="optional-cfg-no-outline-atomics"></a>**`portable_atomic_no_outline_atomics` cfg**<br>
238 Disable dynamic dispatching by run-time CPU feature detection.
239
240 Dynamic dispatching by run-time CPU feature detection allows maintaining support for older CPUs while using features that are not supported on older CPUs, such as CMPXCHG16B (x86_64) and FEAT_LSE/FEAT_LSE2 (AArch64).
241
242 See also the [`atomic128` module's readme](https://github.com/taiki-e/portable-atomic/blob/HEAD/src/imp/atomic128/README.md).
243
244<div class="rustdoc-alert rustdoc-alert-note">
245
246> **ⓘ Note**
247>
248> - If the required target features are enabled at compile-time, dynamic dispatching is automatically disabled and the atomic operations are inlined.
249> - This is compatible with no-std (as with all features except `std`).
250> - On some targets, run-time detection is disabled by default mainly for compatibility with incomplete build environments or support for it is experimental, and can be enabled by `portable_atomic_outline_atomics` cfg. (When both cfg are enabled, `*_no_*` cfg is preferred.)
251> - Some AArch64 targets enable LLVM's `outline-atomics` target feature by default, so if you set this cfg, you may want to disable that as well. (However, portable-atomic's outline-atomics does not depend on the compiler-rt symbols, so even if you need to disable LLVM's outline-atomics, you may not need to disable portable-atomic's outline-atomics.)
252> - Dynamic detection is currently only supported in x86_64, AArch64, Arm, RISC-V, Arm64EC, and powerpc64. Enabling this cfg for unsupported architectures will be ignored.
253
254</div>
255
256## Related Projects
257
258- [portable-atomic-util]: Synchronization primitives built with portable-atomic. This provides portable-atomic version of `std::sync::Arc` and `std::task::Wake`.
259- [atomic-maybe-uninit]: Atomic operations on potentially uninitialized integers.
260- [atomic-memcpy]: Byte-wise atomic memcpy.
261- [asmtest]: A library for tracking generated assemblies.
262
263[#60]: https://github.com/taiki-e/portable-atomic/issues/60
264[asmtest]: https://github.com/taiki-e/asmtest
265[atomic-maybe-uninit]: https://github.com/taiki-e/atomic-maybe-uninit
266[atomic-memcpy]: https://github.com/taiki-e/atomic-memcpy
267[critical-section]: https://github.com/rust-embedded/critical-section
268[portable-atomic-util]: https://github.com/taiki-e/portable-atomic-util
269[rust-lang/rust#100650]: https://github.com/rust-lang/rust/issues/100650
270[serde]: https://github.com/serde-rs/serde
271
272<!-- tidy:sync-markdown-to-rustdoc:end -->
273*/
274
275#![no_std]
276#![doc(test(
277 no_crate_inject,
278 attr(
279 deny(warnings, rust_2018_idioms, single_use_lifetimes),
280 allow(dead_code, unused_variables)
281 )
282))]
283#![cfg_attr(not(portable_atomic_no_unsafe_op_in_unsafe_fn), warn(unsafe_op_in_unsafe_fn))] // unsafe_op_in_unsafe_fn requires Rust 1.52
284#![cfg_attr(portable_atomic_no_unsafe_op_in_unsafe_fn, allow(unused_unsafe))]
285#![warn(
286 // Lints that may help when writing public library.
287 missing_debug_implementations,
288 // missing_docs,
289 clippy::alloc_instead_of_core,
290 clippy::exhaustive_enums,
291 clippy::exhaustive_structs,
292 clippy::impl_trait_in_params,
293 clippy::std_instead_of_alloc,
294 clippy::std_instead_of_core,
295 clippy::missing_inline_in_public_items,
296 // Code outside of cfg(feature = "float") shouldn't use float.
297 clippy::float_arithmetic,
298)]
299#![cfg_attr(not(portable_atomic_no_asm), warn(missing_docs))] // module-level #![allow(missing_docs)] doesn't work for macros on old rustc
300#![cfg_attr(portable_atomic_no_strict_provenance, allow(unstable_name_collisions))]
301#![allow(
302 clippy::inline_always,
303 clippy::manual_assert_eq,
304 clippy::unreadable_literal,
305 clippy::used_underscore_items
306)]
307// asm_experimental_arch
308// AVR, MSP430, and Xtensa are tier 3 platforms and require nightly anyway.
309// On tier 2 platforms (currently N/A), we use cfg set by build script to
310// determine whether this feature is available or not.
311#![cfg_attr(
312 all(
313 not(portable_atomic_no_asm),
314 any(
315 all(target_arch = "avr", not(feature = "critical-section")),
316 target_arch = "msp430",
317 all(
318 target_arch = "xtensa",
319 any(
320 portable_atomic_unsafe_assume_single_core,
321 portable_atomic_unsafe_assume_privileged,
322 ),
323 ),
324 ),
325 ),
326 feature(asm_experimental_arch)
327)]
328// f16/f128
329// cfg is unstable and explicitly enabled by the user
330#![cfg_attr(
331 any(portable_atomic_unstable_f16, portable_atomic_unstable_f128),
332 allow(unused_features)
333)]
334#![cfg_attr(all(portable_atomic_unstable_f16, feature = "float"), feature(f16))]
335#![cfg_attr(all(portable_atomic_unstable_f128, feature = "float"), feature(f128))]
336// Old nightly only
337// These features are already stabilized or have already been removed from compilers,
338// and can safely be enabled for old nightly as long as version detection works.
339// - cfg(target_has_atomic)
340// - asm! on AArch64, Arm, RISC-V, x86, x86_64, Arm64EC, s390x, PowerPC64
341// - llvm_asm! on AVR (tier 3) and MSP430 (tier 3)
342// - #[instruction_set] on non-Linux/Android pre-v6 Arm (tier 3)
343// This also helps us test that our assembly code works with the minimum external
344// LLVM version of the first rustc version that inline assembly stabilized.
345#![cfg_attr(portable_atomic_unstable_cfg_target_has_atomic, feature(cfg_target_has_atomic))]
346#![cfg_attr(
347 all(
348 portable_atomic_unstable_asm,
349 any(
350 target_arch = "aarch64",
351 target_arch = "arm",
352 target_arch = "riscv32",
353 target_arch = "riscv64",
354 target_arch = "x86",
355 target_arch = "x86_64",
356 ),
357 ),
358 feature(asm)
359)]
360#![cfg_attr(
361 all(
362 portable_atomic_unstable_asm_experimental_arch,
363 any(target_arch = "arm64ec", target_arch = "s390x", target_arch = "powerpc64"),
364 ),
365 feature(asm_experimental_arch)
366)]
367#![cfg_attr(
368 all(any(target_arch = "avr", target_arch = "msp430"), portable_atomic_no_asm),
369 feature(llvm_asm)
370)]
371#![cfg_attr(
372 all(
373 target_arch = "arm",
374 portable_atomic_unstable_isa_attribute,
375 any(portable_atomic_unsafe_assume_single_core, portable_atomic_unsafe_assume_privileged),
376 not(any(target_feature = "v7", portable_atomic_target_feature = "v7")),
377 not(any(target_feature = "mclass", portable_atomic_target_feature = "mclass")),
378 ),
379 feature(isa_attribute)
380)]
381// Miri and/or ThreadSanitizer only
382// They do not support inline assembly, so we need to use unstable features instead.
383// Since they require nightly compilers anyway, we can use the unstable features.
384// This is not an ideal situation, but it is still better than always using lock-based
385// fallback and causing memory ordering problems to be missed by these checkers.
386#![cfg_attr(
387 all(
388 any(
389 target_arch = "aarch64",
390 target_arch = "arm64ec",
391 target_arch = "powerpc64",
392 target_arch = "s390x",
393 ),
394 any(miri, portable_atomic_sanitize_thread),
395 ),
396 allow(internal_features)
397)]
398#![cfg_attr(
399 all(
400 any(
401 target_arch = "aarch64",
402 target_arch = "arm64ec",
403 target_arch = "powerpc64",
404 target_arch = "s390x",
405 ),
406 portable_atomic_atomic_intrinsics,
407 any(miri, portable_atomic_sanitize_thread),
408 ),
409 feature(core_intrinsics)
410)]
411// docs.rs only (cfg is enabled by docs.rs, not build script)
412#![cfg_attr(docsrs, feature(doc_cfg))]
413#![cfg_attr(docsrs, doc(auto_cfg = false))]
414#![cfg_attr(
415 all(
416 portable_atomic_no_atomic_load_store,
417 not(any(
418 target_arch = "avr",
419 target_arch = "bpf",
420 target_arch = "msp430",
421 target_arch = "riscv32",
422 target_arch = "riscv64",
423 feature = "critical-section",
424 portable_atomic_unsafe_assume_single_core,
425 )),
426 ),
427 allow(unused_imports, unused_macros, clippy::unused_trait_names)
428)]
429
430#[cfg(any(test, feature = "std"))]
431extern crate std;
432
433#[macro_use]
434mod cfgs;
435#[cfg(target_pointer_width = "16")]
436pub use self::{cfg_has_atomic_16 as cfg_has_atomic_ptr, cfg_no_atomic_16 as cfg_no_atomic_ptr};
437#[cfg(target_pointer_width = "32")]
438pub use self::{cfg_has_atomic_32 as cfg_has_atomic_ptr, cfg_no_atomic_32 as cfg_no_atomic_ptr};
439#[cfg(target_pointer_width = "64")]
440pub use self::{cfg_has_atomic_64 as cfg_has_atomic_ptr, cfg_no_atomic_64 as cfg_no_atomic_ptr};
441#[cfg(target_pointer_width = "128")]
442pub use self::{cfg_has_atomic_128 as cfg_has_atomic_ptr, cfg_no_atomic_128 as cfg_no_atomic_ptr};
443
444// There are currently no 128-bit or higher builtin targets.
445// (Although some of our generic code is written with the future
446// addition of 128-bit targets in mind.)
447// Note that Rust (and C99) pointers must be at least 16-bit (i.e., 8-bit targets are impossible): https://github.com/rust-lang/rust/pull/49305
448#[cfg(not(any(
449 target_pointer_width = "16",
450 target_pointer_width = "32",
451 target_pointer_width = "64",
452)))]
453compile_error!(
454 "portable-atomic currently only supports targets with {16,32,64}-bit pointer width; \
455 if you need support for others, \
456 please submit an issue at <https://github.com/taiki-e/portable-atomic>"
457);
458
459// Reject unsupported architectures.
460#[cfg(portable_atomic_unsafe_assume_single_core)]
461#[cfg(not(any(
462 target_arch = "arm",
463 target_arch = "avr",
464 target_arch = "msp430",
465 target_arch = "riscv32",
466 target_arch = "riscv64",
467 target_arch = "xtensa",
468)))]
469compile_error!(
470 "`portable_atomic_unsafe_assume_single_core` cfg (`unsafe-assume-single-core` feature) \
471 is not supported yet on this architecture;\n\
472 if you need unsafe-assume-{single-core,privileged} support for this target,\n\
473 please submit an issue at <https://github.com/taiki-e/portable-atomic/issues/new>"
474);
475// unsafe-assume-single-core is accepted on AVR/MSP430, but
476// unsafe-assume-privileged on them is really useless on them since they are
477// always single-core, so rejected here.
478#[cfg(portable_atomic_unsafe_assume_privileged)]
479#[cfg(not(any(
480 target_arch = "arm",
481 target_arch = "riscv32",
482 target_arch = "riscv64",
483 target_arch = "xtensa",
484)))]
485compile_error!(
486 "`portable_atomic_unsafe_assume_privileged` cfg (`unsafe-assume-privileged` feature) \
487 is not supported yet on this architecture;\n\
488 if you need unsafe-assume-{single-core,privileged} support for this target,\n\
489 please submit an issue at <https://github.com/taiki-e/portable-atomic/issues/new>"
490);
491// unsafe-assume-privileged requires CAS.
492#[cfg(portable_atomic_unsafe_assume_privileged)]
493cfg_no_atomic_cas! {
494 compile_error!(
495 "`portable_atomic_unsafe_assume_privileged` cfg (`unsafe-assume-privileged` feature) \
496 requires atomic CAS"
497 );
498}
499// Reject targets where privileged instructions are obviously unavailable.
500// TODO: Some embedded OSes should probably be accepted here.
501#[cfg(any(portable_atomic_unsafe_assume_single_core, portable_atomic_unsafe_assume_privileged))]
502#[cfg(any(
503 target_arch = "arm",
504 target_arch = "avr",
505 target_arch = "msp430",
506 target_arch = "riscv32",
507 target_arch = "riscv64",
508 target_arch = "xtensa",
509))]
510#[cfg_attr(
511 portable_atomic_no_cfg_target_has_atomic,
512 cfg(all(not(portable_atomic_no_atomic_cas), not(target_os = "none")))
513)]
514#[cfg_attr(
515 not(portable_atomic_no_cfg_target_has_atomic),
516 cfg(all(target_has_atomic = "ptr", not(target_os = "none")))
517)]
518compile_error!(
519 "`portable_atomic_unsafe_assume_{single_core,privileged}` cfg (`unsafe-assume-{single-core,privileged}` feature) \
520 is not compatible with target where privileged instructions are obviously unavailable;\n\
521 if you need unsafe-assume-{single-core,privileged} support for this target,\n\
522 please submit an issue at <https://github.com/taiki-e/portable-atomic/issues/new>\n\
523 see also <https://github.com/taiki-e/portable-atomic/issues/148> for troubleshooting"
524);
525
526#[cfg(portable_atomic_outline_atomics)]
527#[cfg(not(any(
528 target_arch = "aarch64",
529 target_arch = "powerpc64",
530 target_arch = "riscv32",
531 target_arch = "riscv64",
532)))]
533compile_error!("`portable_atomic_outline_atomics` cfg does not compatible with this target");
534
535#[cfg(portable_atomic_disable_fiq)]
536#[cfg(not(all(
537 target_arch = "arm",
538 not(any(target_feature = "mclass", portable_atomic_target_feature = "mclass")),
539)))]
540compile_error!(
541 "`portable_atomic_disable_fiq` cfg (`disable-fiq` feature) is only available on Arm (except for M-Profile architectures)"
542);
543#[cfg(portable_atomic_s_mode)]
544#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
545compile_error!("`portable_atomic_s_mode` cfg (`s-mode` feature) is only available on RISC-V");
546#[cfg(portable_atomic_force_amo)]
547#[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))]
548compile_error!("`portable_atomic_force_amo` cfg (`force-amo` feature) is only available on RISC-V");
549
550#[cfg(portable_atomic_disable_fiq)]
551#[cfg(not(any(
552 portable_atomic_unsafe_assume_single_core,
553 portable_atomic_unsafe_assume_privileged,
554)))]
555compile_error!(
556 "`portable_atomic_disable_fiq` cfg (`disable-fiq` feature) may only be used together with `portable_atomic_unsafe_assume_{single_core,privileged}` cfg (`unsafe-assume-{single-core,privileged}` feature)"
557);
558#[cfg(portable_atomic_s_mode)]
559#[cfg(not(any(
560 portable_atomic_unsafe_assume_single_core,
561 portable_atomic_unsafe_assume_privileged,
562)))]
563compile_error!(
564 "`portable_atomic_s_mode` cfg (`s-mode` feature) may only be used together with `portable_atomic_unsafe_assume_{single_core,privileged}` cfg (`unsafe-assume-{single-core,privileged}` feature)"
565);
566#[cfg(portable_atomic_force_amo)]
567#[cfg(not(portable_atomic_unsafe_assume_single_core))]
568compile_error!(
569 "`portable_atomic_force_amo` cfg (`force-amo` feature) may only be used together with `portable_atomic_unsafe_assume_single_core` cfg (`unsafe-assume-single-core` feature)"
570);
571#[cfg(portable_atomic_unsafe_assume_privileged)]
572#[cfg(not(feature = "fallback"))]
573compile_error!(
574 "`portable_atomic_unsafe_assume_privileged` cfg (`unsafe-assume-privileged` feature) may only be used together with `fallback` feature"
575);
576
577#[cfg(all(
578 any(portable_atomic_unsafe_assume_single_core, portable_atomic_unsafe_assume_privileged),
579 feature = "critical-section"
580))]
581compile_error!(
582 "you may not enable `critical-section` feature and `portable_atomic_unsafe_assume_{single_core,privileged}` cfg (`unsafe-assume-{single-core,privileged}` feature) at the same time"
583);
584
585#[cfg(feature = "require-cas")]
586#[cfg_attr(
587 portable_atomic_no_cfg_target_has_atomic,
588 cfg(not(any(
589 not(portable_atomic_no_atomic_cas),
590 target_arch = "avr",
591 target_arch = "msp430",
592 feature = "critical-section",
593 portable_atomic_unsafe_assume_single_core,
594 )))
595)]
596#[cfg_attr(
597 not(portable_atomic_no_cfg_target_has_atomic),
598 cfg(not(any(
599 target_has_atomic = "ptr",
600 target_arch = "avr",
601 target_arch = "msp430",
602 feature = "critical-section",
603 portable_atomic_unsafe_assume_single_core,
604 )))
605)]
606compile_error!(
607 "dependents require atomic CAS but not available on this target by default;\n\
608 consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg).\n\
609 see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
610);
611
612#[macro_use]
613mod utils;
614
615#[cfg(test)]
616#[macro_use]
617mod tests;
618
619#[doc(no_inline)]
620pub use core::sync::atomic::Ordering;
621
622cfg_sel!({
623 // LLVM doesn't support fence/compiler_fence for MSP430.
624 #[cfg(target_arch = "msp430")]
625 {
626 pub use self::imp::msp430::{compiler_fence, fence};
627 }
628 // We have optimized fence for x86.
629 // Miri and Sanitizer do not support inline assembly.
630 #[cfg(all(
631 not(doc),
632 any(target_arch = "x86", target_arch = "x86_64"),
633 not(any(miri, portable_atomic_sanitize_thread)),
634 any(not(portable_atomic_no_asm), portable_atomic_unstable_asm),
635 ))]
636 {
637 pub use core::sync::atomic::compiler_fence;
638
639 pub use self::imp::x86::fence;
640 }
641 #[cfg(else)]
642 {
643 pub use core::sync::atomic::{compiler_fence, fence};
644 }
645});
646
647mod imp;
648
649pub mod hint {
650 //! Re-export of the [`core::hint`] module.
651 //!
652 //! The only difference from the [`core::hint`] module is that [`spin_loop`]
653 //! is available in all rust versions that this crate supports.
654 //!
655 //! ```
656 //! use portable_atomic::hint;
657 //!
658 //! hint::spin_loop();
659 //! ```
660
661 #[doc(no_inline)]
662 pub use core::hint::*;
663
664 /// Emits a machine instruction to signal the processor that it is running in
665 /// a busy-wait spin-loop ("spin lock").
666 ///
667 /// Upon receiving the spin-loop signal the processor can optimize its behavior by,
668 /// for example, saving power or switching hyper-threads.
669 ///
670 /// This function is different from [`thread::yield_now`] which directly
671 /// yields to the system's scheduler, whereas `spin_loop` does not interact
672 /// with the operating system.
673 ///
674 /// A common use case for `spin_loop` is implementing bounded optimistic
675 /// spinning in a CAS loop in synchronization primitives. To avoid problems
676 /// like priority inversion, it is strongly recommended that the spin loop is
677 /// terminated after a finite amount of iterations and an appropriate blocking
678 /// syscall is made.
679 ///
680 /// **Note:** On platforms that do not support receiving spin-loop hints this
681 /// function does not do anything at all.
682 ///
683 /// [`thread::yield_now`]: https://doc.rust-lang.org/std/thread/fn.yield_now.html
684 #[inline]
685 pub fn spin_loop() {
686 #[allow(deprecated)]
687 core::sync::atomic::spin_loop_hint();
688 }
689}
690
691#[cfg(doc)]
692use core::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release, SeqCst};
693use core::{fmt, ptr};
694
695cfg_has_atomic_8! {
696/// A boolean type which can be safely shared between threads.
697///
698/// This type has the same in-memory representation as a [`bool`].
699///
700/// If the compiler and the platform support atomic loads and stores of `u8`,
701/// this type is a wrapper for the standard library's
702/// [`AtomicBool`](core::sync::atomic::AtomicBool). If the platform supports it
703/// but the compiler does not, atomic operations are implemented using inline
704/// assembly.
705#[repr(C, align(1))]
706pub struct AtomicBool {
707 v: core::cell::UnsafeCell<u8>,
708}
709
710impl Default for AtomicBool {
711 /// Creates an `AtomicBool` initialized to `false`.
712 #[inline]
713 fn default() -> Self {
714 Self::new(false)
715 }
716}
717
718impl From<bool> for AtomicBool {
719 /// Converts a `bool` into an `AtomicBool`.
720 #[inline]
721 fn from(b: bool) -> Self {
722 Self::new(b)
723 }
724}
725
726// Send is implicitly implemented.
727// SAFETY: any data races are prevented by disabling interrupts or
728// atomic intrinsics (see module-level comments).
729unsafe impl Sync for AtomicBool {}
730
731// UnwindSafe is implicitly implemented.
732#[cfg(not(portable_atomic_no_core_unwind_safe))]
733impl core::panic::RefUnwindSafe for AtomicBool {}
734#[cfg(all(portable_atomic_no_core_unwind_safe, feature = "std"))]
735impl std::panic::RefUnwindSafe for AtomicBool {}
736
737impl_debug_and_serde!(AtomicBool);
738
739impl AtomicBool {
740 /// Creates a new `AtomicBool`.
741 ///
742 /// # Examples
743 ///
744 /// ```
745 /// use portable_atomic::AtomicBool;
746 ///
747 /// let atomic_true = AtomicBool::new(true);
748 /// let atomic_false = AtomicBool::new(false);
749 /// ```
750 #[inline]
751 #[must_use]
752 pub const fn new(v: bool) -> Self {
753 static_assert_layout!(AtomicBool, bool);
754 Self { v: core::cell::UnsafeCell::new(v as u8) }
755 }
756
757 // TODO: update docs based on https://github.com/rust-lang/rust/pull/116762
758 const_fn! {
759 const_if: #[cfg(not(portable_atomic_no_const_mut_refs))];
760 /// Creates a new `AtomicBool` from a pointer.
761 ///
762 /// This is `const fn` on Rust 1.83+.
763 ///
764 /// # Safety
765 ///
766 /// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can
767 /// be bigger than `align_of::<bool>()`).
768 /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
769 /// * If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
770 /// behind `ptr` must have a happens-before relationship with atomic accesses via the returned
771 /// value (or vice-versa).
772 /// * In other words, time periods where the value is accessed atomically may not overlap
773 /// with periods where the value is accessed non-atomically.
774 /// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the
775 /// duration of lifetime `'a`. Most use cases should be able to follow this guideline.
776 /// * This requirement is also trivially satisfied if all accesses (atomic or not) are done
777 /// from the same thread.
778 /// * If this atomic type is *not* lock-free:
779 /// * Any accesses to the value behind `ptr` must have a happens-before relationship
780 /// with accesses via the returned value (or vice-versa).
781 /// * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
782 /// be compatible with operations performed by this atomic type.
783 /// * This method must not be used to create overlapping or mixed-size atomic accesses, as
784 /// these are not supported by the memory model.
785 ///
786 /// [valid]: core::ptr#safety
787 #[inline]
788 #[must_use]
789 pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a Self {
790 #[allow(clippy::cast_ptr_alignment)]
791 // SAFETY: guaranteed by the caller
792 unsafe { &*(ptr as *mut Self) }
793 }
794 }
795
796 /// Returns `true` if operations on values of this type are lock-free.
797 ///
798 /// If the compiler or the platform doesn't support the necessary
799 /// atomic instructions, global locks for every potentially
800 /// concurrent atomic operation will be used.
801 ///
802 /// This function is guaranteed to always return the same result.
803 ///
804 /// # Examples
805 ///
806 /// ```
807 /// use portable_atomic::AtomicBool;
808 ///
809 /// let is_lock_free = AtomicBool::is_lock_free();
810 /// ```
811 #[inline]
812 #[must_use]
813 pub fn is_lock_free() -> bool {
814 imp::AtomicU8::is_lock_free()
815 }
816
817 /// Returns `true` if operations on values of this type are lock-free.
818 ///
819 /// If the compiler or the platform doesn't support the necessary
820 /// atomic instructions, global locks for every potentially
821 /// concurrent atomic operation will be used.
822 ///
823 /// **Note:** If the atomic operation relies on dynamic CPU feature detection,
824 /// this type may be lock-free even if the function returns false.
825 ///
826 /// # Examples
827 ///
828 /// ```
829 /// use portable_atomic::AtomicBool;
830 ///
831 /// const IS_ALWAYS_LOCK_FREE: bool = AtomicBool::is_always_lock_free();
832 /// ```
833 #[inline]
834 #[must_use]
835 pub const fn is_always_lock_free() -> bool {
836 imp::AtomicU8::IS_ALWAYS_LOCK_FREE
837 }
838 #[cfg(test)]
839 const IS_ALWAYS_LOCK_FREE: bool = Self::is_always_lock_free();
840
841 const_fn! {
842 const_if: #[cfg(not(portable_atomic_no_const_mut_refs))];
843 /// Returns a mutable reference to the underlying [`bool`].
844 ///
845 /// This is safe because the mutable reference guarantees that no other threads are
846 /// concurrently accessing the atomic data.
847 ///
848 /// This is `const fn` on Rust 1.83+.
849 ///
850 /// # Examples
851 ///
852 /// ```
853 /// use portable_atomic::{AtomicBool, Ordering};
854 ///
855 /// let mut some_bool = AtomicBool::new(true);
856 /// assert_eq!(*some_bool.get_mut(), true);
857 /// *some_bool.get_mut() = false;
858 /// assert_eq!(some_bool.load(Ordering::SeqCst), false);
859 /// ```
860 #[inline]
861 pub const fn get_mut(&mut self) -> &mut bool {
862 // SAFETY: the mutable reference guarantees unique ownership.
863 unsafe { &mut *self.as_ptr() }
864 }
865 }
866
867 // TODO: Add from_mut/get_mut_slice/from_mut_slice once it is stable on std atomic types.
868 // https://github.com/rust-lang/rust/issues/76314
869
870 const_fn! {
871 const_if: #[cfg(not(portable_atomic_no_const_transmute))];
872 /// Consumes the atomic and returns the contained value.
873 ///
874 /// This is safe because passing `self` by value guarantees that no other threads are
875 /// concurrently accessing the atomic data.
876 ///
877 /// This is `const fn` on Rust 1.56+.
878 ///
879 /// # Examples
880 ///
881 /// ```
882 /// use portable_atomic::AtomicBool;
883 ///
884 /// let some_bool = AtomicBool::new(true);
885 /// assert_eq!(some_bool.into_inner(), true);
886 /// ```
887 #[inline]
888 pub const fn into_inner(self) -> bool {
889 // SAFETY: AtomicBool and u8 have the same size and in-memory representations,
890 // so they can be safely transmuted.
891 // (const UnsafeCell::into_inner is unstable)
892 unsafe { core::mem::transmute::<AtomicBool, u8>(self) != 0 }
893 }
894 }
895
896 /// Loads a value from the bool.
897 ///
898 /// `load` takes an [`Ordering`] argument which describes the memory ordering
899 /// of this operation. Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
900 ///
901 /// # Panics
902 ///
903 /// Panics if `order` is [`Release`] or [`AcqRel`].
904 ///
905 /// # Examples
906 ///
907 /// ```
908 /// use portable_atomic::{AtomicBool, Ordering};
909 ///
910 /// let some_bool = AtomicBool::new(true);
911 ///
912 /// assert_eq!(some_bool.load(Ordering::Relaxed), true);
913 /// ```
914 #[inline]
915 #[cfg_attr(
916 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
917 track_caller
918 )]
919 pub fn load(&self, order: Ordering) -> bool {
920 self.as_atomic_u8().load(order) != 0
921 }
922
923 /// Stores a value into the bool.
924 ///
925 /// `store` takes an [`Ordering`] argument which describes the memory ordering
926 /// of this operation. Possible values are [`SeqCst`], [`Release`] and [`Relaxed`].
927 ///
928 /// # Panics
929 ///
930 /// Panics if `order` is [`Acquire`] or [`AcqRel`].
931 ///
932 /// # Examples
933 ///
934 /// ```
935 /// use portable_atomic::{AtomicBool, Ordering};
936 ///
937 /// let some_bool = AtomicBool::new(true);
938 ///
939 /// some_bool.store(false, Ordering::Relaxed);
940 /// assert_eq!(some_bool.load(Ordering::Relaxed), false);
941 /// ```
942 #[inline]
943 #[cfg_attr(
944 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
945 track_caller
946 )]
947 pub fn store(&self, val: bool, order: Ordering) {
948 self.as_atomic_u8().store(val as u8, order);
949 }
950
951 cfg_has_atomic_cas_or_amo32! {
952 /// Stores a value into the bool, returning the previous value.
953 ///
954 /// `swap` takes an [`Ordering`] argument which describes the memory ordering
955 /// of this operation. All ordering modes are possible. Note that using
956 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
957 /// using [`Release`] makes the load part [`Relaxed`].
958 ///
959 /// # Examples
960 ///
961 /// ```
962 /// use portable_atomic::{AtomicBool, Ordering};
963 ///
964 /// let some_bool = AtomicBool::new(true);
965 ///
966 /// assert_eq!(some_bool.swap(false, Ordering::Relaxed), true);
967 /// assert_eq!(some_bool.load(Ordering::Relaxed), false);
968 /// ```
969 #[inline]
970 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
971 pub fn swap(&self, val: bool, order: Ordering) -> bool {
972 #[cfg(any(
973 target_arch = "riscv32",
974 target_arch = "riscv64",
975 target_arch = "loongarch32",
976 target_arch = "loongarch64",
977 ))]
978 {
979 // See https://github.com/rust-lang/rust/pull/114034 for details.
980 // https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/sync/atomic.rs#L249
981 // https://godbolt.org/z/ofbGGdx44
982 if val { self.fetch_or(true, order) } else { self.fetch_and(false, order) }
983 }
984 #[cfg(not(any(
985 target_arch = "riscv32",
986 target_arch = "riscv64",
987 target_arch = "loongarch32",
988 target_arch = "loongarch64",
989 )))]
990 {
991 self.as_atomic_u8().swap(val as u8, order) != 0
992 }
993 }
994
995 /// Stores a value into the [`bool`] if the current value is the same as the `current` value.
996 ///
997 /// The return value is a result indicating whether the new value was written and containing
998 /// the previous value. On success this value is guaranteed to be equal to `current`.
999 ///
1000 /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
1001 /// ordering of this operation. `success` describes the required ordering for the
1002 /// read-modify-write operation that takes place if the comparison with `current` succeeds.
1003 /// `failure` describes the required ordering for the load operation that takes place when
1004 /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
1005 /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
1006 /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
1007 ///
1008 /// # Panics
1009 ///
1010 /// Panics if `failure` is [`Release`], [`AcqRel`].
1011 ///
1012 /// # Examples
1013 ///
1014 /// ```
1015 /// use portable_atomic::{AtomicBool, Ordering};
1016 ///
1017 /// let some_bool = AtomicBool::new(true);
1018 ///
1019 /// assert_eq!(
1020 /// some_bool.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed),
1021 /// Ok(true)
1022 /// );
1023 /// assert_eq!(some_bool.load(Ordering::Relaxed), false);
1024 ///
1025 /// assert_eq!(
1026 /// some_bool.compare_exchange(true, true, Ordering::SeqCst, Ordering::Acquire),
1027 /// Err(false)
1028 /// );
1029 /// assert_eq!(some_bool.load(Ordering::Relaxed), false);
1030 /// ```
1031 #[cfg_attr(docsrs, doc(alias = "compare_and_swap"))]
1032 #[inline]
1033 #[cfg_attr(
1034 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
1035 track_caller
1036 )]
1037 pub fn compare_exchange(
1038 &self,
1039 current: bool,
1040 new: bool,
1041 success: Ordering,
1042 failure: Ordering,
1043 ) -> Result<bool, bool> {
1044 #[cfg(any(
1045 target_arch = "riscv32",
1046 target_arch = "riscv64",
1047 target_arch = "loongarch32",
1048 target_arch = "loongarch64",
1049 ))]
1050 {
1051 // See https://github.com/rust-lang/rust/pull/114034 for details.
1052 // https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/sync/atomic.rs#L249
1053 // https://godbolt.org/z/ofbGGdx44
1054 crate::utils::assert_compare_exchange_ordering(success, failure);
1055 let order = crate::utils::upgrade_success_ordering(success, failure);
1056 let old = if current == new {
1057 // This is a no-op, but we still need to perform the operation
1058 // for memory ordering reasons.
1059 self.fetch_or(false, order)
1060 } else {
1061 // This sets the value to the new one and returns the old one.
1062 self.swap(new, order)
1063 };
1064 if old == current { Ok(old) } else { Err(old) }
1065 }
1066 #[cfg(not(any(
1067 target_arch = "riscv32",
1068 target_arch = "riscv64",
1069 target_arch = "loongarch32",
1070 target_arch = "loongarch64",
1071 )))]
1072 {
1073 match self.as_atomic_u8().compare_exchange(current as u8, new as u8, success, failure) {
1074 Ok(x) => Ok(x != 0),
1075 Err(x) => Err(x != 0),
1076 }
1077 }
1078 }
1079
1080 /// Stores a value into the [`bool`] if the current value is the same as the `current` value.
1081 ///
1082 /// Unlike [`AtomicBool::compare_exchange`], this function is allowed to spuriously fail even when the
1083 /// comparison succeeds, which can result in more efficient code on some platforms. The
1084 /// return value is a result indicating whether the new value was written and containing the
1085 /// previous value.
1086 ///
1087 /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
1088 /// ordering of this operation. `success` describes the required ordering for the
1089 /// read-modify-write operation that takes place if the comparison with `current` succeeds.
1090 /// `failure` describes the required ordering for the load operation that takes place when
1091 /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
1092 /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
1093 /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
1094 ///
1095 /// # Panics
1096 ///
1097 /// Panics if `failure` is [`Release`], [`AcqRel`].
1098 ///
1099 /// # Examples
1100 ///
1101 /// ```
1102 /// use portable_atomic::{AtomicBool, Ordering};
1103 ///
1104 /// let val = AtomicBool::new(false);
1105 ///
1106 /// let new = true;
1107 /// let mut old = val.load(Ordering::Relaxed);
1108 /// loop {
1109 /// match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
1110 /// Ok(_) => break,
1111 /// Err(x) => old = x,
1112 /// }
1113 /// }
1114 /// ```
1115 #[cfg_attr(docsrs, doc(alias = "compare_and_swap"))]
1116 #[inline]
1117 #[cfg_attr(
1118 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
1119 track_caller
1120 )]
1121 pub fn compare_exchange_weak(
1122 &self,
1123 current: bool,
1124 new: bool,
1125 success: Ordering,
1126 failure: Ordering,
1127 ) -> Result<bool, bool> {
1128 #[cfg(any(
1129 target_arch = "riscv32",
1130 target_arch = "riscv64",
1131 target_arch = "loongarch32",
1132 target_arch = "loongarch64",
1133 ))]
1134 {
1135 // See https://github.com/rust-lang/rust/pull/114034 for details.
1136 // https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/sync/atomic.rs#L249
1137 // https://godbolt.org/z/ofbGGdx44
1138 self.compare_exchange(current, new, success, failure)
1139 }
1140 #[cfg(not(any(
1141 target_arch = "riscv32",
1142 target_arch = "riscv64",
1143 target_arch = "loongarch32",
1144 target_arch = "loongarch64",
1145 )))]
1146 {
1147 match self
1148 .as_atomic_u8()
1149 .compare_exchange_weak(current as u8, new as u8, success, failure)
1150 {
1151 Ok(x) => Ok(x != 0),
1152 Err(x) => Err(x != 0),
1153 }
1154 }
1155 }
1156
1157 /// Logical "and" with a boolean value.
1158 ///
1159 /// Performs a logical "and" operation on the current value and the argument `val`, and sets
1160 /// the new value to the result.
1161 ///
1162 /// Returns the previous value.
1163 ///
1164 /// `fetch_and` takes an [`Ordering`] argument which describes the memory ordering
1165 /// of this operation. All ordering modes are possible. Note that using
1166 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
1167 /// using [`Release`] makes the load part [`Relaxed`].
1168 ///
1169 /// # Examples
1170 ///
1171 /// ```
1172 /// use portable_atomic::{AtomicBool, Ordering};
1173 ///
1174 /// let foo = AtomicBool::new(true);
1175 /// assert_eq!(foo.fetch_and(false, Ordering::SeqCst), true);
1176 /// assert_eq!(foo.load(Ordering::SeqCst), false);
1177 ///
1178 /// let foo = AtomicBool::new(true);
1179 /// assert_eq!(foo.fetch_and(true, Ordering::SeqCst), true);
1180 /// assert_eq!(foo.load(Ordering::SeqCst), true);
1181 ///
1182 /// let foo = AtomicBool::new(false);
1183 /// assert_eq!(foo.fetch_and(false, Ordering::SeqCst), false);
1184 /// assert_eq!(foo.load(Ordering::SeqCst), false);
1185 /// ```
1186 #[inline]
1187 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1188 pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
1189 self.as_atomic_u8().fetch_and(val as u8, order) != 0
1190 }
1191
1192 /// Logical "and" with a boolean value.
1193 ///
1194 /// Performs a logical "and" operation on the current value and the argument `val`, and sets
1195 /// the new value to the result.
1196 ///
1197 /// Unlike `fetch_and`, this does not return the previous value.
1198 ///
1199 /// `and` takes an [`Ordering`] argument which describes the memory ordering
1200 /// of this operation. All ordering modes are possible. Note that using
1201 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
1202 /// using [`Release`] makes the load part [`Relaxed`].
1203 ///
1204 /// This function may generate more efficient code than `fetch_and` on some platforms.
1205 ///
1206 /// - x86/x86_64: `lock and` instead of `cmpxchg` loop
1207 /// - MSP430: `and` instead of disabling interrupts
1208 ///
1209 /// Note: On x86/x86_64, the use of either function should not usually
1210 /// affect the generated code, because LLVM can properly optimize the case
1211 /// where the result is unused.
1212 ///
1213 /// # Examples
1214 ///
1215 /// ```
1216 /// use portable_atomic::{AtomicBool, Ordering};
1217 ///
1218 /// let foo = AtomicBool::new(true);
1219 /// foo.and(false, Ordering::SeqCst);
1220 /// assert_eq!(foo.load(Ordering::SeqCst), false);
1221 ///
1222 /// let foo = AtomicBool::new(true);
1223 /// foo.and(true, Ordering::SeqCst);
1224 /// assert_eq!(foo.load(Ordering::SeqCst), true);
1225 ///
1226 /// let foo = AtomicBool::new(false);
1227 /// foo.and(false, Ordering::SeqCst);
1228 /// assert_eq!(foo.load(Ordering::SeqCst), false);
1229 /// ```
1230 #[inline]
1231 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1232 pub fn and(&self, val: bool, order: Ordering) {
1233 self.as_atomic_u8().and(val as u8, order);
1234 }
1235
1236 /// Logical "nand" with a boolean value.
1237 ///
1238 /// Performs a logical "nand" operation on the current value and the argument `val`, and sets
1239 /// the new value to the result.
1240 ///
1241 /// Returns the previous value.
1242 ///
1243 /// `fetch_nand` takes an [`Ordering`] argument which describes the memory ordering
1244 /// of this operation. All ordering modes are possible. Note that using
1245 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
1246 /// using [`Release`] makes the load part [`Relaxed`].
1247 ///
1248 /// # Examples
1249 ///
1250 /// ```
1251 /// use portable_atomic::{AtomicBool, Ordering};
1252 ///
1253 /// let foo = AtomicBool::new(true);
1254 /// assert_eq!(foo.fetch_nand(false, Ordering::SeqCst), true);
1255 /// assert_eq!(foo.load(Ordering::SeqCst), true);
1256 ///
1257 /// let foo = AtomicBool::new(true);
1258 /// assert_eq!(foo.fetch_nand(true, Ordering::SeqCst), true);
1259 /// assert_eq!(foo.load(Ordering::SeqCst) as usize, 0);
1260 /// assert_eq!(foo.load(Ordering::SeqCst), false);
1261 ///
1262 /// let foo = AtomicBool::new(false);
1263 /// assert_eq!(foo.fetch_nand(false, Ordering::SeqCst), false);
1264 /// assert_eq!(foo.load(Ordering::SeqCst), true);
1265 /// ```
1266 #[inline]
1267 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1268 pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
1269 // https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/sync/atomic.rs#L973-L985
1270 if val {
1271 // !(x & true) == !x
1272 // We must invert the bool.
1273 self.fetch_xor(true, order)
1274 } else {
1275 // !(x & false) == true
1276 // We must set the bool to true.
1277 self.swap(true, order)
1278 }
1279 }
1280
1281 /// Logical "or" with a boolean value.
1282 ///
1283 /// Performs a logical "or" operation on the current value and the argument `val`, and sets the
1284 /// new value to the result.
1285 ///
1286 /// Returns the previous value.
1287 ///
1288 /// `fetch_or` takes an [`Ordering`] argument which describes the memory ordering
1289 /// of this operation. All ordering modes are possible. Note that using
1290 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
1291 /// using [`Release`] makes the load part [`Relaxed`].
1292 ///
1293 /// # Examples
1294 ///
1295 /// ```
1296 /// use portable_atomic::{AtomicBool, Ordering};
1297 ///
1298 /// let foo = AtomicBool::new(true);
1299 /// assert_eq!(foo.fetch_or(false, Ordering::SeqCst), true);
1300 /// assert_eq!(foo.load(Ordering::SeqCst), true);
1301 ///
1302 /// let foo = AtomicBool::new(true);
1303 /// assert_eq!(foo.fetch_or(true, Ordering::SeqCst), true);
1304 /// assert_eq!(foo.load(Ordering::SeqCst), true);
1305 ///
1306 /// let foo = AtomicBool::new(false);
1307 /// assert_eq!(foo.fetch_or(false, Ordering::SeqCst), false);
1308 /// assert_eq!(foo.load(Ordering::SeqCst), false);
1309 /// ```
1310 #[inline]
1311 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1312 pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
1313 self.as_atomic_u8().fetch_or(val as u8, order) != 0
1314 }
1315
1316 /// Logical "or" with a boolean value.
1317 ///
1318 /// Performs a logical "or" operation on the current value and the argument `val`, and sets the
1319 /// new value to the result.
1320 ///
1321 /// Unlike `fetch_or`, this does not return the previous value.
1322 ///
1323 /// `or` takes an [`Ordering`] argument which describes the memory ordering
1324 /// of this operation. All ordering modes are possible. Note that using
1325 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
1326 /// using [`Release`] makes the load part [`Relaxed`].
1327 ///
1328 /// This function may generate more efficient code than `fetch_or` on some platforms.
1329 ///
1330 /// - x86/x86_64: `lock or` instead of `cmpxchg` loop
1331 /// - MSP430: `bis` instead of disabling interrupts
1332 ///
1333 /// Note: On x86/x86_64, the use of either function should not usually
1334 /// affect the generated code, because LLVM can properly optimize the case
1335 /// where the result is unused.
1336 ///
1337 /// # Examples
1338 ///
1339 /// ```
1340 /// use portable_atomic::{AtomicBool, Ordering};
1341 ///
1342 /// let foo = AtomicBool::new(true);
1343 /// foo.or(false, Ordering::SeqCst);
1344 /// assert_eq!(foo.load(Ordering::SeqCst), true);
1345 ///
1346 /// let foo = AtomicBool::new(true);
1347 /// foo.or(true, Ordering::SeqCst);
1348 /// assert_eq!(foo.load(Ordering::SeqCst), true);
1349 ///
1350 /// let foo = AtomicBool::new(false);
1351 /// foo.or(false, Ordering::SeqCst);
1352 /// assert_eq!(foo.load(Ordering::SeqCst), false);
1353 /// ```
1354 #[inline]
1355 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1356 pub fn or(&self, val: bool, order: Ordering) {
1357 self.as_atomic_u8().or(val as u8, order);
1358 }
1359
1360 /// Logical "xor" with a boolean value.
1361 ///
1362 /// Performs a logical "xor" operation on the current value and the argument `val`, and sets
1363 /// the new value to the result.
1364 ///
1365 /// Returns the previous value.
1366 ///
1367 /// `fetch_xor` takes an [`Ordering`] argument which describes the memory ordering
1368 /// of this operation. All ordering modes are possible. Note that using
1369 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
1370 /// using [`Release`] makes the load part [`Relaxed`].
1371 ///
1372 /// # Examples
1373 ///
1374 /// ```
1375 /// use portable_atomic::{AtomicBool, Ordering};
1376 ///
1377 /// let foo = AtomicBool::new(true);
1378 /// assert_eq!(foo.fetch_xor(false, Ordering::SeqCst), true);
1379 /// assert_eq!(foo.load(Ordering::SeqCst), true);
1380 ///
1381 /// let foo = AtomicBool::new(true);
1382 /// assert_eq!(foo.fetch_xor(true, Ordering::SeqCst), true);
1383 /// assert_eq!(foo.load(Ordering::SeqCst), false);
1384 ///
1385 /// let foo = AtomicBool::new(false);
1386 /// assert_eq!(foo.fetch_xor(false, Ordering::SeqCst), false);
1387 /// assert_eq!(foo.load(Ordering::SeqCst), false);
1388 /// ```
1389 #[inline]
1390 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1391 pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
1392 self.as_atomic_u8().fetch_xor(val as u8, order) != 0
1393 }
1394
1395 /// Logical "xor" with a boolean value.
1396 ///
1397 /// Performs a logical "xor" operation on the current value and the argument `val`, and sets
1398 /// the new value to the result.
1399 ///
1400 /// Unlike `fetch_xor`, this does not return the previous value.
1401 ///
1402 /// `xor` takes an [`Ordering`] argument which describes the memory ordering
1403 /// of this operation. All ordering modes are possible. Note that using
1404 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
1405 /// using [`Release`] makes the load part [`Relaxed`].
1406 ///
1407 /// This function may generate more efficient code than `fetch_xor` on some platforms.
1408 ///
1409 /// - x86/x86_64: `lock xor` instead of `cmpxchg` loop
1410 /// - MSP430: `xor` instead of disabling interrupts
1411 ///
1412 /// Note: On x86/x86_64, the use of either function should not usually
1413 /// affect the generated code, because LLVM can properly optimize the case
1414 /// where the result is unused.
1415 ///
1416 /// # Examples
1417 ///
1418 /// ```
1419 /// use portable_atomic::{AtomicBool, Ordering};
1420 ///
1421 /// let foo = AtomicBool::new(true);
1422 /// foo.xor(false, Ordering::SeqCst);
1423 /// assert_eq!(foo.load(Ordering::SeqCst), true);
1424 ///
1425 /// let foo = AtomicBool::new(true);
1426 /// foo.xor(true, Ordering::SeqCst);
1427 /// assert_eq!(foo.load(Ordering::SeqCst), false);
1428 ///
1429 /// let foo = AtomicBool::new(false);
1430 /// foo.xor(false, Ordering::SeqCst);
1431 /// assert_eq!(foo.load(Ordering::SeqCst), false);
1432 /// ```
1433 #[inline]
1434 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1435 pub fn xor(&self, val: bool, order: Ordering) {
1436 self.as_atomic_u8().xor(val as u8, order);
1437 }
1438
1439 /// Logical "not" with a boolean value.
1440 ///
1441 /// Performs a logical "not" operation on the current value, and sets
1442 /// the new value to the result.
1443 ///
1444 /// Returns the previous value.
1445 ///
1446 /// `fetch_not` takes an [`Ordering`] argument which describes the memory ordering
1447 /// of this operation. All ordering modes are possible. Note that using
1448 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
1449 /// using [`Release`] makes the load part [`Relaxed`].
1450 ///
1451 /// # Examples
1452 ///
1453 /// ```
1454 /// use portable_atomic::{AtomicBool, Ordering};
1455 ///
1456 /// let foo = AtomicBool::new(true);
1457 /// assert_eq!(foo.fetch_not(Ordering::SeqCst), true);
1458 /// assert_eq!(foo.load(Ordering::SeqCst), false);
1459 ///
1460 /// let foo = AtomicBool::new(false);
1461 /// assert_eq!(foo.fetch_not(Ordering::SeqCst), false);
1462 /// assert_eq!(foo.load(Ordering::SeqCst), true);
1463 /// ```
1464 #[inline]
1465 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1466 pub fn fetch_not(&self, order: Ordering) -> bool {
1467 self.fetch_xor(true, order)
1468 }
1469
1470 /// Logical "not" with a boolean value.
1471 ///
1472 /// Performs a logical "not" operation on the current value, and sets
1473 /// the new value to the result.
1474 ///
1475 /// Unlike `fetch_not`, this does not return the previous value.
1476 ///
1477 /// `not` takes an [`Ordering`] argument which describes the memory ordering
1478 /// of this operation. All ordering modes are possible. Note that using
1479 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
1480 /// using [`Release`] makes the load part [`Relaxed`].
1481 ///
1482 /// This function may generate more efficient code than `fetch_not` on some platforms.
1483 ///
1484 /// - x86/x86_64: `lock xor` instead of `cmpxchg` loop
1485 /// - MSP430: `xor` instead of disabling interrupts
1486 ///
1487 /// Note: On x86/x86_64, the use of either function should not usually
1488 /// affect the generated code, because LLVM can properly optimize the case
1489 /// where the result is unused.
1490 ///
1491 /// # Examples
1492 ///
1493 /// ```
1494 /// use portable_atomic::{AtomicBool, Ordering};
1495 ///
1496 /// let foo = AtomicBool::new(true);
1497 /// foo.not(Ordering::SeqCst);
1498 /// assert_eq!(foo.load(Ordering::SeqCst), false);
1499 ///
1500 /// let foo = AtomicBool::new(false);
1501 /// foo.not(Ordering::SeqCst);
1502 /// assert_eq!(foo.load(Ordering::SeqCst), true);
1503 /// ```
1504 #[inline]
1505 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1506 pub fn not(&self, order: Ordering) {
1507 self.xor(true, order);
1508 }
1509
1510 /// Fetches the value, and applies a function to it that returns an optional
1511 /// new value. Returns a `Result` of `Ok(previous_value)` if the function
1512 /// returned `Some(_)`, else `Err(previous_value)`.
1513 ///
1514 /// Note: This may call the function multiple times if the value has been
1515 /// changed from other threads in the meantime, as long as the function
1516 /// returns `Some(_)`, but the function will have been applied only once to
1517 /// the stored value.
1518 ///
1519 /// `fetch_update` takes two [`Ordering`] arguments to describe the memory
1520 /// ordering of this operation. The first describes the required ordering for
1521 /// when the operation finally succeeds while the second describes the
1522 /// required ordering for loads. These correspond to the success and failure
1523 /// orderings of [`compare_exchange`](Self::compare_exchange) respectively.
1524 ///
1525 /// Using [`Acquire`] as success ordering makes the store part of this
1526 /// operation [`Relaxed`], and using [`Release`] makes the final successful
1527 /// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`],
1528 /// [`Acquire`] or [`Relaxed`].
1529 ///
1530 /// # Considerations
1531 ///
1532 /// This method is not magic; it is not provided by the hardware.
1533 /// It is implemented in terms of [`compare_exchange_weak`](Self::compare_exchange_weak),
1534 /// and suffers from the same drawbacks.
1535 /// In particular, this method will not circumvent the [ABA Problem].
1536 ///
1537 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
1538 ///
1539 /// # Panics
1540 ///
1541 /// Panics if `fetch_order` is [`Release`], [`AcqRel`].
1542 ///
1543 /// # Examples
1544 ///
1545 /// ```
1546 /// use portable_atomic::{AtomicBool, Ordering};
1547 ///
1548 /// let x = AtomicBool::new(false);
1549 /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(false));
1550 /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(!x)), Ok(false));
1551 /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(!x)), Ok(true));
1552 /// assert_eq!(x.load(Ordering::SeqCst), false);
1553 /// ```
1554 #[inline]
1555 #[cfg_attr(
1556 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
1557 track_caller
1558 )]
1559 pub fn fetch_update<F>(
1560 &self,
1561 set_order: Ordering,
1562 fetch_order: Ordering,
1563 mut f: F,
1564 ) -> Result<bool, bool>
1565 where
1566 F: FnMut(bool) -> Option<bool>,
1567 {
1568 let mut prev = self.load(fetch_order);
1569 while let Some(next) = f(prev) {
1570 match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
1571 x @ Ok(_) => return x,
1572 Err(next_prev) => prev = next_prev,
1573 }
1574 }
1575 Err(prev)
1576 }
1577 } // cfg_has_atomic_cas_or_amo32!
1578
1579 const_fn! {
1580 // This function is actually `const fn`-compatible on Rust 1.32+,
1581 // but makes `const fn` only on Rust 1.58+ to match other atomic types.
1582 const_if: #[cfg(not(portable_atomic_no_const_raw_ptr_deref))];
1583 /// Returns a mutable pointer to the underlying [`bool`].
1584 ///
1585 /// Returning an `*mut` pointer from a shared reference to this atomic is
1586 /// safe because the atomic types work with interior mutability. Any use of
1587 /// the returned raw pointer requires an `unsafe` block and has to uphold
1588 /// the safety requirements. If there is concurrent access, note the following
1589 /// additional safety requirements:
1590 ///
1591 /// - If this atomic type is [lock-free](Self::is_lock_free), any concurrent
1592 /// operations on it must be atomic.
1593 /// - Otherwise, any concurrent operations on it must be compatible with
1594 /// operations performed by this atomic type.
1595 ///
1596 /// This is `const fn` on Rust 1.58+.
1597 #[inline]
1598 pub const fn as_ptr(&self) -> *mut bool {
1599 self.v.get() as *mut bool
1600 }
1601 }
1602
1603 #[inline(always)]
1604 fn as_atomic_u8(&self) -> &imp::AtomicU8 {
1605 // SAFETY: AtomicBool and imp::AtomicU8 have the same layout,
1606 // and both access data in the same way.
1607 unsafe { &*(self as *const Self as *const imp::AtomicU8) }
1608 }
1609}
1610// See https://github.com/taiki-e/portable-atomic/issues/180
1611#[cfg(not(feature = "require-cas"))]
1612cfg_no_atomic_cas! {
1613#[doc(hidden)]
1614#[allow(unused_variables, clippy::unused_self, clippy::extra_unused_lifetimes)]
1615impl<'a> AtomicBool {
1616 cfg_no_atomic_cas_or_amo32! {
1617 #[inline]
1618 pub fn swap(&self, val: bool, order: Ordering) -> bool
1619 where
1620 &'a Self: HasSwap,
1621 {
1622 unimplemented!()
1623 }
1624 #[inline]
1625 pub fn compare_exchange(
1626 &self,
1627 current: bool,
1628 new: bool,
1629 success: Ordering,
1630 failure: Ordering,
1631 ) -> Result<bool, bool>
1632 where
1633 &'a Self: HasCompareExchange,
1634 {
1635 unimplemented!()
1636 }
1637 #[inline]
1638 pub fn compare_exchange_weak(
1639 &self,
1640 current: bool,
1641 new: bool,
1642 success: Ordering,
1643 failure: Ordering,
1644 ) -> Result<bool, bool>
1645 where
1646 &'a Self: HasCompareExchangeWeak,
1647 {
1648 unimplemented!()
1649 }
1650 #[inline]
1651 pub fn fetch_and(&self, val: bool, order: Ordering) -> bool
1652 where
1653 &'a Self: HasFetchAnd,
1654 {
1655 unimplemented!()
1656 }
1657 #[inline]
1658 pub fn and(&self, val: bool, order: Ordering)
1659 where
1660 &'a Self: HasAnd,
1661 {
1662 unimplemented!()
1663 }
1664 #[inline]
1665 pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool
1666 where
1667 &'a Self: HasFetchNand,
1668 {
1669 unimplemented!()
1670 }
1671 #[inline]
1672 pub fn fetch_or(&self, val: bool, order: Ordering) -> bool
1673 where
1674 &'a Self: HasFetchOr,
1675 {
1676 unimplemented!()
1677 }
1678 #[inline]
1679 pub fn or(&self, val: bool, order: Ordering)
1680 where
1681 &'a Self: HasOr,
1682 {
1683 unimplemented!()
1684 }
1685 #[inline]
1686 pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool
1687 where
1688 &'a Self: HasFetchXor,
1689 {
1690 unimplemented!()
1691 }
1692 #[inline]
1693 pub fn xor(&self, val: bool, order: Ordering)
1694 where
1695 &'a Self: HasXor,
1696 {
1697 unimplemented!()
1698 }
1699 #[inline]
1700 pub fn fetch_not(&self, order: Ordering) -> bool
1701 where
1702 &'a Self: HasFetchNot,
1703 {
1704 unimplemented!()
1705 }
1706 #[inline]
1707 pub fn not(&self, order: Ordering)
1708 where
1709 &'a Self: HasNot,
1710 {
1711 unimplemented!()
1712 }
1713 #[inline]
1714 pub fn fetch_update<F>(
1715 &self,
1716 set_order: Ordering,
1717 fetch_order: Ordering,
1718 f: F,
1719 ) -> Result<bool, bool>
1720 where
1721 F: FnMut(bool) -> Option<bool>,
1722 &'a Self: HasFetchUpdate,
1723 {
1724 unimplemented!()
1725 }
1726 } // cfg_no_atomic_cas_or_amo32!
1727}
1728} // cfg_no_atomic_cas!
1729} // cfg_has_atomic_8!
1730
1731cfg_has_atomic_ptr! {
1732/// A raw pointer type which can be safely shared between threads.
1733///
1734/// This type has the same in-memory representation as a `*mut T`.
1735///
1736/// If the compiler and the platform support atomic loads and stores of pointers,
1737/// this type is a wrapper for the standard library's
1738/// [`AtomicPtr`](core::sync::atomic::AtomicPtr). If the platform supports it
1739/// but the compiler does not, atomic operations are implemented using inline
1740/// assembly.
1741// We can use #[repr(transparent)] here, but #[repr(C, align(N))]
1742// will show clearer docs.
1743#[cfg_attr(target_pointer_width = "16", repr(C, align(2)))]
1744#[cfg_attr(target_pointer_width = "32", repr(C, align(4)))]
1745#[cfg_attr(target_pointer_width = "64", repr(C, align(8)))]
1746#[cfg_attr(target_pointer_width = "128", repr(C, align(16)))]
1747pub struct AtomicPtr<T> {
1748 inner: imp::AtomicPtr<T>,
1749}
1750
1751impl<T> Default for AtomicPtr<T> {
1752 /// Creates a null `AtomicPtr<T>`.
1753 #[inline]
1754 fn default() -> Self {
1755 Self::new(ptr::null_mut())
1756 }
1757}
1758
1759impl<T> From<*mut T> for AtomicPtr<T> {
1760 #[inline]
1761 fn from(p: *mut T) -> Self {
1762 Self::new(p)
1763 }
1764}
1765
1766impl<T> fmt::Debug for AtomicPtr<T> {
1767 #[inline] // fmt is not hot path, but #[inline] on fmt seems to still be useful: https://github.com/rust-lang/rust/pull/117727
1768 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1769 // std atomic types use Relaxed in Debug::fmt: https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/sync/atomic.rs#L2188
1770 fmt::Debug::fmt(&self.load(Ordering::Relaxed), f)
1771 }
1772}
1773
1774impl<T> fmt::Pointer for AtomicPtr<T> {
1775 #[inline] // fmt is not hot path, but #[inline] on fmt seems to still be useful: https://github.com/rust-lang/rust/pull/117727
1776 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1777 // std atomic types use Relaxed in Debug::fmt: https://github.com/rust-lang/rust/blob/1.84.0/library/core/src/sync/atomic.rs#L2188
1778 fmt::Pointer::fmt(&self.load(Ordering::Relaxed), f)
1779 }
1780}
1781
1782// UnwindSafe is implicitly implemented.
1783#[cfg(not(portable_atomic_no_core_unwind_safe))]
1784impl<T> core::panic::RefUnwindSafe for AtomicPtr<T> {}
1785#[cfg(all(portable_atomic_no_core_unwind_safe, feature = "std"))]
1786impl<T> std::panic::RefUnwindSafe for AtomicPtr<T> {}
1787
1788impl<T> AtomicPtr<T> {
1789 /// Creates a new `AtomicPtr`.
1790 ///
1791 /// # Examples
1792 ///
1793 /// ```
1794 /// use portable_atomic::AtomicPtr;
1795 ///
1796 /// let ptr = &mut 5;
1797 /// let atomic_ptr = AtomicPtr::new(ptr);
1798 /// ```
1799 #[inline]
1800 #[must_use]
1801 pub const fn new(p: *mut T) -> Self {
1802 static_assert_layout!(AtomicPtr<()>, *mut ());
1803 Self { inner: imp::AtomicPtr::new(p) }
1804 }
1805
1806 // TODO: update docs based on https://github.com/rust-lang/rust/pull/116762
1807 const_fn! {
1808 const_if: #[cfg(not(portable_atomic_no_const_mut_refs))];
1809 /// Creates a new `AtomicPtr` from a pointer.
1810 ///
1811 /// This is `const fn` on Rust 1.83+.
1812 ///
1813 /// # Safety
1814 ///
1815 /// * `ptr` must be aligned to `align_of::<AtomicPtr<T>>()` (note that on some platforms this
1816 /// can be bigger than `align_of::<*mut T>()`).
1817 /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
1818 /// * If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
1819 /// behind `ptr` must have a happens-before relationship with atomic accesses via the returned
1820 /// value (or vice-versa).
1821 /// * In other words, time periods where the value is accessed atomically may not overlap
1822 /// with periods where the value is accessed non-atomically.
1823 /// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the
1824 /// duration of lifetime `'a`. Most use cases should be able to follow this guideline.
1825 /// * This requirement is also trivially satisfied if all accesses (atomic or not) are done
1826 /// from the same thread.
1827 /// * If this atomic type is *not* lock-free:
1828 /// * Any accesses to the value behind `ptr` must have a happens-before relationship
1829 /// with accesses via the returned value (or vice-versa).
1830 /// * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
1831 /// be compatible with operations performed by this atomic type.
1832 /// * This method must not be used to create overlapping or mixed-size atomic accesses, as
1833 /// these are not supported by the memory model.
1834 ///
1835 /// [valid]: core::ptr#safety
1836 #[inline]
1837 #[must_use]
1838 pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a Self {
1839 #[allow(clippy::cast_ptr_alignment)]
1840 // SAFETY: guaranteed by the caller
1841 unsafe { &*(ptr as *mut Self) }
1842 }
1843 }
1844
1845 /// Returns `true` if operations on values of this type are lock-free.
1846 ///
1847 /// If the compiler or the platform doesn't support the necessary
1848 /// atomic instructions, global locks for every potentially
1849 /// concurrent atomic operation will be used.
1850 ///
1851 /// This function is guaranteed to always return the same result.
1852 ///
1853 /// # Examples
1854 ///
1855 /// ```
1856 /// use portable_atomic::AtomicPtr;
1857 ///
1858 /// let is_lock_free = AtomicPtr::<()>::is_lock_free();
1859 /// ```
1860 #[inline]
1861 #[must_use]
1862 pub fn is_lock_free() -> bool {
1863 <imp::AtomicPtr<T>>::is_lock_free()
1864 }
1865
1866 /// Returns `true` if operations on values of this type are lock-free.
1867 ///
1868 /// If the compiler or the platform doesn't support the necessary
1869 /// atomic instructions, global locks for every potentially
1870 /// concurrent atomic operation will be used.
1871 ///
1872 /// **Note:** If the atomic operation relies on dynamic CPU feature detection,
1873 /// this type may be lock-free even if the function returns false.
1874 ///
1875 /// # Examples
1876 ///
1877 /// ```
1878 /// use portable_atomic::AtomicPtr;
1879 ///
1880 /// const IS_ALWAYS_LOCK_FREE: bool = AtomicPtr::<()>::is_always_lock_free();
1881 /// ```
1882 #[inline]
1883 #[must_use]
1884 pub const fn is_always_lock_free() -> bool {
1885 <imp::AtomicPtr<T>>::IS_ALWAYS_LOCK_FREE
1886 }
1887 #[cfg(test)]
1888 const IS_ALWAYS_LOCK_FREE: bool = Self::is_always_lock_free();
1889
1890 const_fn! {
1891 const_if: #[cfg(not(portable_atomic_no_const_mut_refs))];
1892 /// Returns a mutable reference to the underlying pointer.
1893 ///
1894 /// This is safe because the mutable reference guarantees that no other threads are
1895 /// concurrently accessing the atomic data.
1896 ///
1897 /// This is `const fn` on Rust 1.83+.
1898 ///
1899 /// # Examples
1900 ///
1901 /// ```
1902 /// use portable_atomic::{AtomicPtr, Ordering};
1903 ///
1904 /// let mut data = 10;
1905 /// let mut atomic_ptr = AtomicPtr::new(&mut data);
1906 /// let mut other_data = 5;
1907 /// *atomic_ptr.get_mut() = &mut other_data;
1908 /// assert_eq!(unsafe { *atomic_ptr.load(Ordering::SeqCst) }, 5);
1909 /// ```
1910 #[inline]
1911 pub const fn get_mut(&mut self) -> &mut *mut T {
1912 // SAFETY: the mutable reference guarantees unique ownership.
1913 // (core::sync::atomic::Atomic*::get_mut is not const yet)
1914 unsafe { &mut *self.as_ptr() }
1915 }
1916 }
1917
1918 // TODO: Add from_mut/get_mut_slice/from_mut_slice once it is stable on std atomic types.
1919 // https://github.com/rust-lang/rust/issues/76314
1920
1921 const_fn! {
1922 const_if: #[cfg(not(portable_atomic_no_const_transmute))];
1923 /// Consumes the atomic and returns the contained value.
1924 ///
1925 /// This is safe because passing `self` by value guarantees that no other threads are
1926 /// concurrently accessing the atomic data.
1927 ///
1928 /// This is `const fn` on Rust 1.56+.
1929 ///
1930 /// # Examples
1931 ///
1932 /// ```
1933 /// use portable_atomic::AtomicPtr;
1934 ///
1935 /// let mut data = 5;
1936 /// let atomic_ptr = AtomicPtr::new(&mut data);
1937 /// assert_eq!(unsafe { *atomic_ptr.into_inner() }, 5);
1938 /// ```
1939 #[inline]
1940 pub const fn into_inner(self) -> *mut T {
1941 // SAFETY: AtomicPtr<T> and *mut T have the same size and in-memory representations,
1942 // so they can be safely transmuted.
1943 // (const UnsafeCell::into_inner is unstable)
1944 unsafe { core::mem::transmute(self) }
1945 }
1946 }
1947
1948 /// Loads a value from the pointer.
1949 ///
1950 /// `load` takes an [`Ordering`] argument which describes the memory ordering
1951 /// of this operation. Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
1952 ///
1953 /// # Panics
1954 ///
1955 /// Panics if `order` is [`Release`] or [`AcqRel`].
1956 ///
1957 /// # Examples
1958 ///
1959 /// ```
1960 /// use portable_atomic::{AtomicPtr, Ordering};
1961 ///
1962 /// let ptr = &mut 5;
1963 /// let some_ptr = AtomicPtr::new(ptr);
1964 ///
1965 /// let value = some_ptr.load(Ordering::Relaxed);
1966 /// ```
1967 #[inline]
1968 #[cfg_attr(
1969 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
1970 track_caller
1971 )]
1972 pub fn load(&self, order: Ordering) -> *mut T {
1973 self.inner.load(order)
1974 }
1975
1976 /// Stores a value into the pointer.
1977 ///
1978 /// `store` takes an [`Ordering`] argument which describes the memory ordering
1979 /// of this operation. Possible values are [`SeqCst`], [`Release`] and [`Relaxed`].
1980 ///
1981 /// # Panics
1982 ///
1983 /// Panics if `order` is [`Acquire`] or [`AcqRel`].
1984 ///
1985 /// # Examples
1986 ///
1987 /// ```
1988 /// use portable_atomic::{AtomicPtr, Ordering};
1989 ///
1990 /// let ptr = &mut 5;
1991 /// let some_ptr = AtomicPtr::new(ptr);
1992 ///
1993 /// let other_ptr = &mut 10;
1994 ///
1995 /// some_ptr.store(other_ptr, Ordering::Relaxed);
1996 /// ```
1997 #[inline]
1998 #[cfg_attr(
1999 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
2000 track_caller
2001 )]
2002 pub fn store(&self, ptr: *mut T, order: Ordering) {
2003 self.inner.store(ptr, order);
2004 }
2005
2006 cfg_has_atomic_cas_or_amo32! {
2007 /// Stores a value into the pointer, returning the previous value.
2008 ///
2009 /// `swap` takes an [`Ordering`] argument which describes the memory ordering
2010 /// of this operation. All ordering modes are possible. Note that using
2011 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
2012 /// using [`Release`] makes the load part [`Relaxed`].
2013 ///
2014 /// # Examples
2015 ///
2016 /// ```
2017 /// use portable_atomic::{AtomicPtr, Ordering};
2018 ///
2019 /// let ptr = &mut 5;
2020 /// let some_ptr = AtomicPtr::new(ptr);
2021 ///
2022 /// let other_ptr = &mut 10;
2023 ///
2024 /// let value = some_ptr.swap(other_ptr, Ordering::Relaxed);
2025 /// ```
2026 #[inline]
2027 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
2028 pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
2029 self.inner.swap(ptr, order)
2030 }
2031
2032 cfg_has_atomic_cas! {
2033 /// Stores a value into the pointer if the current value is the same as the `current` value.
2034 ///
2035 /// The return value is a result indicating whether the new value was written and containing
2036 /// the previous value. On success this value is guaranteed to be equal to `current`.
2037 ///
2038 /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
2039 /// ordering of this operation. `success` describes the required ordering for the
2040 /// read-modify-write operation that takes place if the comparison with `current` succeeds.
2041 /// `failure` describes the required ordering for the load operation that takes place when
2042 /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
2043 /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
2044 /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
2045 ///
2046 /// # Panics
2047 ///
2048 /// Panics if `failure` is [`Release`], [`AcqRel`].
2049 ///
2050 /// # Examples
2051 ///
2052 /// ```
2053 /// use portable_atomic::{AtomicPtr, Ordering};
2054 ///
2055 /// let ptr = &mut 5;
2056 /// let some_ptr = AtomicPtr::new(ptr);
2057 ///
2058 /// let other_ptr = &mut 10;
2059 ///
2060 /// let value = some_ptr.compare_exchange(ptr, other_ptr, Ordering::SeqCst, Ordering::Relaxed);
2061 /// ```
2062 #[cfg_attr(docsrs, doc(alias = "compare_and_swap"))]
2063 #[inline]
2064 #[cfg_attr(
2065 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
2066 track_caller
2067 )]
2068 pub fn compare_exchange(
2069 &self,
2070 current: *mut T,
2071 new: *mut T,
2072 success: Ordering,
2073 failure: Ordering,
2074 ) -> Result<*mut T, *mut T> {
2075 self.inner.compare_exchange(current, new, success, failure)
2076 }
2077
2078 /// Stores a value into the pointer if the current value is the same as the `current` value.
2079 ///
2080 /// Unlike [`AtomicPtr::compare_exchange`], this function is allowed to spuriously fail even when the
2081 /// comparison succeeds, which can result in more efficient code on some platforms. The
2082 /// return value is a result indicating whether the new value was written and containing the
2083 /// previous value.
2084 ///
2085 /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
2086 /// ordering of this operation. `success` describes the required ordering for the
2087 /// read-modify-write operation that takes place if the comparison with `current` succeeds.
2088 /// `failure` describes the required ordering for the load operation that takes place when
2089 /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
2090 /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
2091 /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
2092 ///
2093 /// # Panics
2094 ///
2095 /// Panics if `failure` is [`Release`], [`AcqRel`].
2096 ///
2097 /// # Examples
2098 ///
2099 /// ```
2100 /// use portable_atomic::{AtomicPtr, Ordering};
2101 ///
2102 /// let some_ptr = AtomicPtr::new(&mut 5);
2103 ///
2104 /// let new = &mut 10;
2105 /// let mut old = some_ptr.load(Ordering::Relaxed);
2106 /// loop {
2107 /// match some_ptr.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
2108 /// Ok(_) => break,
2109 /// Err(x) => old = x,
2110 /// }
2111 /// }
2112 /// ```
2113 #[cfg_attr(docsrs, doc(alias = "compare_and_swap"))]
2114 #[inline]
2115 #[cfg_attr(
2116 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
2117 track_caller
2118 )]
2119 pub fn compare_exchange_weak(
2120 &self,
2121 current: *mut T,
2122 new: *mut T,
2123 success: Ordering,
2124 failure: Ordering,
2125 ) -> Result<*mut T, *mut T> {
2126 self.inner.compare_exchange_weak(current, new, success, failure)
2127 }
2128
2129 /// Fetches the value, and applies a function to it that returns an optional
2130 /// new value. Returns a `Result` of `Ok(previous_value)` if the function
2131 /// returned `Some(_)`, else `Err(previous_value)`.
2132 ///
2133 /// Note: This may call the function multiple times if the value has been
2134 /// changed from other threads in the meantime, as long as the function
2135 /// returns `Some(_)`, but the function will have been applied only once to
2136 /// the stored value.
2137 ///
2138 /// `fetch_update` takes two [`Ordering`] arguments to describe the memory
2139 /// ordering of this operation. The first describes the required ordering for
2140 /// when the operation finally succeeds while the second describes the
2141 /// required ordering for loads. These correspond to the success and failure
2142 /// orderings of [`compare_exchange`](Self::compare_exchange) respectively.
2143 ///
2144 /// Using [`Acquire`] as success ordering makes the store part of this
2145 /// operation [`Relaxed`], and using [`Release`] makes the final successful
2146 /// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`],
2147 /// [`Acquire`] or [`Relaxed`].
2148 ///
2149 /// # Panics
2150 ///
2151 /// Panics if `fetch_order` is [`Release`], [`AcqRel`].
2152 ///
2153 /// # Considerations
2154 ///
2155 /// This method is not magic; it is not provided by the hardware.
2156 /// It is implemented in terms of [`compare_exchange_weak`](Self::compare_exchange_weak),
2157 /// and suffers from the same drawbacks.
2158 /// In particular, this method will not circumvent the [ABA Problem].
2159 ///
2160 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
2161 ///
2162 /// # Examples
2163 ///
2164 /// ```
2165 /// use portable_atomic::{AtomicPtr, Ordering};
2166 ///
2167 /// let ptr: *mut _ = &mut 5;
2168 /// let some_ptr = AtomicPtr::new(ptr);
2169 ///
2170 /// let new: *mut _ = &mut 10;
2171 /// assert_eq!(some_ptr.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(ptr));
2172 /// let result = some_ptr.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| {
2173 /// if x == ptr {
2174 /// Some(new)
2175 /// } else {
2176 /// None
2177 /// }
2178 /// });
2179 /// assert_eq!(result, Ok(ptr));
2180 /// assert_eq!(some_ptr.load(Ordering::SeqCst), new);
2181 /// ```
2182 #[inline]
2183 #[cfg_attr(
2184 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
2185 track_caller
2186 )]
2187 pub fn fetch_update<F>(
2188 &self,
2189 set_order: Ordering,
2190 fetch_order: Ordering,
2191 mut f: F,
2192 ) -> Result<*mut T, *mut T>
2193 where
2194 F: FnMut(*mut T) -> Option<*mut T>,
2195 {
2196 let mut prev = self.load(fetch_order);
2197 while let Some(next) = f(prev) {
2198 match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
2199 x @ Ok(_) => return x,
2200 Err(next_prev) => prev = next_prev,
2201 }
2202 }
2203 Err(prev)
2204 }
2205 } // cfg_has_atomic_cas!
2206
2207 /// Offsets the pointer's address by adding `val` (in units of `T`),
2208 /// returning the previous pointer.
2209 ///
2210 /// This is equivalent to using [`wrapping_add`] to atomically perform the
2211 /// equivalent of `ptr = ptr.wrapping_add(val);`.
2212 ///
2213 /// This method operates in units of `T`, which means that it cannot be used
2214 /// to offset the pointer by an amount which is not a multiple of
2215 /// `size_of::<T>()`. This can sometimes be inconvenient, as you may want to
2216 /// work with a deliberately misaligned pointer. In such cases, you may use
2217 /// the [`fetch_byte_add`](Self::fetch_byte_add) method instead.
2218 ///
2219 /// `fetch_ptr_add` takes an [`Ordering`] argument which describes the
2220 /// memory ordering of this operation. All ordering modes are possible. Note
2221 /// that using [`Acquire`] makes the store part of this operation
2222 /// [`Relaxed`], and using [`Release`] makes the load part [`Relaxed`].
2223 ///
2224 /// [`wrapping_add`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_add
2225 ///
2226 /// # Examples
2227 ///
2228 /// ```
2229 /// # #![allow(unstable_name_collisions)]
2230 /// # #[allow(unused_imports)] use sptr::Strict as _; // strict provenance polyfill for old rustc
2231 /// use portable_atomic::{AtomicPtr, Ordering};
2232 ///
2233 /// let atom = AtomicPtr::<i64>::new(core::ptr::null_mut());
2234 /// assert_eq!(atom.fetch_ptr_add(1, Ordering::Relaxed).addr(), 0);
2235 /// // Note: units of `size_of::<i64>()`.
2236 /// assert_eq!(atom.load(Ordering::Relaxed).addr(), 8);
2237 /// ```
2238 #[inline]
2239 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
2240 pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T {
2241 self.fetch_byte_add(val.wrapping_mul(core::mem::size_of::<T>()), order)
2242 }
2243
2244 /// Offsets the pointer's address by subtracting `val` (in units of `T`),
2245 /// returning the previous pointer.
2246 ///
2247 /// This is equivalent to using [`wrapping_sub`] to atomically perform the
2248 /// equivalent of `ptr = ptr.wrapping_sub(val);`.
2249 ///
2250 /// This method operates in units of `T`, which means that it cannot be used
2251 /// to offset the pointer by an amount which is not a multiple of
2252 /// `size_of::<T>()`. This can sometimes be inconvenient, as you may want to
2253 /// work with a deliberately misaligned pointer. In such cases, you may use
2254 /// the [`fetch_byte_sub`](Self::fetch_byte_sub) method instead.
2255 ///
2256 /// `fetch_ptr_sub` takes an [`Ordering`] argument which describes the memory
2257 /// ordering of this operation. All ordering modes are possible. Note that
2258 /// using [`Acquire`] makes the store part of this operation [`Relaxed`],
2259 /// and using [`Release`] makes the load part [`Relaxed`].
2260 ///
2261 /// [`wrapping_sub`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_sub
2262 ///
2263 /// # Examples
2264 ///
2265 /// ```
2266 /// use portable_atomic::{AtomicPtr, Ordering};
2267 ///
2268 /// let array = [1i32, 2i32];
2269 /// let atom = AtomicPtr::new(array.as_ptr().wrapping_add(1) as *mut _);
2270 ///
2271 /// assert!(core::ptr::eq(atom.fetch_ptr_sub(1, Ordering::Relaxed), &array[1]));
2272 /// assert!(core::ptr::eq(atom.load(Ordering::Relaxed), &array[0]));
2273 /// ```
2274 #[inline]
2275 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
2276 pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T {
2277 self.fetch_byte_sub(val.wrapping_mul(core::mem::size_of::<T>()), order)
2278 }
2279
2280 /// Offsets the pointer's address by adding `val` *bytes*, returning the
2281 /// previous pointer.
2282 ///
2283 /// This is equivalent to using [`wrapping_add`] and [`cast`] to atomically
2284 /// perform `ptr = ptr.cast::<u8>().wrapping_add(val).cast::<T>()`.
2285 ///
2286 /// `fetch_byte_add` takes an [`Ordering`] argument which describes the
2287 /// memory ordering of this operation. All ordering modes are possible. Note
2288 /// that using [`Acquire`] makes the store part of this operation
2289 /// [`Relaxed`], and using [`Release`] makes the load part [`Relaxed`].
2290 ///
2291 /// [`wrapping_add`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_add
2292 /// [`cast`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.cast
2293 ///
2294 /// # Examples
2295 ///
2296 /// ```
2297 /// # #![allow(unstable_name_collisions)]
2298 /// # #[allow(unused_imports)] use sptr::Strict as _; // strict provenance polyfill for old rustc
2299 /// use portable_atomic::{AtomicPtr, Ordering};
2300 ///
2301 /// let atom = AtomicPtr::<i64>::new(core::ptr::null_mut());
2302 /// assert_eq!(atom.fetch_byte_add(1, Ordering::Relaxed).addr(), 0);
2303 /// // Note: in units of bytes, not `size_of::<i64>()`.
2304 /// assert_eq!(atom.load(Ordering::Relaxed).addr(), 1);
2305 /// ```
2306 #[inline]
2307 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
2308 pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T {
2309 self.inner.fetch_byte_add(val, order)
2310 }
2311
2312 /// Offsets the pointer's address by subtracting `val` *bytes*, returning the
2313 /// previous pointer.
2314 ///
2315 /// This is equivalent to using [`wrapping_sub`] and [`cast`] to atomically
2316 /// perform `ptr = ptr.cast::<u8>().wrapping_sub(val).cast::<T>()`.
2317 ///
2318 /// `fetch_byte_sub` takes an [`Ordering`] argument which describes the
2319 /// memory ordering of this operation. All ordering modes are possible. Note
2320 /// that using [`Acquire`] makes the store part of this operation
2321 /// [`Relaxed`], and using [`Release`] makes the load part [`Relaxed`].
2322 ///
2323 /// [`wrapping_sub`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_sub
2324 /// [`cast`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.cast
2325 ///
2326 /// # Examples
2327 ///
2328 /// ```
2329 /// # #![allow(unstable_name_collisions)]
2330 /// # #[allow(unused_imports)] use sptr::Strict as _; // strict provenance polyfill for old rustc
2331 /// use portable_atomic::{AtomicPtr, Ordering};
2332 ///
2333 /// let atom = AtomicPtr::<i64>::new(sptr::invalid_mut(1));
2334 /// assert_eq!(atom.fetch_byte_sub(1, Ordering::Relaxed).addr(), 1);
2335 /// assert_eq!(atom.load(Ordering::Relaxed).addr(), 0);
2336 /// ```
2337 #[inline]
2338 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
2339 pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T {
2340 self.inner.fetch_byte_sub(val, order)
2341 }
2342
2343 /// Performs a bitwise "or" operation on the address of the current pointer,
2344 /// and the argument `val`, and stores a pointer with provenance of the
2345 /// current pointer and the resulting address.
2346 ///
2347 /// This is equivalent to using [`map_addr`] to atomically perform
2348 /// `ptr = ptr.map_addr(|a| a | val)`. This can be used in tagged
2349 /// pointer schemes to atomically set tag bits.
2350 ///
2351 /// **Caveat**: This operation returns the previous value. To compute the
2352 /// stored value without losing provenance, you may use [`map_addr`]. For
2353 /// example: `a.fetch_or(val).map_addr(|a| a | val)`.
2354 ///
2355 /// `fetch_or` takes an [`Ordering`] argument which describes the memory
2356 /// ordering of this operation. All ordering modes are possible. Note that
2357 /// using [`Acquire`] makes the store part of this operation [`Relaxed`],
2358 /// and using [`Release`] makes the load part [`Relaxed`].
2359 ///
2360 /// This API and its claimed semantics are part of the Strict Provenance
2361 /// experiment, see the [module documentation for `ptr`][core::ptr] for
2362 /// details.
2363 ///
2364 /// [`map_addr`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.map_addr
2365 ///
2366 /// # Examples
2367 ///
2368 /// ```
2369 /// # #![allow(unstable_name_collisions)]
2370 /// # #[allow(unused_imports)] use sptr::Strict as _; // strict provenance polyfill for old rustc
2371 /// use portable_atomic::{AtomicPtr, Ordering};
2372 ///
2373 /// let pointer = &mut 3i64 as *mut i64;
2374 ///
2375 /// let atom = AtomicPtr::<i64>::new(pointer);
2376 /// // Tag the bottom bit of the pointer.
2377 /// assert_eq!(atom.fetch_or(1, Ordering::Relaxed).addr() & 1, 0);
2378 /// // Extract and untag.
2379 /// let tagged = atom.load(Ordering::Relaxed);
2380 /// assert_eq!(tagged.addr() & 1, 1);
2381 /// assert_eq!(tagged.map_addr(|p| p & !1), pointer);
2382 /// ```
2383 #[inline]
2384 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
2385 pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T {
2386 self.inner.fetch_or(val, order)
2387 }
2388
2389 /// Performs a bitwise "and" operation on the address of the current
2390 /// pointer, and the argument `val`, and stores a pointer with provenance of
2391 /// the current pointer and the resulting address.
2392 ///
2393 /// This is equivalent to using [`map_addr`] to atomically perform
2394 /// `ptr = ptr.map_addr(|a| a & val)`. This can be used in tagged
2395 /// pointer schemes to atomically unset tag bits.
2396 ///
2397 /// **Caveat**: This operation returns the previous value. To compute the
2398 /// stored value without losing provenance, you may use [`map_addr`]. For
2399 /// example: `a.fetch_and(val).map_addr(|a| a & val)`.
2400 ///
2401 /// `fetch_and` takes an [`Ordering`] argument which describes the memory
2402 /// ordering of this operation. All ordering modes are possible. Note that
2403 /// using [`Acquire`] makes the store part of this operation [`Relaxed`],
2404 /// and using [`Release`] makes the load part [`Relaxed`].
2405 ///
2406 /// This API and its claimed semantics are part of the Strict Provenance
2407 /// experiment, see the [module documentation for `ptr`][core::ptr] for
2408 /// details.
2409 ///
2410 /// [`map_addr`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.map_addr
2411 ///
2412 /// # Examples
2413 ///
2414 /// ```
2415 /// # #![allow(unstable_name_collisions)]
2416 /// # #[allow(unused_imports)] use sptr::Strict as _; // strict provenance polyfill for old rustc
2417 /// use portable_atomic::{AtomicPtr, Ordering};
2418 ///
2419 /// let pointer = &mut 3i64 as *mut i64;
2420 /// // A tagged pointer
2421 /// let atom = AtomicPtr::<i64>::new(pointer.map_addr(|a| a | 1));
2422 /// assert_eq!(atom.fetch_or(1, Ordering::Relaxed).addr() & 1, 1);
2423 /// // Untag, and extract the previously tagged pointer.
2424 /// let untagged = atom.fetch_and(!1, Ordering::Relaxed).map_addr(|a| a & !1);
2425 /// assert_eq!(untagged, pointer);
2426 /// ```
2427 #[inline]
2428 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
2429 pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T {
2430 self.inner.fetch_and(val, order)
2431 }
2432
2433 /// Performs a bitwise "xor" operation on the address of the current
2434 /// pointer, and the argument `val`, and stores a pointer with provenance of
2435 /// the current pointer and the resulting address.
2436 ///
2437 /// This is equivalent to using [`map_addr`] to atomically perform
2438 /// `ptr = ptr.map_addr(|a| a ^ val)`. This can be used in tagged
2439 /// pointer schemes to atomically toggle tag bits.
2440 ///
2441 /// **Caveat**: This operation returns the previous value. To compute the
2442 /// stored value without losing provenance, you may use [`map_addr`]. For
2443 /// example: `a.fetch_xor(val).map_addr(|a| a ^ val)`.
2444 ///
2445 /// `fetch_xor` takes an [`Ordering`] argument which describes the memory
2446 /// ordering of this operation. All ordering modes are possible. Note that
2447 /// using [`Acquire`] makes the store part of this operation [`Relaxed`],
2448 /// and using [`Release`] makes the load part [`Relaxed`].
2449 ///
2450 /// This API and its claimed semantics are part of the Strict Provenance
2451 /// experiment, see the [module documentation for `ptr`][core::ptr] for
2452 /// details.
2453 ///
2454 /// [`map_addr`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.map_addr
2455 ///
2456 /// # Examples
2457 ///
2458 /// ```
2459 /// # #![allow(unstable_name_collisions)]
2460 /// # #[allow(unused_imports)] use sptr::Strict as _; // strict provenance polyfill for old rustc
2461 /// use portable_atomic::{AtomicPtr, Ordering};
2462 ///
2463 /// let pointer = &mut 3i64 as *mut i64;
2464 /// let atom = AtomicPtr::<i64>::new(pointer);
2465 ///
2466 /// // Toggle a tag bit on the pointer.
2467 /// atom.fetch_xor(1, Ordering::Relaxed);
2468 /// assert_eq!(atom.load(Ordering::Relaxed).addr() & 1, 1);
2469 /// ```
2470 #[inline]
2471 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
2472 pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T {
2473 self.inner.fetch_xor(val, order)
2474 }
2475
2476 /// Sets the bit at the specified bit-position to 1.
2477 ///
2478 /// Returns `true` if the specified bit was previously set to 1.
2479 ///
2480 /// `bit_set` takes an [`Ordering`] argument which describes the memory ordering
2481 /// of this operation. All ordering modes are possible. Note that using
2482 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
2483 /// using [`Release`] makes the load part [`Relaxed`].
2484 ///
2485 /// This corresponds to x86's `lock bts`, and the implementation calls them on x86/x86_64.
2486 ///
2487 /// # Examples
2488 ///
2489 /// ```
2490 /// # #![allow(unstable_name_collisions)]
2491 /// # #[allow(unused_imports)] use sptr::Strict as _; // strict provenance polyfill for old rustc
2492 /// use portable_atomic::{AtomicPtr, Ordering};
2493 ///
2494 /// let pointer = &mut 3i64 as *mut i64;
2495 ///
2496 /// let atom = AtomicPtr::<i64>::new(pointer);
2497 /// // Tag the bottom bit of the pointer.
2498 /// assert!(!atom.bit_set(0, Ordering::Relaxed));
2499 /// // Extract and untag.
2500 /// let tagged = atom.load(Ordering::Relaxed);
2501 /// assert_eq!(tagged.addr() & 1, 1);
2502 /// assert_eq!(tagged.map_addr(|p| p & !1), pointer);
2503 /// ```
2504 #[inline]
2505 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
2506 pub fn bit_set(&self, bit: u32, order: Ordering) -> bool {
2507 self.inner.bit_set(bit, order)
2508 }
2509
2510 /// Clears the bit at the specified bit-position to 0.
2511 ///
2512 /// Returns `true` if the specified bit was previously set to 1.
2513 ///
2514 /// `bit_clear` takes an [`Ordering`] argument which describes the memory ordering
2515 /// of this operation. All ordering modes are possible. Note that using
2516 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
2517 /// using [`Release`] makes the load part [`Relaxed`].
2518 ///
2519 /// This corresponds to x86's `lock btr`, and the implementation calls them on x86/x86_64.
2520 ///
2521 /// # Examples
2522 ///
2523 /// ```
2524 /// # #![allow(unstable_name_collisions)]
2525 /// # #[allow(unused_imports)] use sptr::Strict as _; // strict provenance polyfill for old rustc
2526 /// use portable_atomic::{AtomicPtr, Ordering};
2527 ///
2528 /// let pointer = &mut 3i64 as *mut i64;
2529 /// // A tagged pointer
2530 /// let atom = AtomicPtr::<i64>::new(pointer.map_addr(|a| a | 1));
2531 /// assert!(atom.bit_set(0, Ordering::Relaxed));
2532 /// // Untag
2533 /// assert!(atom.bit_clear(0, Ordering::Relaxed));
2534 /// ```
2535 #[inline]
2536 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
2537 pub fn bit_clear(&self, bit: u32, order: Ordering) -> bool {
2538 self.inner.bit_clear(bit, order)
2539 }
2540
2541 /// Toggles the bit at the specified bit-position.
2542 ///
2543 /// Returns `true` if the specified bit was previously set to 1.
2544 ///
2545 /// `bit_toggle` takes an [`Ordering`] argument which describes the memory ordering
2546 /// of this operation. All ordering modes are possible. Note that using
2547 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
2548 /// using [`Release`] makes the load part [`Relaxed`].
2549 ///
2550 /// This corresponds to x86's `lock btc`, and the implementation calls them on x86/x86_64.
2551 ///
2552 /// # Examples
2553 ///
2554 /// ```
2555 /// # #![allow(unstable_name_collisions)]
2556 /// # #[allow(unused_imports)] use sptr::Strict as _; // strict provenance polyfill for old rustc
2557 /// use portable_atomic::{AtomicPtr, Ordering};
2558 ///
2559 /// let pointer = &mut 3i64 as *mut i64;
2560 /// let atom = AtomicPtr::<i64>::new(pointer);
2561 ///
2562 /// // Toggle a tag bit on the pointer.
2563 /// atom.bit_toggle(0, Ordering::Relaxed);
2564 /// assert_eq!(atom.load(Ordering::Relaxed).addr() & 1, 1);
2565 /// ```
2566 #[inline]
2567 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
2568 pub fn bit_toggle(&self, bit: u32, order: Ordering) -> bool {
2569 self.inner.bit_toggle(bit, order)
2570 }
2571 } // cfg_has_atomic_cas_or_amo32!
2572
2573 const_fn! {
2574 const_if: #[cfg(not(portable_atomic_no_const_raw_ptr_deref))];
2575 /// Returns a mutable pointer to the underlying pointer.
2576 ///
2577 /// Returning an `*mut` pointer from a shared reference to this atomic is
2578 /// safe because the atomic types work with interior mutability. Any use of
2579 /// the returned raw pointer requires an `unsafe` block and has to uphold
2580 /// the safety requirements. If there is concurrent access, note the following
2581 /// additional safety requirements:
2582 ///
2583 /// - If this atomic type is [lock-free](Self::is_lock_free), any concurrent
2584 /// operations on it must be atomic.
2585 /// - Otherwise, any concurrent operations on it must be compatible with
2586 /// operations performed by this atomic type.
2587 ///
2588 /// This is `const fn` on Rust 1.58+.
2589 #[inline]
2590 pub const fn as_ptr(&self) -> *mut *mut T {
2591 self.inner.as_ptr()
2592 }
2593 }
2594}
2595// See https://github.com/taiki-e/portable-atomic/issues/180
2596#[cfg(not(feature = "require-cas"))]
2597cfg_no_atomic_cas! {
2598#[doc(hidden)]
2599#[allow(unused_variables, clippy::unused_self, clippy::extra_unused_lifetimes)]
2600impl<'a, T: 'a> AtomicPtr<T> {
2601 cfg_no_atomic_cas_or_amo32! {
2602 #[inline]
2603 pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T
2604 where
2605 &'a Self: HasSwap,
2606 {
2607 unimplemented!()
2608 }
2609 } // cfg_no_atomic_cas_or_amo32!
2610 #[inline]
2611 pub fn compare_exchange(
2612 &self,
2613 current: *mut T,
2614 new: *mut T,
2615 success: Ordering,
2616 failure: Ordering,
2617 ) -> Result<*mut T, *mut T>
2618 where
2619 &'a Self: HasCompareExchange,
2620 {
2621 unimplemented!()
2622 }
2623 #[inline]
2624 pub fn compare_exchange_weak(
2625 &self,
2626 current: *mut T,
2627 new: *mut T,
2628 success: Ordering,
2629 failure: Ordering,
2630 ) -> Result<*mut T, *mut T>
2631 where
2632 &'a Self: HasCompareExchangeWeak,
2633 {
2634 unimplemented!()
2635 }
2636 #[inline]
2637 pub fn fetch_update<F>(
2638 &self,
2639 set_order: Ordering,
2640 fetch_order: Ordering,
2641 f: F,
2642 ) -> Result<*mut T, *mut T>
2643 where
2644 F: FnMut(*mut T) -> Option<*mut T>,
2645 &'a Self: HasFetchUpdate,
2646 {
2647 unimplemented!()
2648 }
2649 cfg_no_atomic_cas_or_amo32! {
2650 #[inline]
2651 pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T
2652 where
2653 &'a Self: HasFetchPtrAdd,
2654 {
2655 unimplemented!()
2656 }
2657 #[inline]
2658 pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T
2659 where
2660 &'a Self: HasFetchPtrSub,
2661 {
2662 unimplemented!()
2663 }
2664 #[inline]
2665 pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T
2666 where
2667 &'a Self: HasFetchByteAdd,
2668 {
2669 unimplemented!()
2670 }
2671 #[inline]
2672 pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T
2673 where
2674 &'a Self: HasFetchByteSub,
2675 {
2676 unimplemented!()
2677 }
2678 #[inline]
2679 pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T
2680 where
2681 &'a Self: HasFetchOr,
2682 {
2683 unimplemented!()
2684 }
2685 #[inline]
2686 pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T
2687 where
2688 &'a Self: HasFetchAnd,
2689 {
2690 unimplemented!()
2691 }
2692 #[inline]
2693 pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T
2694 where
2695 &'a Self: HasFetchXor,
2696 {
2697 unimplemented!()
2698 }
2699 #[inline]
2700 pub fn bit_set(&self, bit: u32, order: Ordering) -> bool
2701 where
2702 &'a Self: HasBitSet,
2703 {
2704 unimplemented!()
2705 }
2706 #[inline]
2707 pub fn bit_clear(&self, bit: u32, order: Ordering) -> bool
2708 where
2709 &'a Self: HasBitClear,
2710 {
2711 unimplemented!()
2712 }
2713 #[inline]
2714 pub fn bit_toggle(&self, bit: u32, order: Ordering) -> bool
2715 where
2716 &'a Self: HasBitToggle,
2717 {
2718 unimplemented!()
2719 }
2720 } // cfg_no_atomic_cas_or_amo32!
2721}
2722} // cfg_no_atomic_cas!
2723} // cfg_has_atomic_ptr!
2724
2725macro_rules! atomic_int {
2726 // Atomic{I,U}* impls
2727 ($atomic_type:ident, $int_type:ident, $align:literal,
2728 $cfg_has_atomic_cas_or_amo32_or_8:ident, $cfg_no_atomic_cas_or_amo32_or_8:ident
2729 $(, #[$cfg_float:meta] $atomic_float_type:ident, $float_type:ident)?
2730 ) => {
2731 doc_comment! {
2732 concat!("An integer type which can be safely shared between threads.
2733
2734This type has the same in-memory representation as the underlying integer type,
2735[`", stringify!($int_type), "`].
2736
2737If the compiler and the platform support atomic loads and stores of [`", stringify!($int_type),
2738"`], this type is a wrapper for the standard library's `", stringify!($atomic_type),
2739"`. If the platform supports it but the compiler does not, atomic operations are implemented using
2740inline assembly. Otherwise synchronizes using global locks.
2741You can call [`", stringify!($atomic_type), "::is_lock_free()`] to check whether
2742atomic instructions or locks will be used.
2743"
2744 ),
2745 // We can use #[repr(transparent)] here, but #[repr(C, align(N))]
2746 // will show clearer docs.
2747 #[repr(C, align($align))]
2748 pub struct $atomic_type {
2749 inner: imp::$atomic_type,
2750 }
2751 }
2752
2753 impl Default for $atomic_type {
2754 #[inline]
2755 fn default() -> Self {
2756 Self::new($int_type::default())
2757 }
2758 }
2759
2760 impl From<$int_type> for $atomic_type {
2761 #[inline]
2762 fn from(v: $int_type) -> Self {
2763 Self::new(v)
2764 }
2765 }
2766
2767 // UnwindSafe is implicitly implemented.
2768 #[cfg(not(portable_atomic_no_core_unwind_safe))]
2769 impl core::panic::RefUnwindSafe for $atomic_type {}
2770 #[cfg(all(portable_atomic_no_core_unwind_safe, feature = "std"))]
2771 impl std::panic::RefUnwindSafe for $atomic_type {}
2772
2773 impl_debug_and_serde!($atomic_type);
2774
2775 impl $atomic_type {
2776 doc_comment! {
2777 concat!(
2778 "Creates a new atomic integer.
2779
2780# Examples
2781
2782```
2783use portable_atomic::", stringify!($atomic_type), ";
2784
2785let atomic_forty_two = ", stringify!($atomic_type), "::new(42);
2786```"
2787 ),
2788 #[inline]
2789 #[must_use]
2790 pub const fn new(v: $int_type) -> Self {
2791 static_assert_layout!($atomic_type, $int_type);
2792 Self { inner: imp::$atomic_type::new(v) }
2793 }
2794 }
2795
2796 // TODO: update docs based on https://github.com/rust-lang/rust/pull/116762
2797 #[cfg(not(portable_atomic_no_const_mut_refs))]
2798 doc_comment! {
2799 concat!("Creates a new reference to an atomic integer from a pointer.
2800
2801This is `const fn` on Rust 1.83+.
2802
2803# Safety
2804
2805* `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this
2806 can be bigger than `align_of::<", stringify!($int_type), ">()`).
2807* `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
2808* If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
2809 behind `ptr` must have a happens-before relationship with atomic accesses via
2810 the returned value (or vice-versa).
2811 * In other words, time periods where the value is accessed atomically may not
2812 overlap with periods where the value is accessed non-atomically.
2813 * This requirement is trivially satisfied if `ptr` is never used non-atomically
2814 for the duration of lifetime `'a`. Most use cases should be able to follow
2815 this guideline.
2816 * This requirement is also trivially satisfied if all accesses (atomic or not) are
2817 done from the same thread.
2818* If this atomic type is *not* lock-free:
2819 * Any accesses to the value behind `ptr` must have a happens-before relationship
2820 with accesses via the returned value (or vice-versa).
2821 * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
2822 be compatible with operations performed by this atomic type.
2823* This method must not be used to create overlapping or mixed-size atomic
2824 accesses, as these are not supported by the memory model.
2825
2826[valid]: core::ptr#safety"),
2827 #[inline]
2828 #[must_use]
2829 pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a Self {
2830 #[allow(clippy::cast_ptr_alignment)]
2831 // SAFETY: guaranteed by the caller
2832 unsafe { &*(ptr as *mut Self) }
2833 }
2834 }
2835 #[cfg(portable_atomic_no_const_mut_refs)]
2836 doc_comment! {
2837 concat!("Creates a new reference to an atomic integer from a pointer.
2838
2839This is `const fn` on Rust 1.83+.
2840
2841# Safety
2842
2843* `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this
2844 can be bigger than `align_of::<", stringify!($int_type), ">()`).
2845* `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
2846* If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
2847 behind `ptr` must have a happens-before relationship with atomic accesses via
2848 the returned value (or vice-versa).
2849 * In other words, time periods where the value is accessed atomically may not
2850 overlap with periods where the value is accessed non-atomically.
2851 * This requirement is trivially satisfied if `ptr` is never used non-atomically
2852 for the duration of lifetime `'a`. Most use cases should be able to follow
2853 this guideline.
2854 * This requirement is also trivially satisfied if all accesses (atomic or not) are
2855 done from the same thread.
2856* If this atomic type is *not* lock-free:
2857 * Any accesses to the value behind `ptr` must have a happens-before relationship
2858 with accesses via the returned value (or vice-versa).
2859 * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
2860 be compatible with operations performed by this atomic type.
2861* This method must not be used to create overlapping or mixed-size atomic
2862 accesses, as these are not supported by the memory model.
2863
2864[valid]: core::ptr#safety"),
2865 #[inline]
2866 #[must_use]
2867 pub unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a Self {
2868 #[allow(clippy::cast_ptr_alignment)]
2869 // SAFETY: guaranteed by the caller
2870 unsafe { &*(ptr as *mut Self) }
2871 }
2872 }
2873
2874 doc_comment! {
2875 concat!("Returns `true` if operations on values of this type are lock-free.
2876
2877If the compiler or the platform doesn't support the necessary
2878atomic instructions, global locks for every potentially
2879concurrent atomic operation will be used.
2880
2881This function is guaranteed to always return the same result.
2882
2883# Examples
2884
2885```
2886use portable_atomic::", stringify!($atomic_type), ";
2887
2888let is_lock_free = ", stringify!($atomic_type), "::is_lock_free();
2889```"),
2890 #[inline]
2891 #[must_use]
2892 pub fn is_lock_free() -> bool {
2893 <imp::$atomic_type>::is_lock_free()
2894 }
2895 }
2896
2897 doc_comment! {
2898 concat!("Returns `true` if operations on values of this type are lock-free.
2899
2900If the compiler or the platform doesn't support the necessary
2901atomic instructions, global locks for every potentially
2902concurrent atomic operation will be used.
2903
2904**Note:** If the atomic operation relies on dynamic CPU feature detection,
2905this type may be lock-free even if the function returns false.
2906
2907# Examples
2908
2909```
2910use portable_atomic::", stringify!($atomic_type), ";
2911
2912const IS_ALWAYS_LOCK_FREE: bool = ", stringify!($atomic_type), "::is_always_lock_free();
2913```"),
2914 #[inline]
2915 #[must_use]
2916 pub const fn is_always_lock_free() -> bool {
2917 <imp::$atomic_type>::IS_ALWAYS_LOCK_FREE
2918 }
2919 }
2920 #[cfg(test)]
2921 #[cfg_attr(all(valgrind, target_arch = "powerpc64"), allow(dead_code))] // TODO(powerpc64): Hang (as of Valgrind 3.26)
2922 const IS_ALWAYS_LOCK_FREE: bool = Self::is_always_lock_free();
2923
2924 #[cfg(not(portable_atomic_no_const_mut_refs))]
2925 doc_comment! {
2926 concat!("Returns a mutable reference to the underlying integer.\n
2927This is safe because the mutable reference guarantees that no other threads are
2928concurrently accessing the atomic data.
2929
2930This is `const fn` on Rust 1.83+.
2931
2932# Examples
2933
2934```
2935use portable_atomic::{", stringify!($atomic_type), ", Ordering};
2936
2937let mut some_var = ", stringify!($atomic_type), "::new(10);
2938assert_eq!(*some_var.get_mut(), 10);
2939*some_var.get_mut() = 5;
2940assert_eq!(some_var.load(Ordering::SeqCst), 5);
2941```"),
2942 #[inline]
2943 pub const fn get_mut(&mut self) -> &mut $int_type {
2944 // SAFETY: the mutable reference guarantees unique ownership.
2945 // (core::sync::atomic::Atomic*::get_mut is not const yet)
2946 unsafe { &mut *self.as_ptr() }
2947 }
2948 }
2949 #[cfg(portable_atomic_no_const_mut_refs)]
2950 doc_comment! {
2951 concat!("Returns a mutable reference to the underlying integer.\n
2952This is safe because the mutable reference guarantees that no other threads are
2953concurrently accessing the atomic data.
2954
2955This is `const fn` on Rust 1.83+.
2956
2957# Examples
2958
2959```
2960use portable_atomic::{", stringify!($atomic_type), ", Ordering};
2961
2962let mut some_var = ", stringify!($atomic_type), "::new(10);
2963assert_eq!(*some_var.get_mut(), 10);
2964*some_var.get_mut() = 5;
2965assert_eq!(some_var.load(Ordering::SeqCst), 5);
2966```"),
2967 #[inline]
2968 pub fn get_mut(&mut self) -> &mut $int_type {
2969 // SAFETY: the mutable reference guarantees unique ownership.
2970 unsafe { &mut *self.as_ptr() }
2971 }
2972 }
2973
2974 // TODO: Add from_mut/get_mut_slice/from_mut_slice once it is stable on std atomic types.
2975 // https://github.com/rust-lang/rust/issues/76314
2976
2977 #[cfg(not(portable_atomic_no_const_transmute))]
2978 doc_comment! {
2979 concat!("Consumes the atomic and returns the contained value.
2980
2981This is safe because passing `self` by value guarantees that no other threads are
2982concurrently accessing the atomic data.
2983
2984This is `const fn` on Rust 1.56+.
2985
2986# Examples
2987
2988```
2989use portable_atomic::", stringify!($atomic_type), ";
2990
2991let some_var = ", stringify!($atomic_type), "::new(5);
2992assert_eq!(some_var.into_inner(), 5);
2993```"),
2994 #[inline]
2995 pub const fn into_inner(self) -> $int_type {
2996 // SAFETY: $atomic_type and $int_type have the same size and in-memory representations,
2997 // so they can be safely transmuted.
2998 // (const UnsafeCell::into_inner is unstable)
2999 unsafe { core::mem::transmute(self) }
3000 }
3001 }
3002 #[cfg(portable_atomic_no_const_transmute)]
3003 doc_comment! {
3004 concat!("Consumes the atomic and returns the contained value.
3005
3006This is safe because passing `self` by value guarantees that no other threads are
3007concurrently accessing the atomic data.
3008
3009This is `const fn` on Rust 1.56+.
3010
3011# Examples
3012
3013```
3014use portable_atomic::", stringify!($atomic_type), ";
3015
3016let some_var = ", stringify!($atomic_type), "::new(5);
3017assert_eq!(some_var.into_inner(), 5);
3018```"),
3019 #[inline]
3020 pub fn into_inner(self) -> $int_type {
3021 // SAFETY: $atomic_type and $int_type have the same size and in-memory representations,
3022 // so they can be safely transmuted.
3023 // (const UnsafeCell::into_inner is unstable)
3024 unsafe { core::mem::transmute(self) }
3025 }
3026 }
3027
3028 doc_comment! {
3029 concat!("Loads a value from the atomic integer.
3030
3031`load` takes an [`Ordering`] argument which describes the memory ordering of this operation.
3032Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
3033
3034# Panics
3035
3036Panics if `order` is [`Release`] or [`AcqRel`].
3037
3038# Examples
3039
3040```
3041use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3042
3043let some_var = ", stringify!($atomic_type), "::new(5);
3044
3045assert_eq!(some_var.load(Ordering::Relaxed), 5);
3046```"),
3047 #[inline]
3048 #[cfg_attr(
3049 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
3050 track_caller
3051 )]
3052 pub fn load(&self, order: Ordering) -> $int_type {
3053 self.inner.load(order)
3054 }
3055 }
3056
3057 doc_comment! {
3058 concat!("Stores a value into the atomic integer.
3059
3060`store` takes an [`Ordering`] argument which describes the memory ordering of this operation.
3061Possible values are [`SeqCst`], [`Release`] and [`Relaxed`].
3062
3063# Panics
3064
3065Panics if `order` is [`Acquire`] or [`AcqRel`].
3066
3067# Examples
3068
3069```
3070use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3071
3072let some_var = ", stringify!($atomic_type), "::new(5);
3073
3074some_var.store(10, Ordering::Relaxed);
3075assert_eq!(some_var.load(Ordering::Relaxed), 10);
3076```"),
3077 #[inline]
3078 #[cfg_attr(
3079 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
3080 track_caller
3081 )]
3082 pub fn store(&self, val: $int_type, order: Ordering) {
3083 self.inner.store(val, order)
3084 }
3085 }
3086
3087 cfg_has_atomic_cas_or_amo32! {
3088 $cfg_has_atomic_cas_or_amo32_or_8! {
3089 doc_comment! {
3090 concat!("Stores a value into the atomic integer, returning the previous value.
3091
3092`swap` takes an [`Ordering`] argument which describes the memory ordering
3093of this operation. All ordering modes are possible. Note that using
3094[`Acquire`] makes the store part of this operation [`Relaxed`], and
3095using [`Release`] makes the load part [`Relaxed`].
3096
3097# Examples
3098
3099```
3100use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3101
3102let some_var = ", stringify!($atomic_type), "::new(5);
3103
3104assert_eq!(some_var.swap(10, Ordering::Relaxed), 5);
3105```"),
3106 #[inline]
3107 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3108 pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
3109 self.inner.swap(val, order)
3110 }
3111 }
3112 } // $cfg_has_atomic_cas_or_amo32_or_8!
3113
3114 cfg_has_atomic_cas! {
3115 doc_comment! {
3116 concat!("Stores a value into the atomic integer if the current value is the same as
3117the `current` value.
3118
3119The return value is a result indicating whether the new value was written and
3120containing the previous value. On success this value is guaranteed to be equal to
3121`current`.
3122
3123`compare_exchange` takes two [`Ordering`] arguments to describe the memory
3124ordering of this operation. `success` describes the required ordering for the
3125read-modify-write operation that takes place if the comparison with `current` succeeds.
3126`failure` describes the required ordering for the load operation that takes place when
3127the comparison fails. Using [`Acquire`] as success ordering makes the store part
3128of this operation [`Relaxed`], and using [`Release`] makes the successful load
3129[`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
3130
3131# Panics
3132
3133Panics if `failure` is [`Release`], [`AcqRel`].
3134
3135# Examples
3136
3137```
3138use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3139
3140let some_var = ", stringify!($atomic_type), "::new(5);
3141
3142assert_eq!(
3143 some_var.compare_exchange(5, 10, Ordering::Acquire, Ordering::Relaxed),
3144 Ok(5),
3145);
3146assert_eq!(some_var.load(Ordering::Relaxed), 10);
3147
3148assert_eq!(
3149 some_var.compare_exchange(6, 12, Ordering::SeqCst, Ordering::Acquire),
3150 Err(10),
3151);
3152assert_eq!(some_var.load(Ordering::Relaxed), 10);
3153```"),
3154 #[cfg_attr(docsrs, doc(alias = "compare_and_swap"))]
3155 #[inline]
3156 #[cfg_attr(
3157 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
3158 track_caller
3159 )]
3160 pub fn compare_exchange(
3161 &self,
3162 current: $int_type,
3163 new: $int_type,
3164 success: Ordering,
3165 failure: Ordering,
3166 ) -> Result<$int_type, $int_type> {
3167 self.inner.compare_exchange(current, new, success, failure)
3168 }
3169 }
3170
3171 doc_comment! {
3172 concat!("Stores a value into the atomic integer if the current value is the same as
3173the `current` value.
3174Unlike [`compare_exchange`](Self::compare_exchange)
3175this function is allowed to spuriously fail even
3176when the comparison succeeds, which can result in more efficient code on some
3177platforms. The return value is a result indicating whether the new value was
3178written and containing the previous value.
3179
3180`compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
3181ordering of this operation. `success` describes the required ordering for the
3182read-modify-write operation that takes place if the comparison with `current` succeeds.
3183`failure` describes the required ordering for the load operation that takes place when
3184the comparison fails. Using [`Acquire`] as success ordering makes the store part
3185of this operation [`Relaxed`], and using [`Release`] makes the successful load
3186[`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
3187
3188# Panics
3189
3190Panics if `failure` is [`Release`], [`AcqRel`].
3191
3192# Examples
3193
3194```
3195use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3196
3197let val = ", stringify!($atomic_type), "::new(4);
3198
3199let mut old = val.load(Ordering::Relaxed);
3200loop {
3201 let new = old * 2;
3202 match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
3203 Ok(_) => break,
3204 Err(x) => old = x,
3205 }
3206}
3207```"),
3208 #[cfg_attr(docsrs, doc(alias = "compare_and_swap"))]
3209 #[inline]
3210 #[cfg_attr(
3211 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
3212 track_caller
3213 )]
3214 pub fn compare_exchange_weak(
3215 &self,
3216 current: $int_type,
3217 new: $int_type,
3218 success: Ordering,
3219 failure: Ordering,
3220 ) -> Result<$int_type, $int_type> {
3221 self.inner.compare_exchange_weak(current, new, success, failure)
3222 }
3223 }
3224 } // cfg_has_atomic_cas!
3225
3226 $cfg_has_atomic_cas_or_amo32_or_8! {
3227 doc_comment! {
3228 concat!("Adds to the current value, returning the previous value.
3229
3230This operation wraps around on overflow.
3231
3232`fetch_add` takes an [`Ordering`] argument which describes the memory ordering
3233of this operation. All ordering modes are possible. Note that using
3234[`Acquire`] makes the store part of this operation [`Relaxed`], and
3235using [`Release`] makes the load part [`Relaxed`].
3236
3237# Examples
3238
3239```
3240use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3241
3242let foo = ", stringify!($atomic_type), "::new(0);
3243assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0);
3244assert_eq!(foo.load(Ordering::SeqCst), 10);
3245```"),
3246 #[inline]
3247 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3248 pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
3249 self.inner.fetch_add(val, order)
3250 }
3251 }
3252
3253 doc_comment! {
3254 concat!("Adds to the current value.
3255
3256This operation wraps around on overflow.
3257
3258Unlike `fetch_add`, this does not return the previous value.
3259
3260`add` takes an [`Ordering`] argument which describes the memory ordering
3261of this operation. All ordering modes are possible. Note that using
3262[`Acquire`] makes the store part of this operation [`Relaxed`], and
3263using [`Release`] makes the load part [`Relaxed`].
3264
3265This function may generate more efficient code than `fetch_add` on some platforms.
3266
3267- MSP430: `add` instead of disabling interrupts ({8,16}-bit atomics)
3268
3269# Examples
3270
3271```
3272use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3273
3274let foo = ", stringify!($atomic_type), "::new(0);
3275foo.add(10, Ordering::SeqCst);
3276assert_eq!(foo.load(Ordering::SeqCst), 10);
3277```"),
3278 #[inline]
3279 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3280 pub fn add(&self, val: $int_type, order: Ordering) {
3281 self.inner.add(val, order);
3282 }
3283 }
3284
3285 doc_comment! {
3286 concat!("Subtracts from the current value, returning the previous value.
3287
3288This operation wraps around on overflow.
3289
3290`fetch_sub` takes an [`Ordering`] argument which describes the memory ordering
3291of this operation. All ordering modes are possible. Note that using
3292[`Acquire`] makes the store part of this operation [`Relaxed`], and
3293using [`Release`] makes the load part [`Relaxed`].
3294
3295# Examples
3296
3297```
3298use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3299
3300let foo = ", stringify!($atomic_type), "::new(20);
3301assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 20);
3302assert_eq!(foo.load(Ordering::SeqCst), 10);
3303```"),
3304 #[inline]
3305 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3306 pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
3307 self.inner.fetch_sub(val, order)
3308 }
3309 }
3310
3311 doc_comment! {
3312 concat!("Subtracts from the current value.
3313
3314This operation wraps around on overflow.
3315
3316Unlike `fetch_sub`, this does not return the previous value.
3317
3318`sub` takes an [`Ordering`] argument which describes the memory ordering
3319of this operation. All ordering modes are possible. Note that using
3320[`Acquire`] makes the store part of this operation [`Relaxed`], and
3321using [`Release`] makes the load part [`Relaxed`].
3322
3323This function may generate more efficient code than `fetch_sub` on some platforms.
3324
3325- MSP430: `sub` instead of disabling interrupts ({8,16}-bit atomics)
3326
3327# Examples
3328
3329```
3330use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3331
3332let foo = ", stringify!($atomic_type), "::new(20);
3333foo.sub(10, Ordering::SeqCst);
3334assert_eq!(foo.load(Ordering::SeqCst), 10);
3335```"),
3336 #[inline]
3337 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3338 pub fn sub(&self, val: $int_type, order: Ordering) {
3339 self.inner.sub(val, order);
3340 }
3341 }
3342 } // $cfg_has_atomic_cas_or_amo32_or_8!
3343
3344 doc_comment! {
3345 concat!("Bitwise \"and\" with the current value.
3346
3347Performs a bitwise \"and\" operation on the current value and the argument `val`, and
3348sets the new value to the result.
3349
3350Returns the previous value.
3351
3352`fetch_and` takes an [`Ordering`] argument which describes the memory ordering
3353of this operation. All ordering modes are possible. Note that using
3354[`Acquire`] makes the store part of this operation [`Relaxed`], and
3355using [`Release`] makes the load part [`Relaxed`].
3356
3357# Examples
3358
3359```
3360use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3361
3362let foo = ", stringify!($atomic_type), "::new(0b101101);
3363assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
3364assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
3365```"),
3366 #[inline]
3367 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3368 pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
3369 self.inner.fetch_and(val, order)
3370 }
3371 }
3372
3373 doc_comment! {
3374 concat!("Bitwise \"and\" with the current value.
3375
3376Performs a bitwise \"and\" operation on the current value and the argument `val`, and
3377sets the new value to the result.
3378
3379Unlike `fetch_and`, this does not return the previous value.
3380
3381`and` takes an [`Ordering`] argument which describes the memory ordering
3382of this operation. All ordering modes are possible. Note that using
3383[`Acquire`] makes the store part of this operation [`Relaxed`], and
3384using [`Release`] makes the load part [`Relaxed`].
3385
3386This function may generate more efficient code than `fetch_and` on some platforms.
3387
3388- x86/x86_64: `lock and` instead of `cmpxchg` loop ({8,16,32}-bit atomics on x86, but additionally 64-bit atomics on x86_64)
3389- MSP430: `and` instead of disabling interrupts ({8,16}-bit atomics)
3390
3391Note: On x86/x86_64, the use of either function should not usually
3392affect the generated code, because LLVM can properly optimize the case
3393where the result is unused.
3394
3395# Examples
3396
3397```
3398use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3399
3400let foo = ", stringify!($atomic_type), "::new(0b101101);
3401assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
3402assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
3403```"),
3404 #[inline]
3405 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3406 pub fn and(&self, val: $int_type, order: Ordering) {
3407 self.inner.and(val, order);
3408 }
3409 }
3410
3411 cfg_has_atomic_cas! {
3412 doc_comment! {
3413 concat!("Bitwise \"nand\" with the current value.
3414
3415Performs a bitwise \"nand\" operation on the current value and the argument `val`, and
3416sets the new value to the result.
3417
3418Returns the previous value.
3419
3420`fetch_nand` takes an [`Ordering`] argument which describes the memory ordering
3421of this operation. All ordering modes are possible. Note that using
3422[`Acquire`] makes the store part of this operation [`Relaxed`], and
3423using [`Release`] makes the load part [`Relaxed`].
3424
3425# Examples
3426
3427```
3428use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3429
3430let foo = ", stringify!($atomic_type), "::new(0x13);
3431assert_eq!(foo.fetch_nand(0x31, Ordering::SeqCst), 0x13);
3432assert_eq!(foo.load(Ordering::SeqCst), !(0x13 & 0x31));
3433```"),
3434 #[inline]
3435 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3436 pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
3437 self.inner.fetch_nand(val, order)
3438 }
3439 }
3440 } // cfg_has_atomic_cas!
3441
3442 doc_comment! {
3443 concat!("Bitwise \"or\" with the current value.
3444
3445Performs a bitwise \"or\" operation on the current value and the argument `val`, and
3446sets the new value to the result.
3447
3448Returns the previous value.
3449
3450`fetch_or` takes an [`Ordering`] argument which describes the memory ordering
3451of this operation. All ordering modes are possible. Note that using
3452[`Acquire`] makes the store part of this operation [`Relaxed`], and
3453using [`Release`] makes the load part [`Relaxed`].
3454
3455# Examples
3456
3457```
3458use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3459
3460let foo = ", stringify!($atomic_type), "::new(0b101101);
3461assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
3462assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
3463```"),
3464 #[inline]
3465 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3466 pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
3467 self.inner.fetch_or(val, order)
3468 }
3469 }
3470
3471 doc_comment! {
3472 concat!("Bitwise \"or\" with the current value.
3473
3474Performs a bitwise \"or\" operation on the current value and the argument `val`, and
3475sets the new value to the result.
3476
3477Unlike `fetch_or`, this does not return the previous value.
3478
3479`or` takes an [`Ordering`] argument which describes the memory ordering
3480of this operation. All ordering modes are possible. Note that using
3481[`Acquire`] makes the store part of this operation [`Relaxed`], and
3482using [`Release`] makes the load part [`Relaxed`].
3483
3484This function may generate more efficient code than `fetch_or` on some platforms.
3485
3486- x86/x86_64: `lock or` instead of `cmpxchg` loop ({8,16,32}-bit atomics on x86, but additionally 64-bit atomics on x86_64)
3487- MSP430: `or` instead of disabling interrupts ({8,16}-bit atomics)
3488
3489Note: On x86/x86_64, the use of either function should not usually
3490affect the generated code, because LLVM can properly optimize the case
3491where the result is unused.
3492
3493# Examples
3494
3495```
3496use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3497
3498let foo = ", stringify!($atomic_type), "::new(0b101101);
3499assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
3500assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
3501```"),
3502 #[inline]
3503 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3504 pub fn or(&self, val: $int_type, order: Ordering) {
3505 self.inner.or(val, order);
3506 }
3507 }
3508
3509 doc_comment! {
3510 concat!("Bitwise \"xor\" with the current value.
3511
3512Performs a bitwise \"xor\" operation on the current value and the argument `val`, and
3513sets the new value to the result.
3514
3515Returns the previous value.
3516
3517`fetch_xor` takes an [`Ordering`] argument which describes the memory ordering
3518of this operation. All ordering modes are possible. Note that using
3519[`Acquire`] makes the store part of this operation [`Relaxed`], and
3520using [`Release`] makes the load part [`Relaxed`].
3521
3522# Examples
3523
3524```
3525use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3526
3527let foo = ", stringify!($atomic_type), "::new(0b101101);
3528assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
3529assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
3530```"),
3531 #[inline]
3532 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3533 pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
3534 self.inner.fetch_xor(val, order)
3535 }
3536 }
3537
3538 doc_comment! {
3539 concat!("Bitwise \"xor\" with the current value.
3540
3541Performs a bitwise \"xor\" operation on the current value and the argument `val`, and
3542sets the new value to the result.
3543
3544Unlike `fetch_xor`, this does not return the previous value.
3545
3546`xor` takes an [`Ordering`] argument which describes the memory ordering
3547of this operation. All ordering modes are possible. Note that using
3548[`Acquire`] makes the store part of this operation [`Relaxed`], and
3549using [`Release`] makes the load part [`Relaxed`].
3550
3551This function may generate more efficient code than `fetch_xor` on some platforms.
3552
3553- x86/x86_64: `lock xor` instead of `cmpxchg` loop ({8,16,32}-bit atomics on x86, but additionally 64-bit atomics on x86_64)
3554- MSP430: `xor` instead of disabling interrupts ({8,16}-bit atomics)
3555
3556Note: On x86/x86_64, the use of either function should not usually
3557affect the generated code, because LLVM can properly optimize the case
3558where the result is unused.
3559
3560# Examples
3561
3562```
3563use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3564
3565let foo = ", stringify!($atomic_type), "::new(0b101101);
3566foo.xor(0b110011, Ordering::SeqCst);
3567assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
3568```"),
3569 #[inline]
3570 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3571 pub fn xor(&self, val: $int_type, order: Ordering) {
3572 self.inner.xor(val, order);
3573 }
3574 }
3575
3576 cfg_has_atomic_cas! {
3577 doc_comment! {
3578 concat!("Fetches the value, and applies a function to it that returns an optional
3579new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
3580`Err(previous_value)`.
3581
3582Note: This may call the function multiple times if the value has been changed from other threads in
3583the meantime, as long as the function returns `Some(_)`, but the function will have been applied
3584only once to the stored value.
3585
3586`fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
3587The first describes the required ordering for when the operation finally succeeds while the second
3588describes the required ordering for loads. These correspond to the success and failure orderings of
3589[`compare_exchange`](Self::compare_exchange) respectively.
3590
3591Using [`Acquire`] as success ordering makes the store part
3592of this operation [`Relaxed`], and using [`Release`] makes the final successful load
3593[`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
3594
3595# Panics
3596
3597Panics if `fetch_order` is [`Release`], [`AcqRel`].
3598
3599# Considerations
3600
3601This method is not magic; it is not provided by the hardware.
3602It is implemented in terms of [`compare_exchange_weak`](Self::compare_exchange_weak),
3603and suffers from the same drawbacks.
3604In particular, this method will not circumvent the [ABA Problem].
3605
3606[ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
3607
3608# Examples
3609
3610```
3611use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3612
3613let x = ", stringify!($atomic_type), "::new(7);
3614assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7));
3615assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7));
3616assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8));
3617assert_eq!(x.load(Ordering::SeqCst), 9);
3618```"),
3619 #[inline]
3620 #[cfg_attr(
3621 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
3622 track_caller
3623 )]
3624 pub fn fetch_update<F>(
3625 &self,
3626 set_order: Ordering,
3627 fetch_order: Ordering,
3628 mut f: F,
3629 ) -> Result<$int_type, $int_type>
3630 where
3631 F: FnMut($int_type) -> Option<$int_type>,
3632 {
3633 let mut prev = self.load(fetch_order);
3634 while let Some(next) = f(prev) {
3635 match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
3636 x @ Ok(_) => return x,
3637 Err(next_prev) => prev = next_prev,
3638 }
3639 }
3640 Err(prev)
3641 }
3642 }
3643 } // cfg_has_atomic_cas!
3644
3645 $cfg_has_atomic_cas_or_amo32_or_8! {
3646 doc_comment! {
3647 concat!("Maximum with the current value.
3648
3649Finds the maximum of the current value and the argument `val`, and
3650sets the new value to the result.
3651
3652Returns the previous value.
3653
3654`fetch_max` takes an [`Ordering`] argument which describes the memory ordering
3655of this operation. All ordering modes are possible. Note that using
3656[`Acquire`] makes the store part of this operation [`Relaxed`], and
3657using [`Release`] makes the load part [`Relaxed`].
3658
3659# Examples
3660
3661```
3662use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3663
3664let foo = ", stringify!($atomic_type), "::new(23);
3665assert_eq!(foo.fetch_max(42, Ordering::SeqCst), 23);
3666assert_eq!(foo.load(Ordering::SeqCst), 42);
3667```
3668
3669If you want to obtain the maximum value in one step, you can use the following:
3670
3671```
3672use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3673
3674let foo = ", stringify!($atomic_type), "::new(23);
3675let bar = 42;
3676let max_foo = foo.fetch_max(bar, Ordering::SeqCst).max(bar);
3677assert!(max_foo == 42);
3678```"),
3679 #[inline]
3680 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3681 pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
3682 self.inner.fetch_max(val, order)
3683 }
3684 }
3685
3686 doc_comment! {
3687 concat!("Minimum with the current value.
3688
3689Finds the minimum of the current value and the argument `val`, and
3690sets the new value to the result.
3691
3692Returns the previous value.
3693
3694`fetch_min` takes an [`Ordering`] argument which describes the memory ordering
3695of this operation. All ordering modes are possible. Note that using
3696[`Acquire`] makes the store part of this operation [`Relaxed`], and
3697using [`Release`] makes the load part [`Relaxed`].
3698
3699# Examples
3700
3701```
3702use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3703
3704let foo = ", stringify!($atomic_type), "::new(23);
3705assert_eq!(foo.fetch_min(42, Ordering::Relaxed), 23);
3706assert_eq!(foo.load(Ordering::Relaxed), 23);
3707assert_eq!(foo.fetch_min(22, Ordering::Relaxed), 23);
3708assert_eq!(foo.load(Ordering::Relaxed), 22);
3709```
3710
3711If you want to obtain the minimum value in one step, you can use the following:
3712
3713```
3714use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3715
3716let foo = ", stringify!($atomic_type), "::new(23);
3717let bar = 12;
3718let min_foo = foo.fetch_min(bar, Ordering::SeqCst).min(bar);
3719assert_eq!(min_foo, 12);
3720```"),
3721 #[inline]
3722 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3723 pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
3724 self.inner.fetch_min(val, order)
3725 }
3726 }
3727 } // $cfg_has_atomic_cas_or_amo32_or_8!
3728
3729 doc_comment! {
3730 concat!("Sets the bit at the specified bit-position to 1.
3731
3732Returns `true` if the specified bit was previously set to 1.
3733
3734`bit_set` takes an [`Ordering`] argument which describes the memory ordering
3735of this operation. All ordering modes are possible. Note that using
3736[`Acquire`] makes the store part of this operation [`Relaxed`], and
3737using [`Release`] makes the load part [`Relaxed`].
3738
3739This corresponds to x86's `lock bts`, and the implementation calls them on x86/x86_64.
3740
3741# Examples
3742
3743```
3744use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3745
3746let foo = ", stringify!($atomic_type), "::new(0b0000);
3747assert!(!foo.bit_set(0, Ordering::Relaxed));
3748assert_eq!(foo.load(Ordering::Relaxed), 0b0001);
3749assert!(foo.bit_set(0, Ordering::Relaxed));
3750assert_eq!(foo.load(Ordering::Relaxed), 0b0001);
3751```"),
3752 #[inline]
3753 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3754 pub fn bit_set(&self, bit: u32, order: Ordering) -> bool {
3755 self.inner.bit_set(bit, order)
3756 }
3757 }
3758
3759 doc_comment! {
3760 concat!("Clears the bit at the specified bit-position to 0.
3761
3762Returns `true` if the specified bit was previously set to 1.
3763
3764`bit_clear` takes an [`Ordering`] argument which describes the memory ordering
3765of this operation. All ordering modes are possible. Note that using
3766[`Acquire`] makes the store part of this operation [`Relaxed`], and
3767using [`Release`] makes the load part [`Relaxed`].
3768
3769This corresponds to x86's `lock btr`, and the implementation calls them on x86/x86_64.
3770
3771# Examples
3772
3773```
3774use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3775
3776let foo = ", stringify!($atomic_type), "::new(0b0001);
3777assert!(foo.bit_clear(0, Ordering::Relaxed));
3778assert_eq!(foo.load(Ordering::Relaxed), 0b0000);
3779```"),
3780 #[inline]
3781 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3782 pub fn bit_clear(&self, bit: u32, order: Ordering) -> bool {
3783 self.inner.bit_clear(bit, order)
3784 }
3785 }
3786
3787 doc_comment! {
3788 concat!("Toggles the bit at the specified bit-position.
3789
3790Returns `true` if the specified bit was previously set to 1.
3791
3792`bit_toggle` takes an [`Ordering`] argument which describes the memory ordering
3793of this operation. All ordering modes are possible. Note that using
3794[`Acquire`] makes the store part of this operation [`Relaxed`], and
3795using [`Release`] makes the load part [`Relaxed`].
3796
3797This corresponds to x86's `lock btc`, and the implementation calls them on x86/x86_64.
3798
3799# Examples
3800
3801```
3802use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3803
3804let foo = ", stringify!($atomic_type), "::new(0b0000);
3805assert!(!foo.bit_toggle(0, Ordering::Relaxed));
3806assert_eq!(foo.load(Ordering::Relaxed), 0b0001);
3807assert!(foo.bit_toggle(0, Ordering::Relaxed));
3808assert_eq!(foo.load(Ordering::Relaxed), 0b0000);
3809```"),
3810 #[inline]
3811 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3812 pub fn bit_toggle(&self, bit: u32, order: Ordering) -> bool {
3813 self.inner.bit_toggle(bit, order)
3814 }
3815 }
3816
3817 doc_comment! {
3818 concat!("Logical negates the current value, and sets the new value to the result.
3819
3820Returns the previous value.
3821
3822`fetch_not` takes an [`Ordering`] argument which describes the memory ordering
3823of this operation. All ordering modes are possible. Note that using
3824[`Acquire`] makes the store part of this operation [`Relaxed`], and
3825using [`Release`] makes the load part [`Relaxed`].
3826
3827# Examples
3828
3829```
3830use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3831
3832let foo = ", stringify!($atomic_type), "::new(0);
3833assert_eq!(foo.fetch_not(Ordering::Relaxed), 0);
3834assert_eq!(foo.load(Ordering::Relaxed), !0);
3835```"),
3836 #[inline]
3837 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3838 pub fn fetch_not(&self, order: Ordering) -> $int_type {
3839 self.inner.fetch_not(order)
3840 }
3841 }
3842
3843 doc_comment! {
3844 concat!("Logical negates the current value, and sets the new value to the result.
3845
3846Unlike `fetch_not`, this does not return the previous value.
3847
3848`not` takes an [`Ordering`] argument which describes the memory ordering
3849of this operation. All ordering modes are possible. Note that using
3850[`Acquire`] makes the store part of this operation [`Relaxed`], and
3851using [`Release`] makes the load part [`Relaxed`].
3852
3853This function may generate more efficient code than `fetch_not` on some platforms.
3854
3855- x86/x86_64: `lock not` instead of `cmpxchg` loop ({8,16,32}-bit atomics on x86, but additionally 64-bit atomics on x86_64)
3856- MSP430: `inv` instead of disabling interrupts ({8,16}-bit atomics)
3857
3858# Examples
3859
3860```
3861use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3862
3863let foo = ", stringify!($atomic_type), "::new(0);
3864foo.not(Ordering::Relaxed);
3865assert_eq!(foo.load(Ordering::Relaxed), !0);
3866```"),
3867 #[inline]
3868 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3869 pub fn not(&self, order: Ordering) {
3870 self.inner.not(order);
3871 }
3872 }
3873
3874 cfg_has_atomic_cas! {
3875 doc_comment! {
3876 concat!("Negates the current value, and sets the new value to the result.
3877
3878Returns the previous value.
3879
3880`fetch_neg` takes an [`Ordering`] argument which describes the memory ordering
3881of this operation. All ordering modes are possible. Note that using
3882[`Acquire`] makes the store part of this operation [`Relaxed`], and
3883using [`Release`] makes the load part [`Relaxed`].
3884
3885# Examples
3886
3887```
3888use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3889
3890let foo = ", stringify!($atomic_type), "::new(5);
3891assert_eq!(foo.fetch_neg(Ordering::Relaxed), 5);
3892assert_eq!(foo.load(Ordering::Relaxed), 5_", stringify!($int_type), ".wrapping_neg());
3893assert_eq!(foo.fetch_neg(Ordering::Relaxed), 5_", stringify!($int_type), ".wrapping_neg());
3894assert_eq!(foo.load(Ordering::Relaxed), 5);
3895```"),
3896 #[inline]
3897 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3898 pub fn fetch_neg(&self, order: Ordering) -> $int_type {
3899 self.inner.fetch_neg(order)
3900 }
3901 }
3902
3903 doc_comment! {
3904 concat!("Negates the current value, and sets the new value to the result.
3905
3906Unlike `fetch_neg`, this does not return the previous value.
3907
3908`neg` takes an [`Ordering`] argument which describes the memory ordering
3909of this operation. All ordering modes are possible. Note that using
3910[`Acquire`] makes the store part of this operation [`Relaxed`], and
3911using [`Release`] makes the load part [`Relaxed`].
3912
3913This function may generate more efficient code than `fetch_neg` on some platforms.
3914
3915- x86/x86_64: `lock neg` instead of `cmpxchg` loop ({8,16,32}-bit atomics on x86, but additionally 64-bit atomics on x86_64)
3916
3917# Examples
3918
3919```
3920use portable_atomic::{", stringify!($atomic_type), ", Ordering};
3921
3922let foo = ", stringify!($atomic_type), "::new(5);
3923foo.neg(Ordering::Relaxed);
3924assert_eq!(foo.load(Ordering::Relaxed), 5_", stringify!($int_type), ".wrapping_neg());
3925foo.neg(Ordering::Relaxed);
3926assert_eq!(foo.load(Ordering::Relaxed), 5);
3927```"),
3928 #[inline]
3929 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3930 pub fn neg(&self, order: Ordering) {
3931 self.inner.neg(order);
3932 }
3933 }
3934 } // cfg_has_atomic_cas!
3935 } // cfg_has_atomic_cas_or_amo32!
3936
3937 const_fn! {
3938 const_if: #[cfg(not(portable_atomic_no_const_raw_ptr_deref))];
3939 /// Returns a mutable pointer to the underlying integer.
3940 ///
3941 /// Returning an `*mut` pointer from a shared reference to this atomic is
3942 /// safe because the atomic types work with interior mutability. Any use of
3943 /// the returned raw pointer requires an `unsafe` block and has to uphold
3944 /// the safety requirements. If there is concurrent access, note the following
3945 /// additional safety requirements:
3946 ///
3947 /// - If this atomic type is [lock-free](Self::is_lock_free), any concurrent
3948 /// operations on it must be atomic.
3949 /// - Otherwise, any concurrent operations on it must be compatible with
3950 /// operations performed by this atomic type.
3951 ///
3952 /// This is `const fn` on Rust 1.58+.
3953 #[inline]
3954 pub const fn as_ptr(&self) -> *mut $int_type {
3955 self.inner.as_ptr()
3956 }
3957 }
3958 }
3959 // See https://github.com/taiki-e/portable-atomic/issues/180
3960 #[cfg(not(feature = "require-cas"))]
3961 cfg_no_atomic_cas! {
3962 #[doc(hidden)]
3963 #[allow(unused_variables, clippy::unused_self, clippy::extra_unused_lifetimes)]
3964 impl<'a> $atomic_type {
3965 $cfg_no_atomic_cas_or_amo32_or_8! {
3966 #[inline]
3967 pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type
3968 where
3969 &'a Self: HasSwap,
3970 {
3971 unimplemented!()
3972 }
3973 } // $cfg_no_atomic_cas_or_amo32_or_8!
3974 #[inline]
3975 pub fn compare_exchange(
3976 &self,
3977 current: $int_type,
3978 new: $int_type,
3979 success: Ordering,
3980 failure: Ordering,
3981 ) -> Result<$int_type, $int_type>
3982 where
3983 &'a Self: HasCompareExchange,
3984 {
3985 unimplemented!()
3986 }
3987 #[inline]
3988 pub fn compare_exchange_weak(
3989 &self,
3990 current: $int_type,
3991 new: $int_type,
3992 success: Ordering,
3993 failure: Ordering,
3994 ) -> Result<$int_type, $int_type>
3995 where
3996 &'a Self: HasCompareExchangeWeak,
3997 {
3998 unimplemented!()
3999 }
4000 $cfg_no_atomic_cas_or_amo32_or_8! {
4001 #[inline]
4002 pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type
4003 where
4004 &'a Self: HasFetchAdd,
4005 {
4006 unimplemented!()
4007 }
4008 #[inline]
4009 pub fn add(&self, val: $int_type, order: Ordering)
4010 where
4011 &'a Self: HasAdd,
4012 {
4013 unimplemented!()
4014 }
4015 #[inline]
4016 pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type
4017 where
4018 &'a Self: HasFetchSub,
4019 {
4020 unimplemented!()
4021 }
4022 #[inline]
4023 pub fn sub(&self, val: $int_type, order: Ordering)
4024 where
4025 &'a Self: HasSub,
4026 {
4027 unimplemented!()
4028 }
4029 } // $cfg_no_atomic_cas_or_amo32_or_8!
4030 cfg_no_atomic_cas_or_amo32! {
4031 #[inline]
4032 pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type
4033 where
4034 &'a Self: HasFetchAnd,
4035 {
4036 unimplemented!()
4037 }
4038 #[inline]
4039 pub fn and(&self, val: $int_type, order: Ordering)
4040 where
4041 &'a Self: HasAnd,
4042 {
4043 unimplemented!()
4044 }
4045 } // cfg_no_atomic_cas_or_amo32!
4046 #[inline]
4047 pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type
4048 where
4049 &'a Self: HasFetchNand,
4050 {
4051 unimplemented!()
4052 }
4053 cfg_no_atomic_cas_or_amo32! {
4054 #[inline]
4055 pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type
4056 where
4057 &'a Self: HasFetchOr,
4058 {
4059 unimplemented!()
4060 }
4061 #[inline]
4062 pub fn or(&self, val: $int_type, order: Ordering)
4063 where
4064 &'a Self: HasOr,
4065 {
4066 unimplemented!()
4067 }
4068 #[inline]
4069 pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type
4070 where
4071 &'a Self: HasFetchXor,
4072 {
4073 unimplemented!()
4074 }
4075 #[inline]
4076 pub fn xor(&self, val: $int_type, order: Ordering)
4077 where
4078 &'a Self: HasXor,
4079 {
4080 unimplemented!()
4081 }
4082 } // cfg_no_atomic_cas_or_amo32!
4083 #[inline]
4084 pub fn fetch_update<F>(
4085 &self,
4086 set_order: Ordering,
4087 fetch_order: Ordering,
4088 f: F,
4089 ) -> Result<$int_type, $int_type>
4090 where
4091 F: FnMut($int_type) -> Option<$int_type>,
4092 &'a Self: HasFetchUpdate,
4093 {
4094 unimplemented!()
4095 }
4096 $cfg_no_atomic_cas_or_amo32_or_8! {
4097 #[inline]
4098 pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type
4099 where
4100 &'a Self: HasFetchMax,
4101 {
4102 unimplemented!()
4103 }
4104 #[inline]
4105 pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type
4106 where
4107 &'a Self: HasFetchMin,
4108 {
4109 unimplemented!()
4110 }
4111 } // $cfg_no_atomic_cas_or_amo32_or_8!
4112 cfg_no_atomic_cas_or_amo32! {
4113 #[inline]
4114 pub fn bit_set(&self, bit: u32, order: Ordering) -> bool
4115 where
4116 &'a Self: HasBitSet,
4117 {
4118 unimplemented!()
4119 }
4120 #[inline]
4121 pub fn bit_clear(&self, bit: u32, order: Ordering) -> bool
4122 where
4123 &'a Self: HasBitClear,
4124 {
4125 unimplemented!()
4126 }
4127 #[inline]
4128 pub fn bit_toggle(&self, bit: u32, order: Ordering) -> bool
4129 where
4130 &'a Self: HasBitToggle,
4131 {
4132 unimplemented!()
4133 }
4134 #[inline]
4135 pub fn fetch_not(&self, order: Ordering) -> $int_type
4136 where
4137 &'a Self: HasFetchNot,
4138 {
4139 unimplemented!()
4140 }
4141 #[inline]
4142 pub fn not(&self, order: Ordering)
4143 where
4144 &'a Self: HasNot,
4145 {
4146 unimplemented!()
4147 }
4148 } // cfg_no_atomic_cas_or_amo32!
4149 #[inline]
4150 pub fn fetch_neg(&self, order: Ordering) -> $int_type
4151 where
4152 &'a Self: HasFetchNeg,
4153 {
4154 unimplemented!()
4155 }
4156 #[inline]
4157 pub fn neg(&self, order: Ordering)
4158 where
4159 &'a Self: HasNeg,
4160 {
4161 unimplemented!()
4162 }
4163 }
4164 } // cfg_no_atomic_cas!
4165 $(
4166 #[$cfg_float]
4167 atomic_int!(float,
4168 #[$cfg_float] $atomic_float_type, $float_type, $atomic_type, $int_type, $align
4169 );
4170 )?
4171 };
4172
4173 // AtomicF* impls
4174 (float,
4175 #[$cfg_float:meta]
4176 $atomic_type:ident,
4177 $float_type:ident,
4178 $atomic_int_type:ident,
4179 $int_type:ident,
4180 $align:literal
4181 ) => {
4182 doc_comment! {
4183 concat!("A floating point type which can be safely shared between threads.
4184
4185This type has the same in-memory representation as the underlying floating point type,
4186[`", stringify!($float_type), "`].
4187"
4188 ),
4189 #[cfg_attr(docsrs, doc($cfg_float))]
4190 // We can use #[repr(transparent)] here, but #[repr(C, align(N))]
4191 // will show clearer docs.
4192 #[repr(C, align($align))]
4193 pub struct $atomic_type {
4194 inner: imp::float::$atomic_type,
4195 }
4196 }
4197
4198 impl Default for $atomic_type {
4199 #[inline]
4200 fn default() -> Self {
4201 Self::new($float_type::default())
4202 }
4203 }
4204
4205 impl From<$float_type> for $atomic_type {
4206 #[inline]
4207 fn from(v: $float_type) -> Self {
4208 Self::new(v)
4209 }
4210 }
4211
4212 // UnwindSafe is implicitly implemented.
4213 #[cfg(not(portable_atomic_no_core_unwind_safe))]
4214 impl core::panic::RefUnwindSafe for $atomic_type {}
4215 #[cfg(all(portable_atomic_no_core_unwind_safe, feature = "std"))]
4216 impl std::panic::RefUnwindSafe for $atomic_type {}
4217
4218 impl_debug_and_serde!($atomic_type);
4219
4220 impl $atomic_type {
4221 /// Creates a new atomic float.
4222 #[inline]
4223 #[must_use]
4224 pub const fn new(v: $float_type) -> Self {
4225 static_assert_layout!($atomic_type, $float_type);
4226 Self { inner: imp::float::$atomic_type::new(v) }
4227 }
4228
4229 // TODO: update docs based on https://github.com/rust-lang/rust/pull/116762
4230 #[cfg(not(portable_atomic_no_const_mut_refs))]
4231 doc_comment! {
4232 concat!("Creates a new reference to an atomic float from a pointer.
4233
4234This is `const fn` on Rust 1.83+.
4235
4236# Safety
4237
4238* `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this
4239 can be bigger than `align_of::<", stringify!($float_type), ">()`).
4240* `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
4241* If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
4242 behind `ptr` must have a happens-before relationship with atomic accesses via
4243 the returned value (or vice-versa).
4244 * In other words, time periods where the value is accessed atomically may not
4245 overlap with periods where the value is accessed non-atomically.
4246 * This requirement is trivially satisfied if `ptr` is never used non-atomically
4247 for the duration of lifetime `'a`. Most use cases should be able to follow
4248 this guideline.
4249 * This requirement is also trivially satisfied if all accesses (atomic or not) are
4250 done from the same thread.
4251* If this atomic type is *not* lock-free:
4252 * Any accesses to the value behind `ptr` must have a happens-before relationship
4253 with accesses via the returned value (or vice-versa).
4254 * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
4255 be compatible with operations performed by this atomic type.
4256* This method must not be used to create overlapping or mixed-size atomic
4257 accesses, as these are not supported by the memory model.
4258
4259[valid]: core::ptr#safety"),
4260 #[inline]
4261 #[must_use]
4262 pub const unsafe fn from_ptr<'a>(ptr: *mut $float_type) -> &'a Self {
4263 #[allow(clippy::cast_ptr_alignment)]
4264 // SAFETY: guaranteed by the caller
4265 unsafe { &*(ptr as *mut Self) }
4266 }
4267 }
4268 #[cfg(portable_atomic_no_const_mut_refs)]
4269 doc_comment! {
4270 concat!("Creates a new reference to an atomic float from a pointer.
4271
4272This is `const fn` on Rust 1.83+.
4273
4274# Safety
4275
4276* `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this
4277 can be bigger than `align_of::<", stringify!($float_type), ">()`).
4278* `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
4279* If this atomic type is [lock-free](Self::is_lock_free), non-atomic accesses to the value
4280 behind `ptr` must have a happens-before relationship with atomic accesses via
4281 the returned value (or vice-versa).
4282 * In other words, time periods where the value is accessed atomically may not
4283 overlap with periods where the value is accessed non-atomically.
4284 * This requirement is trivially satisfied if `ptr` is never used non-atomically
4285 for the duration of lifetime `'a`. Most use cases should be able to follow
4286 this guideline.
4287 * This requirement is also trivially satisfied if all accesses (atomic or not) are
4288 done from the same thread.
4289* If this atomic type is *not* lock-free:
4290 * Any accesses to the value behind `ptr` must have a happens-before relationship
4291 with accesses via the returned value (or vice-versa).
4292 * Any concurrent accesses to the value behind `ptr` for the duration of lifetime `'a` must
4293 be compatible with operations performed by this atomic type.
4294* This method must not be used to create overlapping or mixed-size atomic
4295 accesses, as these are not supported by the memory model.
4296
4297[valid]: core::ptr#safety"),
4298 #[inline]
4299 #[must_use]
4300 pub unsafe fn from_ptr<'a>(ptr: *mut $float_type) -> &'a Self {
4301 #[allow(clippy::cast_ptr_alignment)]
4302 // SAFETY: guaranteed by the caller
4303 unsafe { &*(ptr as *mut Self) }
4304 }
4305 }
4306
4307 /// Returns `true` if operations on values of this type are lock-free.
4308 ///
4309 /// If the compiler or the platform doesn't support the necessary
4310 /// atomic instructions, global locks for every potentially
4311 /// concurrent atomic operation will be used.
4312 ///
4313 /// This function is guaranteed to always return the same result.
4314 #[inline]
4315 #[must_use]
4316 pub fn is_lock_free() -> bool {
4317 <imp::float::$atomic_type>::is_lock_free()
4318 }
4319
4320 /// Returns `true` if operations on values of this type are lock-free.
4321 ///
4322 /// If the compiler or the platform doesn't support the necessary
4323 /// atomic instructions, global locks for every potentially
4324 /// concurrent atomic operation will be used.
4325 ///
4326 /// **Note:** If the atomic operation relies on dynamic CPU feature detection,
4327 /// this type may be lock-free even if the function returns false.
4328 #[inline]
4329 #[must_use]
4330 pub const fn is_always_lock_free() -> bool {
4331 <imp::float::$atomic_type>::IS_ALWAYS_LOCK_FREE
4332 }
4333 #[cfg(test)]
4334 #[cfg_attr(all(not(debug_assertions), target_arch = "x86", not(target_feature = "sse2")), allow(dead_code))]
4335 const IS_ALWAYS_LOCK_FREE: bool = Self::is_always_lock_free();
4336
4337 const_fn! {
4338 const_if: #[cfg(not(portable_atomic_no_const_mut_refs))];
4339 /// Returns a mutable reference to the underlying float.
4340 ///
4341 /// This is safe because the mutable reference guarantees that no other threads are
4342 /// concurrently accessing the atomic data.
4343 ///
4344 /// This is `const fn` on Rust 1.83+.
4345 #[inline]
4346 pub const fn get_mut(&mut self) -> &mut $float_type {
4347 // SAFETY: the mutable reference guarantees unique ownership.
4348 unsafe { &mut *self.as_ptr() }
4349 }
4350 }
4351
4352 // TODO: Add from_mut/get_mut_slice/from_mut_slice once it is stable on std atomic types.
4353 // https://github.com/rust-lang/rust/issues/76314
4354
4355 const_fn! {
4356 const_if: #[cfg(not(portable_atomic_no_const_transmute))];
4357 /// Consumes the atomic and returns the contained value.
4358 ///
4359 /// This is safe because passing `self` by value guarantees that no other threads are
4360 /// concurrently accessing the atomic data.
4361 ///
4362 /// This is `const fn` on Rust 1.56+.
4363 #[inline]
4364 pub const fn into_inner(self) -> $float_type {
4365 // SAFETY: $atomic_type and $float_type have the same size and in-memory representations,
4366 // so they can be safely transmuted.
4367 // (const UnsafeCell::into_inner is unstable)
4368 unsafe { core::mem::transmute(self) }
4369 }
4370 }
4371
4372 /// Loads a value from the atomic float.
4373 ///
4374 /// `load` takes an [`Ordering`] argument which describes the memory ordering of this operation.
4375 /// Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`].
4376 ///
4377 /// # Panics
4378 ///
4379 /// Panics if `order` is [`Release`] or [`AcqRel`].
4380 #[inline]
4381 #[cfg_attr(
4382 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
4383 track_caller
4384 )]
4385 pub fn load(&self, order: Ordering) -> $float_type {
4386 self.inner.load(order)
4387 }
4388
4389 /// Stores a value into the atomic float.
4390 ///
4391 /// `store` takes an [`Ordering`] argument which describes the memory ordering of this operation.
4392 /// Possible values are [`SeqCst`], [`Release`] and [`Relaxed`].
4393 ///
4394 /// # Panics
4395 ///
4396 /// Panics if `order` is [`Acquire`] or [`AcqRel`].
4397 #[inline]
4398 #[cfg_attr(
4399 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
4400 track_caller
4401 )]
4402 pub fn store(&self, val: $float_type, order: Ordering) {
4403 self.inner.store(val, order)
4404 }
4405
4406 cfg_has_atomic_cas_or_amo32! {
4407 /// Stores a value into the atomic float, returning the previous value.
4408 ///
4409 /// `swap` takes an [`Ordering`] argument which describes the memory ordering
4410 /// of this operation. All ordering modes are possible. Note that using
4411 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
4412 /// using [`Release`] makes the load part [`Relaxed`].
4413 #[inline]
4414 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4415 pub fn swap(&self, val: $float_type, order: Ordering) -> $float_type {
4416 self.inner.swap(val, order)
4417 }
4418
4419 cfg_has_atomic_cas! {
4420 /// Stores a value into the atomic float if the current value is the same as
4421 /// the `current` value.
4422 ///
4423 /// The return value is a result indicating whether the new value was written and
4424 /// containing the previous value. On success this value is guaranteed to be equal to
4425 /// `current`.
4426 ///
4427 /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
4428 /// ordering of this operation. `success` describes the required ordering for the
4429 /// read-modify-write operation that takes place if the comparison with `current` succeeds.
4430 /// `failure` describes the required ordering for the load operation that takes place when
4431 /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
4432 /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
4433 /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
4434 ///
4435 /// # Panics
4436 ///
4437 /// Panics if `failure` is [`Release`], [`AcqRel`].
4438 #[cfg_attr(docsrs, doc(alias = "compare_and_swap"))]
4439 #[inline]
4440 #[cfg_attr(
4441 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
4442 track_caller
4443 )]
4444 pub fn compare_exchange(
4445 &self,
4446 current: $float_type,
4447 new: $float_type,
4448 success: Ordering,
4449 failure: Ordering,
4450 ) -> Result<$float_type, $float_type> {
4451 self.inner.compare_exchange(current, new, success, failure)
4452 }
4453
4454 /// Stores a value into the atomic float if the current value is the same as
4455 /// the `current` value.
4456 /// Unlike [`compare_exchange`](Self::compare_exchange)
4457 /// this function is allowed to spuriously fail even
4458 /// when the comparison succeeds, which can result in more efficient code on some
4459 /// platforms. The return value is a result indicating whether the new value was
4460 /// written and containing the previous value.
4461 ///
4462 /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
4463 /// ordering of this operation. `success` describes the required ordering for the
4464 /// read-modify-write operation that takes place if the comparison with `current` succeeds.
4465 /// `failure` describes the required ordering for the load operation that takes place when
4466 /// the comparison fails. Using [`Acquire`] as success ordering makes the store part
4467 /// of this operation [`Relaxed`], and using [`Release`] makes the successful load
4468 /// [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
4469 ///
4470 /// # Panics
4471 ///
4472 /// Panics if `failure` is [`Release`], [`AcqRel`].
4473 #[cfg_attr(docsrs, doc(alias = "compare_and_swap"))]
4474 #[inline]
4475 #[cfg_attr(
4476 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
4477 track_caller
4478 )]
4479 pub fn compare_exchange_weak(
4480 &self,
4481 current: $float_type,
4482 new: $float_type,
4483 success: Ordering,
4484 failure: Ordering,
4485 ) -> Result<$float_type, $float_type> {
4486 self.inner.compare_exchange_weak(current, new, success, failure)
4487 }
4488
4489 /// Adds to the current value, returning the previous value.
4490 ///
4491 /// This operation wraps around on overflow.
4492 ///
4493 /// `fetch_add` takes an [`Ordering`] argument which describes the memory ordering
4494 /// of this operation. All ordering modes are possible. Note that using
4495 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
4496 /// using [`Release`] makes the load part [`Relaxed`].
4497 #[inline]
4498 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4499 pub fn fetch_add(&self, val: $float_type, order: Ordering) -> $float_type {
4500 self.inner.fetch_add(val, order)
4501 }
4502
4503 /// Subtracts from the current value, returning the previous value.
4504 ///
4505 /// This operation wraps around on overflow.
4506 ///
4507 /// `fetch_sub` takes an [`Ordering`] argument which describes the memory ordering
4508 /// of this operation. All ordering modes are possible. Note that using
4509 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
4510 /// using [`Release`] makes the load part [`Relaxed`].
4511 #[inline]
4512 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4513 pub fn fetch_sub(&self, val: $float_type, order: Ordering) -> $float_type {
4514 self.inner.fetch_sub(val, order)
4515 }
4516
4517 /// Fetches the value, and applies a function to it that returns an optional
4518 /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
4519 /// `Err(previous_value)`.
4520 ///
4521 /// Note: This may call the function multiple times if the value has been changed from other threads in
4522 /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied
4523 /// only once to the stored value.
4524 ///
4525 /// `fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
4526 /// The first describes the required ordering for when the operation finally succeeds while the second
4527 /// describes the required ordering for loads. These correspond to the success and failure orderings of
4528 /// [`compare_exchange`](Self::compare_exchange) respectively.
4529 ///
4530 /// Using [`Acquire`] as success ordering makes the store part
4531 /// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
4532 /// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
4533 ///
4534 /// # Panics
4535 ///
4536 /// Panics if `fetch_order` is [`Release`], [`AcqRel`].
4537 ///
4538 /// # Considerations
4539 ///
4540 /// This method is not magic; it is not provided by the hardware.
4541 /// It is implemented in terms of [`compare_exchange_weak`](Self::compare_exchange_weak),
4542 /// and suffers from the same drawbacks.
4543 /// In particular, this method will not circumvent the [ABA Problem].
4544 ///
4545 /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
4546 #[inline]
4547 #[cfg_attr(
4548 any(all(debug_assertions, not(portable_atomic_no_track_caller)), miri),
4549 track_caller
4550 )]
4551 pub fn fetch_update<F>(
4552 &self,
4553 set_order: Ordering,
4554 fetch_order: Ordering,
4555 mut f: F,
4556 ) -> Result<$float_type, $float_type>
4557 where
4558 F: FnMut($float_type) -> Option<$float_type>,
4559 {
4560 let mut prev = self.load(fetch_order);
4561 while let Some(next) = f(prev) {
4562 match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
4563 x @ Ok(_) => return x,
4564 Err(next_prev) => prev = next_prev,
4565 }
4566 }
4567 Err(prev)
4568 }
4569
4570 /// Maximum with the current value.
4571 ///
4572 /// Finds the maximum of the current value and the argument `val`, and
4573 /// sets the new value to the result.
4574 ///
4575 /// Returns the previous value.
4576 ///
4577 /// `fetch_max` takes an [`Ordering`] argument which describes the memory ordering
4578 /// of this operation. All ordering modes are possible. Note that using
4579 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
4580 /// using [`Release`] makes the load part [`Relaxed`].
4581 #[inline]
4582 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4583 pub fn fetch_max(&self, val: $float_type, order: Ordering) -> $float_type {
4584 self.inner.fetch_max(val, order)
4585 }
4586
4587 /// Minimum with the current value.
4588 ///
4589 /// Finds the minimum of the current value and the argument `val`, and
4590 /// sets the new value to the result.
4591 ///
4592 /// Returns the previous value.
4593 ///
4594 /// `fetch_min` takes an [`Ordering`] argument which describes the memory ordering
4595 /// of this operation. All ordering modes are possible. Note that using
4596 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
4597 /// using [`Release`] makes the load part [`Relaxed`].
4598 #[inline]
4599 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4600 pub fn fetch_min(&self, val: $float_type, order: Ordering) -> $float_type {
4601 self.inner.fetch_min(val, order)
4602 }
4603 } // cfg_has_atomic_cas!
4604
4605 /// Negates the current value, and sets the new value to the result.
4606 ///
4607 /// Returns the previous value.
4608 ///
4609 /// `fetch_neg` takes an [`Ordering`] argument which describes the memory ordering
4610 /// of this operation. All ordering modes are possible. Note that using
4611 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
4612 /// using [`Release`] makes the load part [`Relaxed`].
4613 #[inline]
4614 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4615 pub fn fetch_neg(&self, order: Ordering) -> $float_type {
4616 self.inner.fetch_neg(order)
4617 }
4618
4619 /// Computes the absolute value of the current value, and sets the
4620 /// new value to the result.
4621 ///
4622 /// Returns the previous value.
4623 ///
4624 /// `fetch_abs` takes an [`Ordering`] argument which describes the memory ordering
4625 /// of this operation. All ordering modes are possible. Note that using
4626 /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
4627 /// using [`Release`] makes the load part [`Relaxed`].
4628 #[inline]
4629 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
4630 pub fn fetch_abs(&self, order: Ordering) -> $float_type {
4631 self.inner.fetch_abs(order)
4632 }
4633 } // cfg_has_atomic_cas_or_amo32!
4634
4635 #[cfg(not(portable_atomic_no_const_raw_ptr_deref))]
4636 doc_comment! {
4637 concat!("Raw transmutation to `&", stringify!($atomic_int_type), "`.
4638
4639See [`", stringify!($float_type) ,"::from_bits`] for some discussion of the
4640portability of this operation (there are almost no issues).
4641
4642This is `const fn` on Rust 1.58+."),
4643 #[inline]
4644 pub const fn as_bits(&self) -> &$atomic_int_type {
4645 self.inner.as_bits()
4646 }
4647 }
4648 #[cfg(portable_atomic_no_const_raw_ptr_deref)]
4649 doc_comment! {
4650 concat!("Raw transmutation to `&", stringify!($atomic_int_type), "`.
4651
4652See [`", stringify!($float_type) ,"::from_bits`] for some discussion of the
4653portability of this operation (there are almost no issues).
4654
4655This is `const fn` on Rust 1.58+."),
4656 #[inline]
4657 pub fn as_bits(&self) -> &$atomic_int_type {
4658 self.inner.as_bits()
4659 }
4660 }
4661
4662 const_fn! {
4663 const_if: #[cfg(not(portable_atomic_no_const_raw_ptr_deref))];
4664 /// Returns a mutable pointer to the underlying float.
4665 ///
4666 /// Returning an `*mut` pointer from a shared reference to this atomic is
4667 /// safe because the atomic types work with interior mutability. Any use of
4668 /// the returned raw pointer requires an `unsafe` block and has to uphold
4669 /// the safety requirements. If there is concurrent access, note the following
4670 /// additional safety requirements:
4671 ///
4672 /// - If this atomic type is [lock-free](Self::is_lock_free), any concurrent
4673 /// operations on it must be atomic.
4674 /// - Otherwise, any concurrent operations on it must be compatible with
4675 /// operations performed by this atomic type.
4676 ///
4677 /// This is `const fn` on Rust 1.58+.
4678 #[inline]
4679 pub const fn as_ptr(&self) -> *mut $float_type {
4680 self.inner.as_ptr()
4681 }
4682 }
4683 }
4684 // See https://github.com/taiki-e/portable-atomic/issues/180
4685 #[cfg(not(feature = "require-cas"))]
4686 cfg_no_atomic_cas! {
4687 #[doc(hidden)]
4688 #[allow(unused_variables, clippy::unused_self, clippy::extra_unused_lifetimes)]
4689 impl<'a> $atomic_type {
4690 cfg_no_atomic_cas_or_amo32! {
4691 #[inline]
4692 pub fn swap(&self, val: $float_type, order: Ordering) -> $float_type
4693 where
4694 &'a Self: HasSwap,
4695 {
4696 unimplemented!()
4697 }
4698 } // cfg_no_atomic_cas_or_amo32!
4699 #[inline]
4700 pub fn compare_exchange(
4701 &self,
4702 current: $float_type,
4703 new: $float_type,
4704 success: Ordering,
4705 failure: Ordering,
4706 ) -> Result<$float_type, $float_type>
4707 where
4708 &'a Self: HasCompareExchange,
4709 {
4710 unimplemented!()
4711 }
4712 #[inline]
4713 pub fn compare_exchange_weak(
4714 &self,
4715 current: $float_type,
4716 new: $float_type,
4717 success: Ordering,
4718 failure: Ordering,
4719 ) -> Result<$float_type, $float_type>
4720 where
4721 &'a Self: HasCompareExchangeWeak,
4722 {
4723 unimplemented!()
4724 }
4725 #[inline]
4726 pub fn fetch_add(&self, val: $float_type, order: Ordering) -> $float_type
4727 where
4728 &'a Self: HasFetchAdd,
4729 {
4730 unimplemented!()
4731 }
4732 #[inline]
4733 pub fn fetch_sub(&self, val: $float_type, order: Ordering) -> $float_type
4734 where
4735 &'a Self: HasFetchSub,
4736 {
4737 unimplemented!()
4738 }
4739 #[inline]
4740 pub fn fetch_update<F>(
4741 &self,
4742 set_order: Ordering,
4743 fetch_order: Ordering,
4744 f: F,
4745 ) -> Result<$float_type, $float_type>
4746 where
4747 F: FnMut($float_type) -> Option<$float_type>,
4748 &'a Self: HasFetchUpdate,
4749 {
4750 unimplemented!()
4751 }
4752 #[inline]
4753 pub fn fetch_max(&self, val: $float_type, order: Ordering) -> $float_type
4754 where
4755 &'a Self: HasFetchMax,
4756 {
4757 unimplemented!()
4758 }
4759 #[inline]
4760 pub fn fetch_min(&self, val: $float_type, order: Ordering) -> $float_type
4761 where
4762 &'a Self: HasFetchMin,
4763 {
4764 unimplemented!()
4765 }
4766 cfg_no_atomic_cas_or_amo32! {
4767 #[inline]
4768 pub fn fetch_neg(&self, order: Ordering) -> $float_type
4769 where
4770 &'a Self: HasFetchNeg,
4771 {
4772 unimplemented!()
4773 }
4774 #[inline]
4775 pub fn fetch_abs(&self, order: Ordering) -> $float_type
4776 where
4777 &'a Self: HasFetchAbs,
4778 {
4779 unimplemented!()
4780 }
4781 } // cfg_no_atomic_cas_or_amo32!
4782 }
4783 } // cfg_no_atomic_cas!
4784 };
4785}
4786
4787cfg_has_atomic_ptr! {
4788 #[cfg(target_pointer_width = "16")]
4789 atomic_int!(AtomicIsize, isize, 2, cfg_has_atomic_cas_or_amo8, cfg_no_atomic_cas_or_amo8);
4790 #[cfg(target_pointer_width = "16")]
4791 atomic_int!(AtomicUsize, usize, 2, cfg_has_atomic_cas_or_amo8, cfg_no_atomic_cas_or_amo8);
4792 #[cfg(target_pointer_width = "32")]
4793 atomic_int!(AtomicIsize, isize, 4, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32);
4794 #[cfg(target_pointer_width = "32")]
4795 atomic_int!(AtomicUsize, usize, 4, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32);
4796 #[cfg(target_pointer_width = "64")]
4797 atomic_int!(AtomicIsize, isize, 8, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32);
4798 #[cfg(target_pointer_width = "64")]
4799 atomic_int!(AtomicUsize, usize, 8, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32);
4800 #[cfg(target_pointer_width = "128")]
4801 atomic_int!(AtomicIsize, isize, 16, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32);
4802 #[cfg(target_pointer_width = "128")]
4803 atomic_int!(AtomicUsize, usize, 16, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32);
4804}
4805
4806cfg_has_atomic_8! {
4807 atomic_int!(AtomicI8, i8, 1, cfg_has_atomic_cas_or_amo8, cfg_no_atomic_cas_or_amo8);
4808 atomic_int!(AtomicU8, u8, 1, cfg_has_atomic_cas_or_amo8, cfg_no_atomic_cas_or_amo8);
4809}
4810cfg_has_atomic_16! {
4811 atomic_int!(AtomicI16, i16, 2, cfg_has_atomic_cas_or_amo8, cfg_no_atomic_cas_or_amo8);
4812 atomic_int!(AtomicU16, u16, 2, cfg_has_atomic_cas_or_amo8, cfg_no_atomic_cas_or_amo8,
4813 #[cfg(all(feature = "float", portable_atomic_unstable_f16))] AtomicF16, f16);
4814}
4815cfg_has_atomic_32! {
4816 atomic_int!(AtomicI32, i32, 4, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32);
4817 atomic_int!(AtomicU32, u32, 4, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32,
4818 #[cfg(feature = "float")] AtomicF32, f32);
4819}
4820cfg_has_atomic_64! {
4821 atomic_int!(AtomicI64, i64, 8, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32);
4822 atomic_int!(AtomicU64, u64, 8, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32,
4823 #[cfg(feature = "float")] AtomicF64, f64);
4824}
4825cfg_has_atomic_128! {
4826 atomic_int!(AtomicI128, i128, 16, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32);
4827 atomic_int!(AtomicU128, u128, 16, cfg_has_atomic_cas_or_amo32, cfg_no_atomic_cas_or_amo32,
4828 #[cfg(all(feature = "float", portable_atomic_unstable_f128))] AtomicF128, f128);
4829}
4830
4831// See https://github.com/taiki-e/portable-atomic/issues/180
4832#[cfg(not(feature = "require-cas"))]
4833cfg_no_atomic_cas! {
4834cfg_no_atomic_cas_or_amo32! {
4835#[cfg(feature = "float")]
4836use self::diagnostic_helper::HasFetchAbs;
4837use self::diagnostic_helper::{
4838 HasAnd, HasBitClear, HasBitSet, HasBitToggle, HasFetchAnd, HasFetchByteAdd, HasFetchByteSub,
4839 HasFetchNot, HasFetchOr, HasFetchPtrAdd, HasFetchPtrSub, HasFetchXor, HasNot, HasOr, HasXor,
4840};
4841} // cfg_no_atomic_cas_or_amo32!
4842cfg_no_atomic_cas_or_amo8! {
4843use self::diagnostic_helper::{HasAdd, HasSub, HasSwap};
4844} // cfg_no_atomic_cas_or_amo8!
4845#[cfg_attr(not(feature = "float"), allow(unused_imports))]
4846use self::diagnostic_helper::{
4847 HasCompareExchange, HasCompareExchangeWeak, HasFetchAdd, HasFetchMax, HasFetchMin,
4848 HasFetchNand, HasFetchNeg, HasFetchSub, HasFetchUpdate, HasNeg,
4849};
4850#[cfg_attr(
4851 any(
4852 all(
4853 portable_atomic_no_atomic_load_store,
4854 not(any(
4855 target_arch = "avr",
4856 target_arch = "bpf",
4857 target_arch = "msp430",
4858 target_arch = "riscv32",
4859 target_arch = "riscv64",
4860 feature = "critical-section",
4861 portable_atomic_unsafe_assume_single_core,
4862 )),
4863 ),
4864 not(feature = "float"),
4865 ),
4866 allow(dead_code, unreachable_pub)
4867)]
4868#[allow(unknown_lints, unnameable_types)] // Not public API. unnameable_types is available on Rust 1.79+
4869mod diagnostic_helper {
4870 cfg_no_atomic_cas_or_amo8! {
4871 #[doc(hidden)]
4872 #[cfg_attr(
4873 not(portable_atomic_no_diagnostic_namespace),
4874 diagnostic::on_unimplemented(
4875 message = "`swap` requires atomic CAS but not available on this target by default",
4876 label = "this associated function is not available on this target by default",
4877 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
4878 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
4879 )
4880 )]
4881 pub trait HasSwap {}
4882 } // cfg_no_atomic_cas_or_amo8!
4883 #[doc(hidden)]
4884 #[cfg_attr(
4885 not(portable_atomic_no_diagnostic_namespace),
4886 diagnostic::on_unimplemented(
4887 message = "`compare_exchange` requires atomic CAS but not available on this target by default",
4888 label = "this associated function is not available on this target by default",
4889 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
4890 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
4891 )
4892 )]
4893 pub trait HasCompareExchange {}
4894 #[doc(hidden)]
4895 #[cfg_attr(
4896 not(portable_atomic_no_diagnostic_namespace),
4897 diagnostic::on_unimplemented(
4898 message = "`compare_exchange_weak` requires atomic CAS but not available on this target by default",
4899 label = "this associated function is not available on this target by default",
4900 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
4901 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
4902 )
4903 )]
4904 pub trait HasCompareExchangeWeak {}
4905 #[doc(hidden)]
4906 #[cfg_attr(
4907 not(portable_atomic_no_diagnostic_namespace),
4908 diagnostic::on_unimplemented(
4909 message = "`fetch_add` requires atomic CAS but not available on this target by default",
4910 label = "this associated function is not available on this target by default",
4911 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
4912 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
4913 )
4914 )]
4915 pub trait HasFetchAdd {}
4916 cfg_no_atomic_cas_or_amo8! {
4917 #[doc(hidden)]
4918 #[cfg_attr(
4919 not(portable_atomic_no_diagnostic_namespace),
4920 diagnostic::on_unimplemented(
4921 message = "`add` requires atomic CAS but not available on this target by default",
4922 label = "this associated function is not available on this target by default",
4923 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
4924 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
4925 )
4926 )]
4927 pub trait HasAdd {}
4928 } // cfg_no_atomic_cas_or_amo8!
4929 #[doc(hidden)]
4930 #[cfg_attr(
4931 not(portable_atomic_no_diagnostic_namespace),
4932 diagnostic::on_unimplemented(
4933 message = "`fetch_sub` requires atomic CAS but not available on this target by default",
4934 label = "this associated function is not available on this target by default",
4935 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
4936 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
4937 )
4938 )]
4939 pub trait HasFetchSub {}
4940 cfg_no_atomic_cas_or_amo8! {
4941 #[doc(hidden)]
4942 #[cfg_attr(
4943 not(portable_atomic_no_diagnostic_namespace),
4944 diagnostic::on_unimplemented(
4945 message = "`sub` requires atomic CAS but not available on this target by default",
4946 label = "this associated function is not available on this target by default",
4947 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
4948 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
4949 )
4950 )]
4951 pub trait HasSub {}
4952 } // cfg_no_atomic_cas_or_amo8!
4953 cfg_no_atomic_cas_or_amo32! {
4954 #[doc(hidden)]
4955 #[cfg_attr(
4956 not(portable_atomic_no_diagnostic_namespace),
4957 diagnostic::on_unimplemented(
4958 message = "`fetch_ptr_add` requires atomic CAS but not available on this target by default",
4959 label = "this associated function is not available on this target by default",
4960 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
4961 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
4962 )
4963 )]
4964 pub trait HasFetchPtrAdd {}
4965 #[doc(hidden)]
4966 #[cfg_attr(
4967 not(portable_atomic_no_diagnostic_namespace),
4968 diagnostic::on_unimplemented(
4969 message = "`fetch_ptr_sub` requires atomic CAS but not available on this target by default",
4970 label = "this associated function is not available on this target by default",
4971 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
4972 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
4973 )
4974 )]
4975 pub trait HasFetchPtrSub {}
4976 #[doc(hidden)]
4977 #[cfg_attr(
4978 not(portable_atomic_no_diagnostic_namespace),
4979 diagnostic::on_unimplemented(
4980 message = "`fetch_byte_add` requires atomic CAS but not available on this target by default",
4981 label = "this associated function is not available on this target by default",
4982 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
4983 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
4984 )
4985 )]
4986 pub trait HasFetchByteAdd {}
4987 #[doc(hidden)]
4988 #[cfg_attr(
4989 not(portable_atomic_no_diagnostic_namespace),
4990 diagnostic::on_unimplemented(
4991 message = "`fetch_byte_sub` requires atomic CAS but not available on this target by default",
4992 label = "this associated function is not available on this target by default",
4993 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
4994 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
4995 )
4996 )]
4997 pub trait HasFetchByteSub {}
4998 #[doc(hidden)]
4999 #[cfg_attr(
5000 not(portable_atomic_no_diagnostic_namespace),
5001 diagnostic::on_unimplemented(
5002 message = "`fetch_and` requires atomic CAS but not available on this target by default",
5003 label = "this associated function is not available on this target by default",
5004 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5005 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5006 )
5007 )]
5008 pub trait HasFetchAnd {}
5009 #[doc(hidden)]
5010 #[cfg_attr(
5011 not(portable_atomic_no_diagnostic_namespace),
5012 diagnostic::on_unimplemented(
5013 message = "`and` requires atomic CAS but not available on this target by default",
5014 label = "this associated function is not available on this target by default",
5015 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5016 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5017 )
5018 )]
5019 pub trait HasAnd {}
5020 } // cfg_no_atomic_cas_or_amo32!
5021 #[doc(hidden)]
5022 #[cfg_attr(
5023 not(portable_atomic_no_diagnostic_namespace),
5024 diagnostic::on_unimplemented(
5025 message = "`fetch_nand` requires atomic CAS but not available on this target by default",
5026 label = "this associated function is not available on this target by default",
5027 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5028 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5029 )
5030 )]
5031 pub trait HasFetchNand {}
5032 cfg_no_atomic_cas_or_amo32! {
5033 #[doc(hidden)]
5034 #[cfg_attr(
5035 not(portable_atomic_no_diagnostic_namespace),
5036 diagnostic::on_unimplemented(
5037 message = "`fetch_or` requires atomic CAS but not available on this target by default",
5038 label = "this associated function is not available on this target by default",
5039 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5040 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5041 )
5042 )]
5043 pub trait HasFetchOr {}
5044 #[doc(hidden)]
5045 #[cfg_attr(
5046 not(portable_atomic_no_diagnostic_namespace),
5047 diagnostic::on_unimplemented(
5048 message = "`or` requires atomic CAS but not available on this target by default",
5049 label = "this associated function is not available on this target by default",
5050 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5051 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5052 )
5053 )]
5054 pub trait HasOr {}
5055 #[doc(hidden)]
5056 #[cfg_attr(
5057 not(portable_atomic_no_diagnostic_namespace),
5058 diagnostic::on_unimplemented(
5059 message = "`fetch_xor` requires atomic CAS but not available on this target by default",
5060 label = "this associated function is not available on this target by default",
5061 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5062 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5063 )
5064 )]
5065 pub trait HasFetchXor {}
5066 #[doc(hidden)]
5067 #[cfg_attr(
5068 not(portable_atomic_no_diagnostic_namespace),
5069 diagnostic::on_unimplemented(
5070 message = "`xor` requires atomic CAS but not available on this target by default",
5071 label = "this associated function is not available on this target by default",
5072 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5073 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5074 )
5075 )]
5076 pub trait HasXor {}
5077 #[doc(hidden)]
5078 #[cfg_attr(
5079 not(portable_atomic_no_diagnostic_namespace),
5080 diagnostic::on_unimplemented(
5081 message = "`fetch_not` requires atomic CAS but not available on this target by default",
5082 label = "this associated function is not available on this target by default",
5083 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5084 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5085 )
5086 )]
5087 pub trait HasFetchNot {}
5088 #[doc(hidden)]
5089 #[cfg_attr(
5090 not(portable_atomic_no_diagnostic_namespace),
5091 diagnostic::on_unimplemented(
5092 message = "`not` requires atomic CAS but not available on this target by default",
5093 label = "this associated function is not available on this target by default",
5094 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5095 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5096 )
5097 )]
5098 pub trait HasNot {}
5099 } // cfg_no_atomic_cas_or_amo32!
5100 #[doc(hidden)]
5101 #[cfg_attr(
5102 not(portable_atomic_no_diagnostic_namespace),
5103 diagnostic::on_unimplemented(
5104 message = "`fetch_neg` requires atomic CAS but not available on this target by default",
5105 label = "this associated function is not available on this target by default",
5106 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5107 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5108 )
5109 )]
5110 pub trait HasFetchNeg {}
5111 #[doc(hidden)]
5112 #[cfg_attr(
5113 not(portable_atomic_no_diagnostic_namespace),
5114 diagnostic::on_unimplemented(
5115 message = "`neg` requires atomic CAS but not available on this target by default",
5116 label = "this associated function is not available on this target by default",
5117 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5118 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5119 )
5120 )]
5121 pub trait HasNeg {}
5122 cfg_no_atomic_cas_or_amo32! {
5123 #[cfg(feature = "float")]
5124 #[cfg_attr(target_pointer_width = "16", allow(dead_code, unreachable_pub))]
5125 #[doc(hidden)]
5126 #[cfg_attr(
5127 not(portable_atomic_no_diagnostic_namespace),
5128 diagnostic::on_unimplemented(
5129 message = "`fetch_abs` requires atomic CAS but not available on this target by default",
5130 label = "this associated function is not available on this target by default",
5131 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5132 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5133 )
5134 )]
5135 pub trait HasFetchAbs {}
5136 } // cfg_no_atomic_cas_or_amo32!
5137 #[doc(hidden)]
5138 #[cfg_attr(
5139 not(portable_atomic_no_diagnostic_namespace),
5140 diagnostic::on_unimplemented(
5141 message = "`fetch_min` requires atomic CAS but not available on this target by default",
5142 label = "this associated function is not available on this target by default",
5143 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5144 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5145 )
5146 )]
5147 pub trait HasFetchMin {}
5148 #[doc(hidden)]
5149 #[cfg_attr(
5150 not(portable_atomic_no_diagnostic_namespace),
5151 diagnostic::on_unimplemented(
5152 message = "`fetch_max` requires atomic CAS but not available on this target by default",
5153 label = "this associated function is not available on this target by default",
5154 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5155 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5156 )
5157 )]
5158 pub trait HasFetchMax {}
5159 #[doc(hidden)]
5160 #[cfg_attr(
5161 not(portable_atomic_no_diagnostic_namespace),
5162 diagnostic::on_unimplemented(
5163 message = "`fetch_update` requires atomic CAS but not available on this target by default",
5164 label = "this associated function is not available on this target by default",
5165 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5166 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5167 )
5168 )]
5169 pub trait HasFetchUpdate {}
5170 cfg_no_atomic_cas_or_amo32! {
5171 #[doc(hidden)]
5172 #[cfg_attr(
5173 not(portable_atomic_no_diagnostic_namespace),
5174 diagnostic::on_unimplemented(
5175 message = "`bit_set` requires atomic CAS but not available on this target by default",
5176 label = "this associated function is not available on this target by default",
5177 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5178 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5179 )
5180 )]
5181 pub trait HasBitSet {}
5182 #[doc(hidden)]
5183 #[cfg_attr(
5184 not(portable_atomic_no_diagnostic_namespace),
5185 diagnostic::on_unimplemented(
5186 message = "`bit_clear` requires atomic CAS but not available on this target by default",
5187 label = "this associated function is not available on this target by default",
5188 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5189 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5190 )
5191 )]
5192 pub trait HasBitClear {}
5193 #[doc(hidden)]
5194 #[cfg_attr(
5195 not(portable_atomic_no_diagnostic_namespace),
5196 diagnostic::on_unimplemented(
5197 message = "`bit_toggle` requires atomic CAS but not available on this target by default",
5198 label = "this associated function is not available on this target by default",
5199 note = "consider enabling one of the `critical-section` feature or `unsafe-assume-single-core` feature (or `portable_atomic_unsafe_assume_single_core` cfg)",
5200 note = "see <https://docs.rs/portable-atomic/latest/portable_atomic/#optional-features> for more."
5201 )
5202 )]
5203 pub trait HasBitToggle {}
5204 } // cfg_no_atomic_cas_or_amo32!
5205}
5206} // cfg_no_atomic_cas!