Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"bfc89c873a70587ef4cae76a2bf6f821a9b18ae10d8f6b57100c47d95b4cce9b","Cargo.lock":"2a510578edf545879036ccfed6ca76322563ae60a96aeca08bc563aad995c8e4","Cargo.toml":"b41fc2b1f6259ab32f9c93aeb73074efa00739c587a4ebbf5c13beb45a9edb3f","Cargo.toml.orig":"ac6b24ea8c3e17822772c1a9a30455a068bdf4d4107178e17a65eb2cf4f08291","LICENSE.txt":"13f4cc9fbc8d4a447b28aa84019c10ad4abf4b5f6919db061bf6690ccc23bc02","README.md":"23e6ae3cc7d7c8d7b608f87fbe79dd7af36dd9c1c00a4d2ff6bb45171a58799d","build.rs":"198e126042203936db2a99e9440569f3b5ff0f8bd9b3648e3b79807e26a82591","src/lib.rs":"134e22792ab52d7889df5d63310059688d84f35ce6f04c52a0f66c32d7c582e7","src/macros.rs":"622bae57d328535f3b9d0d21460189adc09bbaffb23cdc8aaafae3e50dca1c11","src/types.rs":"01acfbee32dbed511b0eae368017d7405a9b166bd306eafad2a83769e0b6cef4"},"package":"dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"}
+5
View File
@@ -0,0 +1,5 @@
{
"git": {
"sha1": "3f27e0d827338aee919213fd071b99819a1b9fff"
}
}
+16
View File
@@ -0,0 +1,16 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "radium"
version = "0.7.0"
dependencies = [
"static_assertions",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+29
View File
@@ -0,0 +1,29 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "radium"
version = "0.7.0"
authors = ["Nika Layzell <nika@thelayzells.com>", "myrrlyn <self@myrrlyn.dev>"]
include = ["src/**/*.rs", "Cargo.toml", "README.md", "LICENSE.txt", "build.rs"]
description = "Portable interfaces for maybe-atomic types"
homepage = "https://github.com/bitvecto-rs/radium"
documentation = "https://docs.rs/radium"
readme = "README.md"
keywords = ["atomic", "cell", "sync", "generic", "trait"]
categories = ["concurrency", "no-std"]
license = "MIT"
repository = "https://github.com/bitvecto-rs/radium"
[dependencies]
[dev-dependencies.static_assertions]
version = "1"
+24
View File
@@ -0,0 +1,24 @@
[package]
name = "radium"
version = "0.7.0"
authors = [
"Nika Layzell <nika@thelayzells.com>",
"myrrlyn <self@myrrlyn.dev>"
]
license = "MIT"
readme = "README.md"
repository = "https://github.com/bitvecto-rs/radium"
homepage = "https://github.com/bitvecto-rs/radium"
documentation = "https://docs.rs/radium"
description = "Portable interfaces for maybe-atomic types"
keywords = ["atomic", "cell", "sync", "generic", "trait"]
categories = ["concurrency", "no-std"]
include = ["src/**/*.rs", "Cargo.toml", "README.md", "LICENSE.txt", "build.rs"]
edition = "2018"
[dependencies]
[dev-dependencies]
static_assertions = "1"
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 kneecaw (Nika Layzell)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+80
View File
@@ -0,0 +1,80 @@
# radium
[![Latest Version][version_img]][crate_link]
[![Documentation][docs_img]][docs_link]
`radium` provides abstractions and graceful degradation for behavior that *must*
be shared-mutable, but merely *may* use atomic instructions to do so.
The primary export is the [`Radium`] trait. This is implemented on all symbols
in the [`atomic`] module, and on their [`Cell<T>`] equivalents, and presents the
atomic inherent API as a trait. Your code can be generic over `Radium`, use a
stable and consistent API, and permit callers to select atomic or `Cell`
behavior as they need.
The symbols in the [`atomic`] module are conditionally present according to the
target architectures atomic support. As such, code that is portable across
targets with varying atomic support cannot use those names directly. Instead,
the [`radium::types`] module provides names that will always exist, and forward
to the corresponding atomic type when it exists and the equivalent [`Cell<T>`]
type when it does not.
As the `cfg(target_has_atomic)` compiler attribute is unstable, `radium`
provides the macro `radium::if_atomic!` to perform conditional compilation based
on atomic availability.
This crate is `#![no_std]`-compatible, and uses no non-core types.
## Versioning
Each change of supported target architecture will result in a new minor version.
Furthermore, `radium` is by definition attached to the Rust standard library.
As the atomic API evolves, `radium` will follow it. MSRV raising is always at
least a minor-version increase.
If you require a backport of architecture discovery to older Rust versions,
please file an issue. We will happily backport upon request, but we do not
proactively guarantee support for compilers older than ~six months.
## Target Architecture Compatibility
Because the compiler does not expose this information to libraries, `radium`
uses a build script to detect the target architecture and emit its own
directives that mark the presence or absence of an atomic integer. We accomplish
this by reading the compilers target information records and copying the
information directly into the build script.
If `radium` does not work for your architecture, please update the build script
to handle your target string and submit a pull request. We write the build
script on an as-needed basis; it is not proactively filled with all of the
information listed in the compiler.
**NOTE**: The build script receives information through two variables: `TARGET`
and `CARGO_CFG_TARGET_ARCH`. The latter is equivalent to the value in
`cfg!(target_arch =)`; however, this value **does not** contain enough
information to fully disambiguate the target. The build script attempts to do
rudimentary parsing of the `env!(TARGET)` string; if this does not work for your
target, consider using the `TARGET_ARCH` matcher, or match on the full `TARGET`
string rather than the parse attempt.
---
**@kneecaw** - <https://twitter.com/kneecaw/status/1132695060812849154>
> Feelin' lazy: Has someone already written a helper trait abstracting
> operations over `AtomicUsize` and `Cell<usize>` for generic code which may
> not care about atomicity?
**@ManishEarth** - <https://twitter.com/ManishEarth/status/1132706585300496384>
> no but call the crate radium
>
> (since people didn't care that it was radioactive and used it in everything)
<!-- Badges -->
[crate_link]: https://crates.io/crates/raidum "Crates.io package"
[docs_img]: https://docs.rs/radium/badge.svg "Radium documentation badge"
[docs_link]: https://docs.rs/radium "Radium documentation"
[version_img]: https://img.shields.io/crates/v/radium.svg "Radium version badge"
[`Cell<T>`]: https://doc.rust-lang.org/core/cell/struct.Cell.html
[`Radium`]: https://docs.rs/radium/latest/radium/trait.Radium.html
[`atomic`]: https://doc.rust-lang.org/core/sync/atomic
[`radium::types`]: https://docs.rs/radium/latest/radium/types
+118
View File
@@ -0,0 +1,118 @@
//! Target detection
//!
//! This build script translates the target for which `radium` is being compiled
//! into a set of directives that the crate can use to control which atomic
//! symbols it attempts to name.
//!
//! The compiler maintains its store of target information here:
//! <https://github.com/rust-lang/rust/tree/be28b6235e64e0f662b96b710bf3af9de169215c/compiler/rustc_target/src/spec>
//!
//! That module is not easily extracted into something that can be loaded here,
//! so we are replicating it through string matching on the target name until
//! we are able to uniquely identify targets through `cfg` checks.
//!
//! Use `rustc --print target-list` to enumerate the full list of targets
//! available, and `rustc --print cfg` (optionally with `-Z unstable-options`)
//! to see what `cfg` values are produced for a target.
//!
//! The missing `cfg` checks required for conditional compilation, rather than a
//! build script, are:
//!
//! - [`accessible`](https://github.com/rust-lang/rust/issues/64797)
//! - [`target_feature`](https://github.com/rust-lang/rust/issues/69098)
//! - [`target_has_atomic`](https://github.com/rust-lang/rust/issues/32976)
//!
//! Once any of these becomes usable on the stable series, we can switch to a
//! set of `cfg` checks instead of a build script.
use std::{env, error::Error};
/// Collection of flags indicating whether the target processor supports atomic
/// instructions for a certain width.
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
struct Atomics {
/// Target supports 8-bit atomics
has_8: bool,
/// Target supports 16-bit atomics
has_16: bool,
/// Target supports 32-bit atomics
has_32: bool,
/// Target supports 64-bit atomics
has_64: bool,
/// Target supports word-width atomics
has_ptr: bool,
}
impl Atomics {
const ALL: Self = Self {
has_8: true,
has_16: true,
has_32: true,
has_64: true,
has_ptr: true,
};
const NONE: Self = Self {
has_8: false,
has_16: false,
has_32: false,
has_64: false,
has_ptr: false,
};
}
fn main() -> Result<(), Box<dyn Error>> {
let mut atomics = Atomics::ALL;
let target = env::var("TARGET")?;
// Add new target strings here with their atomic availability.
#[allow(clippy::match_single_binding, clippy::single_match)]
match &*target {
"arm-linux-androideabi" => atomics.has_64 = false,
_ => {}
}
// If for some reason splitting fails, use the whole target string.
let tgt_arch = target.split("-").next().unwrap_or(&target);
// Additionally, the `cfg!(target_arch)` value may be of use for some
// targets. Note that it does **not** carry distinguishing information in
// all cases! `armv5te` and `armv7` targets are both
// `cfg!(target_arch = "arm")`.
let env_arch = env::var("CARGO_CFG_TARGET_ARCH")?;
// Add new architecture sections here with their atomic availability.
#[allow(clippy::match_single_binding, clippy::single_match)]
match tgt_arch {
"armv5te" | "mips" | "mipsel" | "powerpc" | "riscv32imac" | "thumbv7em" | "thumbv7m"
| "thumbv8m.base" | "thumbv8m.main" | "armebv7r" | "armv7r" => atomics.has_64 = false,
// These ARMv7 targets have 32-bit pointers and 64-bit atomics.
"armv7" | "armv7a" | "armv7s" => atomics.has_64 = true,
// "riscv32imc-unknown-none-elf" and "riscv32imac-unknown-none-elf" are
// both `target_arch = "riscv32", and have no stable `cfg`-discoverable
// distinction. As such, the non-atomic RISC-V targets must be
// discovered here.
"riscv32i" | "riscv32imc" | "thumbv6m" => atomics = Atomics::NONE,
_ => {}
}
#[allow(clippy::match_single_binding, clippy::single_match)]
match &*env_arch {
"avr" => atomics = Atomics::NONE,
_ => {}
}
if atomics.has_8 {
println!("cargo:rustc-cfg=radium_atomic_8");
}
if atomics.has_16 {
println!("cargo:rustc-cfg=radium_atomic_16");
}
if atomics.has_32 {
println!("cargo:rustc-cfg=radium_atomic_32");
}
if atomics.has_64 {
println!("cargo:rustc-cfg=radium_atomic_64");
}
if atomics.has_ptr {
println!("cargo:rustc-cfg=radium_atomic_ptr");
}
Ok(())
}
+914
View File
@@ -0,0 +1,914 @@
//! `radium` provides a series of helpers for a uniform API over both atomic
//! types like [`AtomicUsize`], and non-atomic types like [`Cell<T>`].
//!
//! This crate is `#![no_std]`-compatible, and uses no non-core types.
//!
//! For details, see the documentation for [`Radium`].
//!
//! The `types` module provides type names that are atomic where the target
//! supports it, and fall back to `Cell` when the target does not.
//!
//! The `if_atomic!` macro provides a means of conditional compilation based on
//! the presence of atomic instructions. It is a substitute for the
//! `cfg(target_has_atomic)` or `cfg(accessible)` attribute tests, which are not
//! yet stabilized.
//!
//! ---
//!
//! **@kneecaw** - <https://twitter.com/kneecaw/status/1132695060812849154>
//! > Feelin' lazy: Has someone already written a helper trait abstracting
//! > operations over `AtomicUsize` and `Cell<usize>` for generic code which may
//! > not care about atomicity?
//!
//! **@ManishEarth** - <https://twitter.com/ManishEarth/status/1132706585300496384>
//! > no but call the crate radium
//! >
//! > (since people didn't care that it was radioactive and used it in everything)
//!
//! [`AtomicUsize`]: core::sync::atomic::AtomicUsize
//! [`Cell<T>`]: core::cell::Cell
#![no_std]
#![deny(unconditional_recursion)]
#[macro_use]
mod macros;
pub mod types;
use core::cell::Cell;
use core::sync::atomic::Ordering;
if_atomic! {
if atomic(8) {
use core::sync::atomic::{AtomicBool, AtomicI8, AtomicU8};
}
if atomic(16) {
use core::sync::atomic::{AtomicI16, AtomicU16};
}
if atomic(32) {
use core::sync::atomic::{AtomicI32, AtomicU32};
}
if atomic(64) {
use core::sync::atomic::{AtomicI64, AtomicU64};
}
if atomic(ptr) {
use core::sync::atomic::{AtomicIsize, AtomicPtr, AtomicUsize};
}
}
/// A maybe-atomic shared mutable fundamental type `T`.
///
/// This trait is implemented by both the [atomic wrapper] type for `T`, and by
/// [`Cell<T>`], providing a consistent interface for interacting with the two
/// types.
///
/// This trait provides methods predicated on marker traits for the underlying
/// fundamental. Only types which can be viewed as sequences of bits may use the
/// functions for bit-wise arithmetic, and only types which can be used as
/// integers may use the functions for numeric arithmetic. Use of these methods
/// on insufficient underlying types (for example, `Radium::fetch_and` on an
/// atomic or cell-wrapped pointer) will cause a compiler error.
///
/// [atomic wrapper]: core::sync::atomic
/// [`Cell<T>`]: core::cell::Cell
pub trait Radium {
type Item;
/// Creates a new value of this type.
fn new(value: Self::Item) -> Self;
/// If the underlying value is atomic, calls [`fence`] with the given
/// [`Ordering`]. Otherwise, does nothing.
///
/// [`Ordering`]: core::sync::atomic::Ordering
/// [`fence`]: core::sync::atomic::fence
fn fence(order: Ordering);
/// Returns a mutable reference to the underlying value.
///
/// This is safe because the mutable reference to `self` guarantees that no
/// other references exist to this value.
fn get_mut(&mut self) -> &mut Self::Item;
/// Consumes the wrapper and returns the contained value.
///
/// This is safe as passing by value ensures no other references exist.
fn into_inner(self) -> Self::Item;
/// Load a value from this object.
///
/// Ordering values are ignored by non-atomic types.
///
/// See also: [`AtomicUsize::load`].
///
/// [`AtomicUsize::load`]: core::sync::atomic::AtomicUsize::load
fn load(&self, order: Ordering) -> Self::Item;
/// Store a value in this object.
///
/// Ordering arguments are ignored by non-atomic types.
///
/// See also: [`AtomicUsize::store`].
///
/// [`AtomicUsize::store`]: core::sync::atomic::AtomicUsize::store
fn store(&self, value: Self::Item, order: Ordering);
/// Swap with the value stored in this object.
///
/// Ordering arguments are ignored by non-atomic types.
///
/// See also: [`AtomicUsize::swap`].
///
/// [`AtomicUsize::swap`]: core::sync::atomic::AtomicUsize::swap
fn swap(&self, value: Self::Item, order: Ordering) -> Self::Item;
/// Stores a value into this object if the currently-stored value is the
/// same as the `current` value.
///
/// The return value is always the previously-stored value. If it is equal to
/// `current`, then the value was updated with `new`.
///
/// Ordering arguments are ignored by non-atomic types.
///
/// See also: [`AtomicUsize::compare_and_swap`].
///
/// [`AtomicUsize::compare_and_swap`]: core::sync::atomic::AtomicUsize::compare_and_swap
#[deprecated = "Use `compare_exchange` or `compare_exchange_weak` instead"]
fn compare_and_swap(&self, current: Self::Item, new: Self::Item, order: Ordering)
-> Self::Item;
/// Stores a value into this object if the currently-stored value is the
/// same as the `current` value.
///
/// The return value is a `Result` indicating whether the new value was
/// written, and containing the previously-stored value. On success, this
/// value is guaranteed to be equal to `current`.
///
/// Ordering arguments are ignored by non-atomic types.
///
/// See also: [`AtomicUsize::compare_exchange`].
///
/// [`AtomicUsize::compare_exchange`]: core::sync::atomic::AtomicUsize::compare_exchange
fn compare_exchange(
&self,
current: Self::Item,
new: Self::Item,
success: Ordering,
failure: Ordering,
) -> Result<Self::Item, Self::Item>;
/// Stores a value into this object if the currently-stored value is the
/// same as the `current` value.
///
/// Unlike `compare_exchange`, this function is allowed to spuriously fail
/// even when the comparison succeeds, which can result in more efficient
/// code on some platforms. The return value is a `Result` indicating
/// whether the new value was written, and containing the previously-stored
/// value.
///
/// Ordering arguments are ignored by non-atomic types.
///
/// See also: [`AtomicUsize::compare_exchange_weak`].
///
/// [`AtomicUsize::compare_exchange_weak`]: core::sync::atomic::AtomicUsize::compare_exchange_weak
fn compare_exchange_weak(
&self,
current: Self::Item,
new: Self::Item,
success: Ordering,
failure: Ordering,
) -> Result<Self::Item, Self::Item>;
/// Performs a bitwise "and" on the currently-stored value and the argument
/// `value`, and stores the result in `self`.
///
/// Returns the previously-stored value.
///
/// Ordering arguments are ignored by non-atomic types.
///
/// See also: [`AtomicUsize::fetch_and`].
///
/// [`AtomicUsize::fetch_and`]: core::sync::atomic::AtomicUsize::fetch_and
fn fetch_and(&self, value: Self::Item, order: Ordering) -> Self::Item
where
Self::Item: marker::BitOps;
/// Performs a bitwise "nand" on the currently-stored value and the argument
/// `value`, and stores the result in `self`.
///
/// Returns the previously-stored value.
///
/// Ordering arguments are ignored by non-atomic types.
///
/// See also: [`AtomicUsize::fetch_nand`].
///
/// [`AtomicUsize::fetch_nand`]: core::sync::atomic::AtomicUsize::fetch_nand
fn fetch_nand(&self, value: Self::Item, order: Ordering) -> Self::Item
where
Self::Item: marker::BitOps;
/// Performs a bitwise "or" on the currently-stored value and the argument
/// `value`, and stores the result in `self`.
///
/// Returns the previously-stored value.
///
/// Ordering arguments are ignored by non-atomic types.
///
/// See also: [`AtomicUsize::fetch_or`].
///
/// [`AtomicUsize::fetch_or`]: core::sync::atomic::AtomicUsize::fetch_or
fn fetch_or(&self, value: Self::Item, order: Ordering) -> Self::Item
where
Self::Item: marker::BitOps;
/// Performs a bitwise "xor" on the currently-stored value and the argument
/// `value`, and stores the result in `self`.
///
/// Returns the previously-stored value.
///
/// Ordering arguments are ignored by non-atomic types.
///
/// See also: [`AtomicUsize::fetch_xor`].
///
/// [`AtomicUsize::fetch_xor`]: core::sync::atomic::AtomicUsize::fetch_xor
fn fetch_xor(&self, value: Self::Item, order: Ordering) -> Self::Item
where
Self::Item: marker::BitOps;
/// Adds `value` to the currently-stored value, wrapping on overflow, and
/// stores the result in `self`.
///
/// Returns the previously-stored value.
///
/// Ordering arguments are ignored by non-atomic types.
///
/// See also: [`AtomicUsize::fetch_add`].
///
/// [`AtomicUsize::fetch_add`]: core::sync::atomic::AtomicUsize::fetch_add
fn fetch_add(&self, value: Self::Item, order: Ordering) -> Self::Item
where
Self::Item: marker::NumericOps;
/// Subtracts `value` from the currently-stored value, wrapping on
/// underflow, and stores the result in `self`.
///
/// Returns the previously-stored value.
///
/// Ordering arguments are ignored by non-atomic types.
///
/// See also: [`AtomicUsize::fetch_sub`].
///
/// [`AtomicUsize::fetch_sub`]: core::sync::atomic::AtomicUsize::fetch_sub
fn fetch_sub(&self, value: Self::Item, order: Ordering) -> Self::Item
where
Self::Item: marker::NumericOps;
/// Fetches the value, and applies a function to it that returns an
/// optional new value.
///
/// Note: This may call the function multiple times if the value has been
/// changed from other threads in the meantime, as long as the function
/// returns `Some(_)`, but the function will have been applied only once to
/// the stored value.
///
/// Returns a `Result` of `Ok(previous_value)` if the function returned
/// `Some(_)`, else `Err(previous_value)`.
///
/// Ordering arguments are ignored by non-atomic types.
///
/// See also: [`AtomicUsize::fetch_update`].
///
/// [`AtomicUsize::fetch_update`]: core::sync::atomic::AtomicUsize::fetch_update
fn fetch_update<F>(
&self,
set_order: Ordering,
fetch_order: Ordering,
f: F,
) -> Result<Self::Item, Self::Item>
where
F: FnMut(Self::Item) -> Option<Self::Item>;
}
/// Marker traits used by [`Radium`].
pub mod marker {
/// Types supporting maybe-atomic bitwise operations.
///
/// Types implementing this trait support the [`fetch_and`], [`fetch_nand`],
/// [`fetch_or`], and [`fetch_xor`] maybe-atomic operations.
///
/// [`fetch_and`]: crate::Radium::fetch_and
/// [`fetch_nand`]: crate::Radium::fetch_nand
/// [`fetch_or`]: crate::Radium::fetch_or
/// [`fetch_xor`]: crate::Radium::fetch_xor
///
/// `bool` and all integer fundamental types implement this.
///
/// ```rust
/// # use core::sync::atomic::*;
/// # use radium::Radium;
/// let num: AtomicUsize = AtomicUsize::new(0);
/// Radium::fetch_or(&num, 2, Ordering::Relaxed);
/// ```
///
/// Pointers do not. This will cause a compiler error.
///
/// ```rust,compile_fail
/// # use core::sync::atomic::*;
/// # use radium::Radium;
/// # use core::ptr;
/// let ptr: AtomicPtr<usize> = Default::default();
/// Radium::fetch_or(&ptr, ptr::null_mut(), Ordering::Relaxed);
/// ```
pub trait BitOps {}
/// Types supporting maybe-atomic arithmetic operations.
///
/// Types implementing this trait support the [`fetch_add`] and
/// [`fetch_sub`] maybe-atomic operations.
///
/// [`fetch_add`]: crate::Radium::fetch_add
/// [`fetch_sub`]: crate::Radium::fetch_sub
///
/// The integer types, such as `usize` and `i32`, implement this trait.
///
/// ```rust
/// # use core::sync::atomic::*;
/// # use radium::Radium;
/// let num: AtomicUsize = AtomicUsize::new(2);
/// Radium::fetch_add(&num, 2, Ordering::Relaxed);
/// ```
///
/// `bool` and pointers do not. This will cause a compiler error.
///
/// ```rust,compile_fail
/// # use core::sync::atomic::*;
/// # use radium::Radium;
/// let bit: AtomicBool = AtomicBool::new(false);
/// Radium::fetch_add(&bit, true, Ordering::Relaxed);
/// ```
pub trait NumericOps: BitOps {}
}
macro_rules! radium {
// Emit the universal `Radium` trait function bodies for atomic types.
( atom $base:ty ) => {
#[inline]
fn new(value: $base) -> Self {
Self::new(value)
}
#[inline]
fn fence(order: Ordering) {
core::sync::atomic::fence(order);
}
#[inline]
fn get_mut(&mut self) -> &mut $base {
self.get_mut()
}
#[inline]
fn into_inner(self) -> $base {
self.into_inner()
}
#[inline]
fn load(&self, order: Ordering) -> $base {
self.load(order)
}
#[inline]
fn store(&self, value: $base, order: Ordering) {
self.store(value, order);
}
#[inline]
fn swap(&self, value: $base, order: Ordering) -> $base {
self.swap(value, order)
}
#[inline]
#[allow(deprecated)]
fn compare_and_swap(&self, current: $base, new: $base, order: Ordering) -> $base {
self.compare_and_swap(current, new, order)
}
#[inline]
fn compare_exchange(
&self,
current: $base,
new: $base,
success: Ordering,
failure: Ordering,
) -> Result<$base, $base> {
self.compare_exchange(current, new, success, failure)
}
#[inline]
fn compare_exchange_weak(
&self,
current: $base,
new: $base,
success: Ordering,
failure: Ordering,
) -> Result<$base, $base> {
self.compare_exchange_weak(current, new, success, failure)
}
#[inline]
fn fetch_update<F>(
&self,
set_order: Ordering,
fetch_order: Ordering,
f: F,
) -> Result<$base, $base>
where
F: FnMut($base) -> Option<$base>,
{
self.fetch_update(set_order, fetch_order, f)
}
};
// Emit the `Radium` trait function bodies for bit-wise types.
( atom_bit $base:ty ) => {
#[inline]
fn fetch_and(&self, value: $base, order: Ordering) -> $base {
self.fetch_and(value, order)
}
#[inline]
fn fetch_nand(&self, value: $base, order: Ordering) -> $base {
self.fetch_nand(value, order)
}
#[inline]
fn fetch_or(&self, value: $base, order: Ordering) -> $base {
self.fetch_or(value, order)
}
#[inline]
fn fetch_xor(&self, value: $base, order: Ordering) -> $base {
self.fetch_xor(value, order)
}
};
// Emit the `Radium` trait function bodies for integral types.
( atom_int $base:ty ) => {
#[inline]
fn fetch_add(&self, value: $base, order: Ordering) -> $base {
self.fetch_add(value, order)
}
#[inline]
fn fetch_sub(&self, value: $base, order: Ordering) -> $base {
self.fetch_sub(value, order)
}
};
// Emit the universal `Radium` trait function bodies for `Cell<_>`.
( cell $base:ty ) => {
#[inline]
fn new(value: $base) -> Self {
Cell::new(value)
}
#[inline]
fn fence(_: Ordering) {}
#[inline]
fn get_mut(&mut self) -> &mut $base {
self.get_mut()
}
#[inline]
fn into_inner(self) -> $base {
self.into_inner()
}
#[inline]
fn load(&self, _: Ordering) -> $base {
self.get()
}
#[inline]
fn store(&self, value: $base, _: Ordering) {
self.set(value);
}
#[inline]
fn swap(&self, value: $base, _: Ordering) -> $base {
self.replace(value)
}
#[inline]
fn compare_and_swap(&self, current: $base, new: $base, _: Ordering) -> $base {
if self.get() == current {
self.replace(new)
} else {
self.get()
}
}
#[inline]
fn compare_exchange(
&self,
current: $base,
new: $base,
_: Ordering,
_: Ordering,
) -> Result<$base, $base> {
if self.get() == current {
Ok(self.replace(new))
} else {
Err(self.get())
}
}
#[inline]
fn compare_exchange_weak(
&self,
current: $base,
new: $base,
success: Ordering,
failure: Ordering,
) -> Result<$base, $base> {
Radium::compare_exchange(self, current, new, success, failure)
}
#[inline]
fn fetch_update<F>(&self, _: Ordering, _: Ordering, mut f: F) -> Result<$base, $base>
where
F: FnMut($base) -> Option<$base>,
{
match f(self.get()) {
Some(x) => Ok(self.replace(x)),
None => Err(self.get()),
}
}
};
// Emit the `Radium` trait function bodies for bit-wise types.
( cell_bit $base:ty ) => {
#[inline]
fn fetch_and(&self, value: $base, _: Ordering) -> $base {
self.replace(self.get() & value)
}
#[inline]
fn fetch_nand(&self, value: $base, _: Ordering) -> $base {
self.replace(!(self.get() & value))
}
#[inline]
fn fetch_or(&self, value: $base, _: Ordering) -> $base {
self.replace(self.get() | value)
}
#[inline]
fn fetch_xor(&self, value: $base, _: Ordering) -> $base {
self.replace(self.get() ^ value)
}
};
// Emit the `Radium` trait function bodies for integral types.
( cell_int $base:ty ) => {
#[inline]
fn fetch_add(&self, value: $base, _: Ordering) -> $base {
self.replace(self.get().wrapping_add(value))
}
#[inline]
fn fetch_sub(&self, value: $base, _: Ordering) -> $base {
self.replace(self.get().wrapping_sub(value))
}
};
}
macro_rules! radium_int {
( $( $width:tt: $base:ty , $atom:ty ; )* ) => { $(
impl marker::BitOps for $base {}
impl marker::NumericOps for $base {}
if_atomic!(if atomic($width) {
impl Radium for $atom {
type Item = $base;
radium!(atom $base);
radium!(atom_bit $base);
radium!(atom_int $base);
}
});
impl Radium for Cell<$base> {
type Item = $base;
radium!(cell $base);
radium!(cell_bit $base);
radium!(cell_int $base);
}
)* };
}
radium_int! {
8: i8, AtomicI8;
8: u8, AtomicU8;
16: i16, AtomicI16;
16: u16, AtomicU16;
32: i32, AtomicI32;
32: u32, AtomicU32;
64: i64, AtomicI64;
64: u64, AtomicU64;
size: isize, AtomicIsize;
size: usize, AtomicUsize;
}
impl marker::BitOps for bool {}
if_atomic!(if atomic(bool) {
impl Radium for AtomicBool {
type Item = bool;
radium!(atom bool);
radium!(atom_bit bool);
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let atom = AtomicBool::new(false);
/// Radium::fetch_add(&atom, true, Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_add(&self, _value: bool, _order: Ordering) -> bool {
unreachable!("This method statically cannot be called")
}
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let atom = AtomicBool::new(false);
/// Radium::fetch_sub(&atom, true, Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_sub(&self, _value: bool, _order: Ordering) -> bool {
unreachable!("This method statically cannot be called")
}
}
});
impl Radium for Cell<bool> {
type Item = bool;
radium!(cell bool);
radium!(cell_bit bool);
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let cell = Cell::<bool>::new(false);
/// Radium::fetch_add(&cell, true, Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_add(&self, _value: bool, _order: Ordering) -> bool {
unreachable!("This method statically cannot be called")
}
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let cell = Cell::<bool>::new(false);
/// Radium::fetch_sub(&cell, true, Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_sub(&self, _value: bool, _order: Ordering) -> bool {
unreachable!("This method statically cannot be called")
}
}
if_atomic!(if atomic(ptr) {
impl<T> Radium for AtomicPtr<T> {
type Item = *mut T;
radium!(atom *mut T);
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
/// Radium::fetch_and(&atom, ptr::null_mut(), Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_and(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
/// Radium::fetch_nand(&atom, ptr::null_mut(), Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_nand(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
/// Radium::fetch_or(&atom, ptr::null_mut(), Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_or(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
/// Radium::fetch_xor(&atom, ptr::null_mut(), Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_xor(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
/// Radium::fetch_add(&atom, ptr::null_mut(), Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_add(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let atom = AtomicPtr::<u8>::new(ptr::null_mut());
/// Radium::fetch_sub(&atom, ptr::null_mut(), Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_sub(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
}
});
impl<T> Radium for Cell<*mut T> {
type Item = *mut T;
radium!(cell *mut T);
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let cell = Cell::<*mut u8>::new(ptr::null_mut());
/// Radium::fetch_and(&cell, ptr::null_mut(), Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_and(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let cell = Cell::<*mut u8>::new(ptr::null_mut());
/// Radium::fetch_nand(&cell, ptr::null_mut(), Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_nand(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let cell = Cell::<*mut u8>::new(ptr::null_mut());
/// Radium::fetch_or(&cell, ptr::null_mut(), Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_or(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let cell = Cell::<*mut u8>::new(ptr::null_mut());
/// Radium::fetch_xor(&cell, ptr::null_mut(), Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_xor(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let cell = Cell::<*mut u8>::new(ptr::null_mut());
/// Radium::fetch_add(&cell, ptr::null_mut(), Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_add(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
/// ```compile_fail
/// # use std::{ptr, sync::atomic::*, cell::*};
/// # use radium::*;
/// let cell = Cell::<*mut u8>::new(ptr::null_mut());
/// Radium::fetch_sub(&cell, ptr::null_mut(), Ordering::Relaxed);
/// ```
#[doc(hidden)]
fn fetch_sub(&self, _value: *mut T, _order: Ordering) -> *mut T {
unreachable!("This method statically cannot be called")
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::cell::Cell;
#[test]
fn absent_traits() {
static_assertions::assert_not_impl_any!(bool: marker::NumericOps);
static_assertions::assert_not_impl_any!(*mut u8: marker::BitOps, marker::NumericOps);
}
#[test]
fn present_traits() {
static_assertions::assert_impl_all!(bool: marker::BitOps);
static_assertions::assert_impl_all!(usize: marker::BitOps, marker::NumericOps);
}
#[test]
fn always_cell() {
static_assertions::assert_impl_all!(Cell<bool>: Radium<Item = bool>);
static_assertions::assert_impl_all!(Cell<i8>: Radium<Item = i8>);
static_assertions::assert_impl_all!(Cell<u8>: Radium<Item = u8>);
static_assertions::assert_impl_all!(Cell<i16>: Radium<Item = i16>);
static_assertions::assert_impl_all!(Cell<u16>: Radium<Item = u16>);
static_assertions::assert_impl_all!(Cell<i32>: Radium<Item = i32>);
static_assertions::assert_impl_all!(Cell<u32>: Radium<Item = u32>);
static_assertions::assert_impl_all!(Cell<i64>: Radium<Item = i64>);
static_assertions::assert_impl_all!(Cell<u64>: Radium<Item = u64>);
static_assertions::assert_impl_all!(Cell<isize>: Radium<Item = isize>);
static_assertions::assert_impl_all!(Cell<usize>: Radium<Item = usize>);
static_assertions::assert_impl_all!(Cell<*mut ()>: Radium<Item = *mut ()>);
}
#[test]
fn always_alias() {
static_assertions::assert_impl_all!(types::RadiumBool: Radium<Item = bool>);
static_assertions::assert_impl_all!(types::RadiumI8: Radium<Item = i8>);
static_assertions::assert_impl_all!(types::RadiumU8: Radium<Item = u8>);
static_assertions::assert_impl_all!(types::RadiumI16: Radium<Item = i16>);
static_assertions::assert_impl_all!(types::RadiumU16: Radium<Item = u16>);
static_assertions::assert_impl_all!(types::RadiumI32: Radium<Item = i32>);
static_assertions::assert_impl_all!(types::RadiumU32: Radium<Item = u32>);
static_assertions::assert_impl_all!(types::RadiumI64: Radium<Item = i64>);
static_assertions::assert_impl_all!(types::RadiumU64: Radium<Item = u64>);
static_assertions::assert_impl_all!(types::RadiumIsize: Radium<Item = isize>);
static_assertions::assert_impl_all!(types::RadiumUsize: Radium<Item = usize>);
static_assertions::assert_impl_all!(types::RadiumPtr<()>: Radium<Item = *mut ()>);
}
#[test]
fn maybe_atom() {
if_atomic! {
if atomic(bool) {
use core::sync::atomic::*;
static_assertions::assert_impl_all!(AtomicBool: Radium<Item = bool>);
}
if atomic(8) {
static_assertions::assert_impl_all!(AtomicI8: Radium<Item = i8>);
static_assertions::assert_impl_all!(AtomicU8: Radium<Item = u8>);
}
if atomic(16) {
static_assertions::assert_impl_all!(AtomicI16: Radium<Item = i16>);
static_assertions::assert_impl_all!(AtomicU16: Radium<Item = u16>);
}
if atomic(32) {
static_assertions::assert_impl_all!(AtomicI32: Radium<Item = i32>);
static_assertions::assert_impl_all!(AtomicU32: Radium<Item = u32>);
}
if atomic(64) {
static_assertions::assert_impl_all!(AtomicI64: Radium<Item = i64>);
static_assertions::assert_impl_all!(AtomicU64: Radium<Item = u64>);
}
if atomic(size) {
static_assertions::assert_impl_all!(AtomicIsize: Radium<Item = isize>);
static_assertions::assert_impl_all!(AtomicUsize: Radium<Item = usize>);
}
if atomic(ptr) {
static_assertions::assert_impl_all!(AtomicPtr<()>: Radium<Item = *mut ()>);
}
}
}
}
+178
View File
@@ -0,0 +1,178 @@
#[doc(hidden)]
#[macro_export]
#[cfg(radium_atomic_8)]
macro_rules! __radium_if_atomic_8 {
( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
}
#[doc(hidden)]
#[macro_export]
#[cfg(not(radium_atomic_8))]
macro_rules! __radium_if_atomic_8 {
( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
}
#[doc(hidden)]
#[macro_export]
#[cfg(radium_atomic_16)]
macro_rules! __radium_if_atomic_16 {
( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
}
#[doc(hidden)]
#[macro_export]
#[cfg(not(radium_atomic_16))]
macro_rules! __radium_if_atomic_16 {
( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
}
#[doc(hidden)]
#[macro_export]
#[cfg(radium_atomic_32)]
macro_rules! __radium_if_atomic_32 {
( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
}
#[doc(hidden)]
#[macro_export]
#[cfg(not(radium_atomic_32))]
macro_rules! __radium_if_atomic_32 {
( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
}
#[doc(hidden)]
#[macro_export]
#[cfg(radium_atomic_64)]
macro_rules! __radium_if_atomic_64 {
( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
}
#[doc(hidden)]
#[macro_export]
#[cfg(not(radium_atomic_64))]
macro_rules! __radium_if_atomic_64 {
( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
}
#[doc(hidden)]
#[macro_export]
#[cfg(radium_atomic_ptr)]
macro_rules! __radium_if_atomic_ptr {
( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($a)* }
}
#[doc(hidden)]
#[macro_export]
#[cfg(not(radium_atomic_ptr))]
macro_rules! __radium_if_atomic_ptr {
( [ $( $a:tt )* ] [ $( $b:tt )* ] ) => { $($b)* }
}
/// Conditional compilation based on the presence of atomic instructions.
///
/// This macro allows you to write `if`/`else` clauses, evaluated at
/// compile-time, that test the presence of atomic instructions and preserve or
/// destroy their guarded code accordingly.
///
/// The `if atomic(WIDTH)` test preserves the contents of its block when the
/// target architecture has atomic instructions for the requested `WIDTH`, and
/// removes them from the syntax tree when the target does not. If an `else`
/// clause is provided, the contents of the `else` block are used as a
/// substitute when the `if` is destroyed.
///
/// This macro can be used in any position. When it is used in item or statement
/// position, it can contain multiple `if` clauses, and each will be evaluated
/// in turn. Expression and type positions can only accept exactly one code
/// span, and so may only have exactly one `if`/`else` clause. An `else` clause
/// is required here so that the macro will always expand to something; an empty
/// expansion is a parse error.
///
/// # Macro Syntax
///
/// The macro contents `if atomic() {} else {}` are part of the macro
/// invocation. Only the contents of the two blocks are actual Rust code.
///
/// The acceptable arguments to `atomic()` are:
///
/// - `8`
/// - `16`
/// - `32`
/// - `64`
/// - `ptr`
/// - `bool`: alias for `8`
/// - `size`: alias for `ptr`
///
/// In addition, the `atomic()` test can be inverted, as `!atomic()`, to reverse
/// the preserve/destroy behavior of the `if` and `else` blocks.
///
/// # Examples
///
/// This demonstrates the use of `if_atomic!` to produce multiple statements,
/// and then to produce a single type-name.
///
/// ```rust
/// radium::if_atomic! {
/// if atomic(size) { use core::sync::atomic::AtomicUsize; }
/// if !atomic(size) { use core::cell::Cell; }
/// }
///
/// struct RadiumRc<T: ?Sized> {
/// strong: radium::if_atomic! {
/// if atomic(ptr) { AtomicUsize }
/// else { Cell<usize> }
/// },
/// weak: radium::types::RadiumUsize,
/// data: T,
/// }
/// ```
#[macro_export]
macro_rules! if_atomic {
( if atomic(8) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
$crate::__radium_if_atomic_8! {
[ $($a)* ] [ $( $($b)* )? ]
}
$($crate::if_atomic! { if $($rest)* })?
};
( if atomic(16) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
$crate::__radium_if_atomic_16! {
[ $($a)* ] [ $( $($b)* )? ]
}
$( $crate::if_atomic! { if $($rest)* } )?
};
( if atomic(32) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
$crate::__radium_if_atomic_32! {
[ $($a)* ] [ $( $($b)* )? ]
}
$( $crate::if_atomic! { if $($rest)* } )?
};
( if atomic(64) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
$crate::__radium_if_atomic_64! {
[ $($a)* ] [ $( $($b)* )? ]
}
$( $crate::if_atomic! { if $($rest)* } )?
};
( if atomic(ptr) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
$crate::__radium_if_atomic_ptr! {
[ $($a)* ] [ $( $($b)* )? ]
}
$( $crate::if_atomic! { if $($rest)* } )?
};
( if atomic(bool) $($rest:tt)* ) => {
$crate::if_atomic! { if atomic(8) $($rest)* }
};
( if atomic(size) $($rest:tt)* ) => {
$crate::if_atomic! { if atomic(ptr) $($rest)* }
};
( if ! atomic( $t:tt ) { $($a:tt)* } $( else { $($b:tt)* } )? $( if $($rest:tt)* )? ) => {
$crate::if_atomic! {
if atomic($t) { $( $($b)* )? } else { $($a)* } $( if $($rest)* )?
}
};
}
+78
View File
@@ -0,0 +1,78 @@
//! Best-effort atomic types
//!
//! This module exports `RadiumType` aliases that map to the `AtomicType` on
//! targets that have it, or `Cell<type>` on targets that do not. This alias can
//! be used as a consistent name for crates that need portable names for
//! non-portable types.
/// Best-effort atomic `bool` type.
pub type RadiumBool = if_atomic! {
if atomic(bool) { core::sync::atomic::AtomicBool }
else { core::cell::Cell<bool> }
};
/// Best-effort atomic `i8` type.
pub type RadiumI8 = if_atomic! {
if atomic(8) { core::sync::atomic::AtomicI8 }
else { core::cell::Cell<i8> }
};
/// Best-effort atomic `u8` type.
pub type RadiumU8 = if_atomic! {
if atomic(8) { core::sync::atomic::AtomicU8 }
else { core::cell::Cell<u8> }
};
/// Best-effort atomic `i16` type.
pub type RadiumI16 = if_atomic! {
if atomic(16) { core::sync::atomic::AtomicI16 }
else { core::cell::Cell<i16> }
};
/// Best-effort atomic `u16` type.
pub type RadiumU16 = if_atomic! {
if atomic(16) { core::sync::atomic::AtomicU16 }
else { core::cell::Cell<u16> }
};
/// Best-effort atomic `i32` type.
pub type RadiumI32 = if_atomic! {
if atomic(32) { core::sync::atomic::AtomicI32 }
else { core::cell::Cell<i32> }
};
/// Best-effort atomic `u32` type.
pub type RadiumU32 = if_atomic! {
if atomic(32) { core::sync::atomic::AtomicU32 }
else { core::cell::Cell<u32> }
};
/// Best-effort atomic `i64` type.
pub type RadiumI64 = if_atomic! {
if atomic(64) { core::sync::atomic::AtomicI64 }
else { core::cell::Cell<i64> }
};
/// Best-effort atomic `u64` type.
pub type RadiumU64 = if_atomic! {
if atomic(64) { core::sync::atomic::AtomicU64 }
else { core::cell::Cell<u64> }
};
/// Best-effort atomic `isize` type.
pub type RadiumIsize = if_atomic! {
if atomic(size) { core::sync::atomic::AtomicIsize }
else { core::cell::Cell<isize> }
};
/// Best-effort atomic `usize` type.
pub type RadiumUsize = if_atomic! {
if atomic(size) { core::sync::atomic::AtomicUsize }
else { core::cell::Cell<usize> }
};
/// Best-effort atomic pointer type.
pub type RadiumPtr<T> = if_atomic! {
if atomic(ptr) { core::sync::atomic::AtomicPtr<T> }
else { core::cell::Cell<*mut T> }
};