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