Import radium 0.7.0 upstream upstream/0.7.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 24 Mar 2023 01:51:31 +0000 (10:51 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 24 Mar 2023 01:51:31 +0000 (10:51 +0900)
.cargo_vcs_info.json [new file with mode: 0644]
Cargo.lock [new file with mode: 0644]
Cargo.toml [new file with mode: 0644]
Cargo.toml.orig [new file with mode: 0644]
LICENSE.txt [new file with mode: 0644]
README.md [new file with mode: 0644]
build.rs [new file with mode: 0644]
src/lib.rs [new file with mode: 0644]
src/macros.rs [new file with mode: 0644]
src/types.rs [new file with mode: 0644]

diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644 (file)
index 0000000..389764d
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "git": {
+    "sha1": "3f27e0d827338aee919213fd071b99819a1b9fff"
+  }
+}
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644 (file)
index 0000000..ae34cac
--- /dev/null
@@ -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"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644 (file)
index 0000000..6bfe43d
--- /dev/null
@@ -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"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644 (file)
index 0000000..8204e6d
--- /dev/null
@@ -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"
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644 (file)
index 0000000..504df28
--- /dev/null
@@ -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.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..81e3cf0
--- /dev/null
+++ b/README.md
@@ -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 architecture’s 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 compiler’s 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
diff --git a/build.rs b/build.rs
new file mode 100644 (file)
index 0000000..884ec99
--- /dev/null
+++ b/build.rs
@@ -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(())
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644 (file)
index 0000000..00e9588
--- /dev/null
@@ -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 ()>);
+            }
+        }
+    }
+}
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644 (file)
index 0000000..9f0a623
--- /dev/null
@@ -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)* )?
+        }
+    };
+}
diff --git a/src/types.rs b/src/types.rs
new file mode 100644 (file)
index 0000000..c73b0db
--- /dev/null
@@ -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> }
+};