radium-1.1.0/.cargo_vcs_info.json 0000644 00000000144 00000000001 0012313 0 ustar {
"git": {
"sha1": "68ab1dce6ad46442fe8681df75674737120ab115"
},
"path_in_vcs": "radium"
} radium-1.1.0/Cargo.lock 0000644 00000001454 00000000001 0010273 0 ustar # This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "portable-atomic"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b"
[[package]]
name = "radium"
version = "1.1.0"
dependencies = [
"cfg-if",
"portable-atomic",
"static_assertions",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
radium-1.1.0/Cargo.toml 0000644 00000002477 00000000001 0010324 0 ustar # 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 = "2021"
rust-version = "1.60"
name = "radium"
version = "1.1.0"
include = [
"Cargo.toml",
"src/**/*.rs",
"README.md",
"doc/**/*.md",
"LICENSE.txt",
]
description = "Portable interfaces for maybe-atomic types"
homepage = "https://ferrilab.github.io/ferrilab"
documentation = "https://docs.rs/radium"
readme = "README.md"
keywords = [
"atomic",
"cell",
"sync",
"generic",
"trait",
]
categories = [
"concurrency",
"no-std",
]
license = "MIT"
repository = "https://github.com/ferrilab/ferrilab"
[dependencies.cfg-if]
version = "1"
[dependencies.portable-atomic]
version = "1"
optional = true
default-features = false
[dev-dependencies.static_assertions]
version = "1.1"
[features]
portable-atomic = ["dep:portable-atomic"]
portable-atomic-fallback = [
"portable-atomic",
"portable-atomic/fallback",
]
radium-1.1.0/Cargo.toml.orig 0000644 0000000 0000000 00000001466 00726746425 0014032 0 ustar 0000000 0000000 [package]
name = "radium"
version = "1.1.0"
license = "MIT"
readme = "README.md"
repository = "https://github.com/ferrilab/ferrilab"
homepage = "https://ferrilab.github.io/ferrilab"
documentation = "https://docs.rs/radium"
description = "Portable interfaces for maybe-atomic types"
keywords = [
"atomic",
"cell",
"sync",
"generic",
"trait",
]
categories = [
"concurrency",
"no-std",
]
include = [
"Cargo.toml",
"src/**/*.rs",
"README.md",
"doc/**/*.md",
"LICENSE.txt",
]
edition = "2021"
rust-version = "1.60"
[features]
portable-atomic = [
"dep:portable-atomic",
]
portable-atomic-fallback = [
"portable-atomic",
"portable-atomic/fallback",
]
[dependencies]
cfg-if = "1"
[dependencies.portable-atomic]
version = "1"
optional = true
default-features = false
[dev-dependencies]
static_assertions = "1.1"
radium-1.1.0/LICENSE.txt 0000644 0000000 0000000 00000002067 00726746425 0012764 0 ustar 0000000 0000000 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.
radium-1.1.0/README.md 0000644 0000000 0000000 00000016014 00726746425 0012415 0 ustar 0000000 0000000
# Radium
[![Latest Version][version_img]][crate_link]
[![MSRV][msrv_img]][crate_link]
[![Documentation][docs_img]][docs_link]
[![Crate Downloads][downloads_img]][crate_link]
Radium provides unifying abstractions and graceful degradation for code that
requires shared-mutability, but does not necessarily require hardware-level
atomicity to provide it.
The primary export is the [`Radium`] trait. This is implemented on all of the
types in the standard library’s [`atomic`] module, as well as the [`Cell`]
wrappers over `bool`, the integers, and mutable pointers. Your code can be
generic over the `Radium` trait and use a stable and consistent API, and permit
client code to provide atomic or non-atomic types as they are able.
Additionally, Radium provides three type families with varying guarantees of
atomic behavior: [`Atom`] wraps the standard library atomics, and only
accepts `T` parameters where the target has an `AtomicT` type; [`Isotope`]
accepts any of the types which could be atomic, and wraps atomics where they
exist and silently decays to `Cell` where they do not; and [`Radon`] wraps
`Cell`. All three of these types have no API except for implementing
`Radium`, `Debug`, `Default`, and `From`, so your code can switch between
them without needing to worry about changing usage.
Lastly, Radium provides `RadiumT` type aliases matching all of the `AtomicT`
type names in the standard library. Each of these aliases forwards to its atomic
variant when it exists, and to `Cell` when it does not. Your code can use
these names to be portable across targets with varying levels of atomic support
without having to worry about the fact that `AtomicT` symbols vanish on targets
that do not have the requisite atomic instructions.
The Rust compiler [stabilized][0] the `cfg(target_has_atomic)` test in version
1.60. This is now the MSRV for Radium 1.0. The version-0 series will stay
supported for the indeterminate future to allow for pre-1.60 projects to
continue to use it. The `radium::if_atomic!` macro allows projects to simulate
`#[cfg(target_has_atomic)]` in version-0, but is removed in version-1.
This crate is `#![no_std]`-compatible, as it relies solely on the
`core::sync::atomic` and `core::cell` modules.
## Versioning
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.
As of Rust 1.60, support for 128-bit atomics is still unstable. Since Radium
commits to being usable on the stable release series, it does not support
128-bit atomics. As a compromise, `Cell<{i,u}128>` *is* integrated with Radium
to prepare for stabilizaation in the future.
If 128-bit atomics are removed from the standard library without stabilization,
Radium will remove support for `Cell<{i,u}128>` in a major-version increase.
## Non-Standard Implementors
In addition to the Rust standard library `Cell` and `Atomic` types, we also
provide an implementation for the [`portable-atomic`] crate. However, the
`portable-atomic` implementation cannot compile on a select few targets. As of
1.60, they are:
- `thumbv6m-none-eabi`
- `riscv32i-unknown-none-elf`
- `riscv32imc-unknown-none-elf`
These targets have 32-bit atomic load and store instructions, but do not have
read/modify/write instructions. Since `Radium` demands RMU behavior, and
`portable-atomic` does not provide it even in software (the `.fetch_action`
methods are all missing), we do not attempt to handle these targets gracefully
and simply allow the compile to fail.
Do not use the `portable-atomic` feature when compiling for these targets.
We disable all `portable-atomic` features, including the default-on `fallback`
feature. This causes `portable-atomic` to only generate symbols that match what
the standard library provides on that target. If you enable
`portable-atomic/fallback` in your own crate, then these symbols will exist, but
`radium` will not be able to see them because `#[cfg(feature = "...")]` cannot
query *other* crates’ enabled feature set. You will need to set radium’s
`portable-atomic-fallback` feature to get `Radium` implementations for atomic
operations wider than what the target instruction set supports.
## Pre-1.60 Target Discovery
Because the compiler did not make atomic support on targets accessible to
libraries, Radium used a build script to detect the target architecture and emit
its own directives that marked the presence or absence of an atomic integer. We
accomplished this by reading the compiler’s target information records and
copying the information directly into our build script.
If Radium v0 does not work for your architecture, please update the build script
to handle your target string and submit a pull request against the v0 branch.
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 environment
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 attempted parse.
----
## Project Origins
**@kneecaw** -
> Feelin' lazy: Has someone already written a helper trait abstracting
> operations over `AtomicUsize` and `Cell` for generic code which may not
> care about atomicity?
**@ManishEarth** -
> no but call the crate radium
>
> (since people didn't care that it was radioactive and used it in everything)
[crate_link]: https://crates.io/crates/radium "Crates.io package"
[docs_img]: https://img.shields.io/docsrs/radium/latest.svg?style=for-the-badge "Radium documentation badge"
[docs_link]: https://docs.rs/radium "Radium documentation"
[downloads_img]: https://img.shields.io/crates/dv/radium.svg?style=for-the-badge "Crate downloads"
[msrv_img]: https://img.shields.io/badge/MSRV-1.60-f46623?style=for-the-badge&logo=rust "Minimum Supported Rust Version: 1.60"
[version_img]: https://img.shields.io/crates/v/radium?color=f46623&style=for-the-badge "Radium version badge"
[`Atom`]: https://docs.rs/radium/latest/radium/types/struct.Atom.html
[`Cell`]: https://doc.rust-lang.org/core/cell/struct.Cell.html
[`Isotope`]: https://docs.rs/radium/latest/radium/types/struct.Isotope.html
[`Radium`]: https://docs.rs/radium/latest/radium/trait.Radium.html
[`Radon`]: https://docs.rs/radium/latest/radium/types/struct.Radon.html
[`atomic`]: https://doc.rust-lang.org/core/sync/atomic
[`portable-atomic`]: https://docs.rs/portable-atomic/1
[0]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1600-2022-04-07
radium-1.1.0/doc/atom.md 0000644 0000000 0000000 00000001225 00726746425 0013163 0 ustar 0000000 0000000 # Atomic Primitives
This family takes a Rust primitive (`bool`, integer, or pointer) as a type
parameter and acts as the corresponding `AtomicT` type. Attempting to construct
an `Atom` on a target that has no `AtomicT` will cause a compilation failure
stating that `T` does not implement the `Atomic` trait. The [`Isotope`]
sibling type will never fail to compile, but in exchange does not guarantee
atomic behavior.
This type implements the [`Radium`] API, as well as the `Debug`, `Default`, and
`From` traits that the standard library atomics implement. It has no other
API surface.
[`Isotope`]: crate::types::Isotope
[`Radium`]: crate::Radium
radium-1.1.0/doc/isotope.md 0000644 0000000 0000000 00000001431 00726746425 0013704 0 ustar 0000000 0000000 # Best-Effort Atomic Primitives
This family takes a Rust primitive (`bool`, integer, or pointer) as a type
parameter and acts as the corresponding `RadiumT` type. Unlike the [`Atom`]
sibling type, this type will never produce a compiler error when instantiated
(with a valid primitive). When the requisite atomic support is missing on the
target architecture, it falls back to acting as a `Cell`.
This type implements the [`Radium`] API, as well as the `Debug`, `Default`, and
`From` traits that the standard library atomics implement. It has no other
API surface, and in particular *does not* attempt to follow the `Cell` API.
See also [`Radon`], which is always strictly non-atomic.
[`Atom`]: crate::types::Atom
[`Radium`]: crate::Radium
[`Radon`]: crate::types::Radon
radium-1.1.0/doc/radium.md 0000644 0000000 0000000 00000005004 00726746425 0013503 0 ustar 0000000 0000000 # Unified Shared-Mutable API
The `Radium` trait is a common interface for shared-mutable types. We provide
implementations for the `AtomicT` and `Cell` types in the standard library,
as well as our [alternative types][types]. It mirrors the API of the Rust
[atomic] types.
You should consult the Rust standard library documentation for the correct usage
of all methods. While we refer to, and draw on, the Rust project’s work, we do
not guarantee keeping our language up to date with it.
Some of the `Radium` methods are gated on marker types in order to prevent their
use when the underlying primitive does not support them. For instance, pointers
do not (at time of writing) support atomic bit-wise or numeric operations, and
so cannot be used with any of the `.fetch_modify()` methods. Attempting to call
these methods will cause a compiler error when the underlying primitive type is
unsuitable.
## Usage
You should use this trait as a type parameter in your API when you want to
accept *something* that supports shared-mutability, but you don’t need to care
about what it is. You will likely want to specify the `Item` to be a known type,
by writing this bound: `>` where `T` is another generic
parameter or a named primitive.
Radium does *not* provide any unified trait system for the Rust primitives! If
you want to accept `Radium::Item` as a generic parameter, you will need to use
another crate (for instance, [`funty`]) to describe behavior over generic
primitives.
## Non-Usage
If you do not wish to expose caller-specified shared-mutability in your API, you
should instead use the [`radium::types`][types] module. The types in that module
all implement `Radium` as their only behavior, but may be easier to use when you
are describing particular data types.
## Safety
This trait is marked as `unsafe` to implement, because it abstracts over types
which can be mutated through a shared reference. The implementor is required to
correctly synchronize writes that occur through `Radium` methods, and in
particular, to never violate the Rust language’s rules about the invalid
production of unique references.
## Implementation
While we do not enforce any restrictions on `Radium` implementors, only types
which are transparent wrappers over a Rust primitive should implement this.
Out-of-line guards such as `Mutex` can technically satisfy its API requirements,
but are not likely to be useful candidate types for these uses.
[atomic]: core::sync::atomic
[types]: crate::types
[`funty`]: //crates.io/crates/funty
radium-1.1.0/doc/radon.md 0000644 0000000 0000000 00000001732 00726746425 0013331 0 ustar 0000000 0000000 # Non-Atomic Primitives
This family takes a Rust primitive (`bool`, integer, or pointer) as a type
parameter and wraps it in a `Cell`. Like `Atom` and `Isotope`, it
implements *only* the [`Radium`] API (and `Debug`, `Default`, and `From`),
and as such is suitable for cases where a crate wants to turn off atomic usage
entirely, while guaranteeing that swapping out types will not cause a
compilation failure.
## Examples
Consider a crate with an `"atomic"` feature. It might decide to *attempt* atomic
behavior when this flag is on, and unconditionally deny it when the flag is off:
```rust
#[cfg(feature = "atomic")]
pub type MyAtom = radium::types::Isotope;
#[cfg(not(feature = "atomic"))]
pub type MyAtom = radium::types::Radon;
```
## Behind the Name
Radium decays into radon, and the `Radon` type is a “decayed” `Radium`
implementor. Radon gas is also poisonous, and `Radon` poisons your codebase
against multithreading.
[`Radium`]: crate::Radium
radium-1.1.0/doc/types.md 0000644 0000000 0000000 00000002440 00726746425 0013367 0 ustar 0000000 0000000 # Aliases and Type Families
This module provides `RadiumT` aliases that correspond to `AtomicT` from the
standard library, and resolve to `AtomicT` when it exists and `Cell` when it
does not.
In addition, newtype structs `Atom` and `Isotope` correspond to (and
contain) `AtomicT` and `RadiumT`, respectively. These newtypes are designed to
be used in cases where you are generic over a primitive and want to plug it into
a shared-mutable wrapper type without having to specifically name one of the
`AtomicT` or `RadiumT` individual names.
Lastly, the `Radon` newtype struct wraps `Cell` and only implements the
`Radium` API, mirroring `Atom` and `Isotope`. This type exists so that
client crates can switch out types based on a crate feature to disable atomics,
and guarantee that their API will continue to function in every regard (except
for losing `Sync` impls).
## Examples
```rust
use radium::{Radium, types::*};
#[cfg(target_has_atomic = "ptr")]
let a = Atom::new(0usize);
let b = Isotope::new(1usize);
let c = Radon::new(2usize);
// when atomics are not disabled, use best-effort
#[cfg(feature = "atomics")]
pub type MyIsotope = Isotope;
// when atomics are fully disabled, enforce use of `Cell`
#[cfg(not(feature = "atomics"))]
pub type MyIsotope = Radon;
```
radium-1.1.0/src/lib.rs 0000644 0000000 0000000 00000057674 00726746425 0013062 0 ustar 0000000 0000000 #![doc = include_str!("../README.md")]
#![no_std]
#![deny(unconditional_recursion)]
pub mod marker;
pub mod portable;
pub mod types;
use core::{
cell::Cell,
sync::atomic::*,
};
use crate::marker::*;
pub use crate::types::{
Atom,
Isotope,
Radon,
};
#[doc = include_str!("../doc/radium.md")]
pub unsafe trait Radium {
/// The primitive type that this implementor makes shared-mutable.
type Item: Copy + PartialEq;
/// Creates a new value of this type.
fn new(value: Self::Item) -> Self;
/// If the implementor is atomic, this calls [`atomic::fence`] with the
/// given `Ordering`; otherwise, it does nothing.
///
/// [`atomic::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 because consuming by value ensures that no other references
/// exist.
fn into_inner(self) -> Self::Item;
/// Loads a value from this object.
///
/// Non-atomic implementors ignore the ordering value.
///
/// See also: [`AtomicUsize::load`].
///
/// [`AtomicUsize::load`]: core::sync::atomic::AtomicUsize::load
fn load(&self, order: Ordering) -> Self::Item;
/// Stores a value into this object.
///
/// Non-atomic implementors ignore the ordering value.
///
/// See also: [`AtomicUsize::store`].
///
/// [`AtomicUsize::store`]: core::sync::atomic::AtomicUsize::store
fn store(&self, value: Self::Item, order: Ordering);
/// Swaps a new value with the value stored in this object.
///
/// Non-atomic implementors ignore the ordering value.
///
/// See also: [`AtomicUsize::swap`].
///
/// [`AtomicUsize::swap`]: core::sync::atomic::AtomicUsize::swap
fn swap(&self, value: Self::Item, order: Ordering) -> Self::Item;
/// Stores a new value into this object if (and only if) the value currently
/// stored in it is the same as the `current` argument.
///
/// The return value is always what the object contained before the call
/// entered. If it is equal to the `current` argument, then the object has
/// been updated to contain `new`.
///
/// Non-atomic implementors ignore the ordering value.
///
/// 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 new value into this object if (and only if) the value currently
/// stored in it is the same as the `current` argument.
///
/// The return value is a `Result` indicating whether the new value was
/// written into this object, and containing the value this object contained
/// when the call entered. On success, this value is guaranteed to be equal
/// to `current`.
///
/// Non-atomic implementors ignore the ordering value.
///
/// 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;
/// Stores a new value into this object if (and only if) the value currently
/// stored in it is the same as the `current` argument.
///
/// 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 comparison succeeded and the new value was written, and
/// containing the value this object contained when the call entered.
///
/// Non-atomic implementors ignore the ordering value.
///
/// 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;
/// Performs a bit-wise AND on the currently-stored value and the argument.
/// The result is stored into this object, and the previous value is
/// returned.
///
/// Non-atomic implementors ignore the ordering value.
///
/// 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: BitOps;
/// Performs a bit-wise NAND on the currently-stored value and the argument.
/// The result is stored into this object, and the previous value is
/// returned.
///
/// Non-atomic implementors ignore the ordering value.
///
/// 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: BitOps;
/// Performs a bit-wise OR on the currently-stored value and the argument.
/// The result is stored into this object, and the previous value is
/// returned.
///
/// Non-atomic implementors ignore the ordering value.
///
/// 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: BitOps;
/// Performs a bit-wise XOR on the currently-stored value and the argument.
/// The result is stored into this object, and the previous value is
/// returned.
///
/// Non-atomic implementors ignore the ordering value.
///
/// 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: BitOps;
/// Adds the argument into the currently-stored value, wrapping on overflow.
/// The result is stored into this object, and the previous value is
/// returned.
///
/// Non-atomic implementors ignore the ordering value.
///
/// 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: NumericOps;
/// Subtracts the argument from the currently-stored value, wrapping on
/// overflow. The result is stored into this object, and the previous value
/// is returned.
///
/// Non-atomic implementors ignore the ordering value.
///
/// 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: NumericOps;
/// Finds the maximum of the currently-stored value and the argument. The
/// result is stored into this object, and the previous value is returned.
///
/// Non-atomic implementors ignore the ordering value.
///
/// See also: [`AtomicUsize::fetch_max`].
///
/// [`AtomicUsize::fetch_max`]: core::sync::atomic::AtomicUsize::fetch_max
fn fetch_max(&self, value: Self::Item, order: Ordering) -> Self::Item
where Self::Item: NumericOps;
/// Finds the minimum of the currently-stored value and the argument. The
/// result is stored into this object, and the previous value is returned.
///
/// Non-atomic implementors ignore the ordering value.
///
/// See also: [`AtomicUsize::fetch_min`].
///
/// [`AtomicUsize::fetch_min`]: core::sync::atomic::AtomicUsize::fetch_min
fn fetch_min(&self, value: Self::Item, order: Ordering) -> Self::Item
where Self::Item: NumericOps;
/// Fetches the value, and applies a function to it that may produce a new
/// value.
///
/// Note: this may call the generator function multiple times if the stored
/// value is updated in between the fetch and store. However, when a store
/// occurs successfully, the generator will have been applied only once to
/// the fetched value. That is, this function will never store
/// `f(f(self.load()))`.
///
/// Returns `Ok(fetched)` if the generator produces `Some` new value which
/// is successfully stored, or `Err(fetched)` if it produces `None`.
///
/// Non-atomic implementors ignore the ordering value.
///
/// See also: [`AtomicUsize::fetch_update`].
///
/// [`AtomicUsize::fetch_update`]: core::sync::atomic::AtomicUsize::fetch_update
fn fetch_update(
&self,
set_order: Ordering,
fetch_order: Ordering,
f: F,
) -> Result
where
F: FnMut(Self::Item) -> Option;
}
/// Generates `Radium` implementation bodies.
macro_rules! radium {
($($width:literal : $bit:ident $num:ident => {
$($(@<$t:ident>)? $base:ty $(=> $atom:ident)?;)+
} )+) => { $( $(
radium!(atom $width $bit $num $(@<$t>)? $base $(=> $atom)?);
radium!(cell $width $bit $num $(@<$t>)? $base);
)+ )+ };
// Trap the branch that has no named atom.
(atom $width:literal $bit:ident $num:ident $(@<$t:ident>)? $base:ty) => {};
// Generate an implementation for the named atom.
(
atom $width:literal $bit:ident $num:ident
$(@<$t:ident>)? $base:ty => $atom:ident
) => {
#[cfg(target_has_atomic = $width)]
unsafe impl$(<$t>)? Radium for $atom$(<$t>)? {
type Item = $base;
#[inline]
fn new(value: $base) -> Self {
<$atom$(<$t>)?>::new(value)
}
#[inline]
fn fence(order: Ordering) {
core::sync::atomic::fence(order);
}
#[inline]
fn get_mut(&mut self) -> &mut $base {
<$atom$(<$t>)?>::get_mut(self)
}
#[inline]
fn into_inner(self) -> $base {
<$atom$(<$t>)?>::into_inner(self)
}
#[inline]
fn load(&self, order: Ordering) -> $base {
<$atom$(<$t>)?>::load(self, order)
}
#[inline]
fn store(&self, value: $base, order: Ordering) {
<$atom$(<$t>)?>::store(self, value, order);
}
#[inline]
fn swap(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::swap(self, value, order)
}
#[inline]
#[allow(deprecated)]
fn compare_and_swap(
&self,
current: $base,
new: $base,
order: Ordering,
) -> $base {
<$atom$(<$t>)?>::compare_and_swap(self, current, new, order)
}
#[inline]
fn compare_exchange(
&self,
current: $base,
new: $base,
success: Ordering,
failure: Ordering
) -> Result<$base, $base> {
<$atom$(<$t>)?>::compare_exchange(self, current, new, success, failure)
}
#[inline]
fn compare_exchange_weak(
&self,
current: $base,
new: $base,
success: Ordering,
failure: Ordering,
) -> Result<$base, $base> {
<$atom$(<$t>)?>::compare_exchange_weak(
self,
current,
new,
success,
failure,
)
}
radium!(atom $bit $(@<$t>)? $atom => $base);
radium!(atom $num $(@<$t>)? $atom => $base);
#[inline]
fn fetch_update(
&self,
set_order: Ordering,
fetch_order: Ordering,
func: F,
) -> Result<$base, $base>
where
F: FnMut($base) -> Option<$base>,
{
<$atom$(<$t>)?>::fetch_update(self, set_order, fetch_order, func)
}
}
};
// Generate an implementation for the Cell.
(cell $width:literal $bit:ident $num:ident $(@<$t:ident>)? $base:ty) => {
unsafe impl$(<$t>)? Radium for Cell<$base> {
type Item = $base;
#[inline]
fn new(value: $base) -> Self {
Cell::new(value)
}
#[inline]
fn fence(_: Ordering) {}
#[inline]
fn get_mut(&mut self) -> &mut $base {
Cell::get_mut(self)
}
#[inline]
fn into_inner(self) -> $base {
Cell::into_inner(self)
}
#[inline]
fn load(&self, _: Ordering) -> $base {
Cell::get(self)
}
#[inline]
fn store(&self, value: $base, _: Ordering) {
Cell::set(self, value);
}
#[inline]
fn swap(&self, value: $base, _: Ordering) -> $base {
Cell::replace(self, value)
}
#[inline]
#[allow(deprecated)]
fn compare_and_swap(
&self,
current: $base,
new: $base,
_: Ordering,
) -> $base {
let old = Cell::get(self);
if old == current {
Cell::set(self, new);
}
old
}
#[inline]
fn compare_exchange(
&self,
current: $base,
new: $base,
_: Ordering,
_: Ordering
) -> Result<$base, $base> {
let old = Cell::get(self);
if old == current {
Cell::set(self, new);
Ok(old)
} else {
Err(old)
}
}
#[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)
}
radium!(cell $bit $(@<$t>)? $base);
radium!(cell $num $(@<$t>)? $base);
#[inline]
fn fetch_update(&self, _: Ordering, _: Ordering, mut func: F)
-> Result<$base, $base>
where
F: FnMut($base) -> Option<$base>,
{
let old = Cell::get(self);
match func(old) {
Some(new) => {
Cell::set(self, new);
Ok(old)
},
None => Err(old),
}
}
}
};
// Forward to the atomic RMU functions.
(atom bit $(@<$t:ident>)? $atom:ident => $base:ty) => {
#[inline]
fn fetch_and(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_and(self, value, order)
}
#[inline]
fn fetch_nand(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_nand(self, value, order)
}
#[inline]
fn fetch_or(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_or(self, value, order)
}
#[inline]
fn fetch_xor(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_xor(self, value, order)
}
};
(atom num $(@<$t:ident>)? $atom:ident => $base:ty) => {
#[inline]
fn fetch_add(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_add(self, value, order)
}
#[inline]
fn fetch_sub(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_sub(self, value, order)
}
#[inline]
fn fetch_max(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_max(self, value, order)
}
#[inline]
fn fetch_min(&self, value: $base, order: Ordering) -> $base {
<$atom$(<$t>)?>::fetch_min(self, value, order)
}
};
// Implement non-atomic RMU functions.
(cell bit $(@<$t:ident>)? $base:ty) => {
#[inline]
fn fetch_and(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, old & value);
old
}
#[inline]
fn fetch_nand(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, !(old & value));
old
}
#[inline]
fn fetch_or(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, old | value);
old
}
#[inline]
fn fetch_xor(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, old ^ value);
old
}
};
(cell num $(@<$t:ident>)? $base:ty) => {
#[inline]
fn fetch_add(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, old.wrapping_add(value));
old
}
#[inline]
fn fetch_sub(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, old.wrapping_sub(value));
old
}
#[inline]
fn fetch_max(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, core::cmp::max(old, value));
old
}
#[inline]
fn fetch_min(&self, value: $base, _: Ordering) -> $base {
let old = Cell::get(self);
Cell::set(self, core::cmp::min(old, value));
old
}
};
// Handle stubbed-out RMU functions.
(atom no_bit $(@<$t:ident>)? $atom:ident => $base:ty) => {
radium!(unreachable fetch_and, fetch_nand, fetch_or, fetch_xor);
};
(atom no_num $(@<$t:ident>)? $atom:ident => $base:ty) => {
radium!(unreachable fetch_add, fetch_sub, fetch_max, fetch_min);
};
(cell no_bit $(@<$t:ident>)? $base:ty) => {
radium!(unreachable fetch_and, fetch_nand, fetch_or, fetch_xor);
};
(cell no_num $(@<$t:ident>)? $base:ty) => {
radium!(unreachable fetch_add, fetch_sub, fetch_max, fetch_min);
};
// Generate forwarding functions for `Atom` and `Isotope`.
(wrappers) => {
#[inline]
fn new(value: T) -> Self {
Self {
inner: Radium::new(value),
}
}
#[inline]
fn get_mut(&mut self) -> &mut T {
Radium::get_mut(&mut self.inner)
}
#[inline]
fn into_inner(self) -> T {
Radium::into_inner(self.inner)
}
#[inline]
fn load(&self, order: Ordering) -> T {
Radium::load(&self.inner, order)
}
#[inline]
fn store(&self, value: T, order: Ordering) {
Radium::store(&self.inner, value, order);
}
#[inline]
fn swap(&self, value: T, order: Ordering) -> T {
Radium::swap(&self.inner, value, order)
}
#[inline]
#[allow(deprecated)]
fn compare_and_swap(
&self,
current: T,
new: T,
order: Ordering,
) -> T {
Radium::compare_and_swap(&self.inner, current, new, order)
}
#[inline]
fn compare_exchange(
&self,
current: T,
new: T,
success: Ordering,
failure: Ordering,
) -> Result {
Radium::compare_exchange(
&self.inner,
current,
new,
success,
failure,
)
}
#[inline]
fn compare_exchange_weak(
&self,
current: T,
new: T,
success: Ordering,
failure: Ordering,
) -> Result {
Radium::compare_exchange_weak(
&self.inner,
current,
new,
success,
failure,
)
}
#[inline]
fn fetch_and(&self, value: T, order: Ordering) -> T
where
T: BitOps,
{
Radium::fetch_and(&self.inner, value, order)
}
#[inline]
fn fetch_nand(&self, value: T, order: Ordering) -> T
where
T: BitOps,
{
Radium::fetch_nand(&self.inner, value, order)
}
#[inline]
fn fetch_or(&self, value: T, order: Ordering) -> T
where
T: BitOps,
{
Radium::fetch_or(&self.inner, value, order)
}
#[inline]
fn fetch_xor(&self, value: T, order: Ordering) -> T
where
T: BitOps,
{
Radium::fetch_xor(&self.inner, value, order)
}
#[inline]
fn fetch_add(&self, value: T, order: Ordering) -> T
where
T: NumericOps,
{
Radium::fetch_add(&self.inner, value, order)
}
#[inline]
fn fetch_sub(&self, value: T, order: Ordering) -> T
where
T: NumericOps,
{
Radium::fetch_sub(&self.inner, value, order)
}
#[inline]
fn fetch_max(&self, value: T, order: Ordering) -> T
where
T: NumericOps,
{
Radium::fetch_max(&self.inner, value, order)
}
#[inline]
fn fetch_min(&self, value: T, order: Ordering) -> T
where
T: NumericOps,
{
Radium::fetch_min(&self.inner, value, order)
}
#[inline]
fn fetch_update(
&self,
set_order: Ordering,
fetch_order: Ordering,
func: F,
) -> Result
where
F: FnMut(T) -> Option,
{
Radium::fetch_update(&self.inner, set_order, fetch_order, func)
}
};
// Generate stubs for the conditionally-unreachable methods.
(unreachable $($n:ident),+ $(,)?) => { $(
fn $n(&self, _: Self::Item, _: Ordering) -> Self::Item {
unreachable!(
"This function is statically guaranteed to never be callable",
);
}
)+ };
}
radium! {
"8": bit no_num => {
bool => AtomicBool;
}
"8": bit num => {
i8 => AtomicI8;
u8 => AtomicU8;
}
"16": bit num => {
i16 => AtomicI16;
u16 => AtomicU16;
}
"32": bit num => {
i32 => AtomicI32;
u32 => AtomicU32;
}
"64": bit num => {
i64 => AtomicI64;
u64 => AtomicU64;
}
"128": bit num => {
i128; // => AtomicI128; // when this stabilizes
u128; // => AtomicU128; // when this stabilizes
}
"ptr": bit num => {
isize => AtomicIsize;
usize => AtomicUsize;
}
"ptr": no_bit no_num => {
@ *mut T => AtomicPtr;
}
}
unsafe impl Radium for Atom
where
T: Atomic + PartialEq,
T::Atom: Radium- ,
{
type Item = T;
radium!(wrappers);
fn fence(order: Ordering) {
core::sync::atomic::fence(order);
}
}
unsafe impl Radium for Isotope
where
T: Nuclear + PartialEq,
T::Nucleus: Radium
- ,
{
type Item = T;
radium!(wrappers);
fn fence(order: Ordering) {
::fence(order);
}
}
unsafe impl Radium for Radon
where
T: Nuclear + PartialEq,
Cell: Radium
- ,
{
type Item = T;
radium!(wrappers);
fn fence(_: Ordering) {
}
}
#[cfg(test)]
mod tests {
#[allow(unused_imports)]
use core::sync::atomic::*;
use static_assertions::*;
use super::*;
use crate::types::*;
#[test]
fn absent_traits() {
assert_not_impl_any!(bool: NumericOps);
assert_not_impl_any!(*mut u8: BitOps, NumericOps);
}
#[test]
fn present_traits() {
assert_impl_all!(bool: BitOps);
assert_impl_all!(usize: BitOps, NumericOps);
}
#[test]
fn always_cell() {
assert_impl_all!(Cell: Radium
- );
assert_impl_all!(Cell: Radium
- );
assert_impl_all!(Cell: Radium
- );
assert_impl_all!(Cell: Radium
- );
assert_impl_all!(Cell: Radium
- );
assert_impl_all!(Cell: Radium
- );
assert_impl_all!(Cell: Radium
- );
assert_impl_all!(Cell: Radium
- );
assert_impl_all!(Cell: Radium
- );
assert_impl_all!(Cell: Radium
- );
assert_impl_all!(Cell: Radium
- );
assert_impl_all!(Cell<*mut ()>: Radium
- );
}
#[test]
fn always_alias() {
assert_impl_all!(RadiumBool: Radium
- );
assert_impl_all!(RadiumI8: Radium
- );
assert_impl_all!(RadiumU8: Radium
- );
assert_impl_all!(RadiumI16: Radium
- );
assert_impl_all!(RadiumU16: Radium
- );
assert_impl_all!(RadiumI32: Radium
- );
assert_impl_all!(RadiumU32: Radium
- );
assert_impl_all!(RadiumI64: Radium
- );
assert_impl_all!(RadiumU64: Radium
- );
assert_impl_all!(RadiumIsize: Radium
- );
assert_impl_all!(RadiumUsize: Radium
- );
assert_impl_all!(RadiumPtr<()>: Radium
- );
assert_impl_all!(Isotope: Radium
- );
assert_impl_all!(Isotope: Radium
- );
assert_impl_all!(Isotope: Radium
- );
assert_impl_all!(Isotope: Radium
- );
assert_impl_all!(Isotope: Radium
- );
assert_impl_all!(Isotope: Radium
- );
assert_impl_all!(Isotope: Radium
- );
assert_impl_all!(Isotope: Radium
- );
assert_impl_all!(Isotope: Radium
- );
assert_impl_all!(Isotope: Radium
- );
assert_impl_all!(Isotope: Radium
- );
assert_impl_all!(Isotope<*mut ()>: Radium
- );
}
#[test]
fn maybe_atom() {
#[cfg(target_has_atomic = "8")]
{
assert_impl_all!(AtomicBool: Radium
- );
assert_impl_all!(AtomicI8: Radium
- );
assert_impl_all!(AtomicU8: Radium
- );
assert_impl_all!(Atom: Radium
- );
assert_impl_all!(Atom: Radium
- );
assert_impl_all!(Atom: Radium
- );
}
#[cfg(target_has_atomic = "16")]
{
assert_impl_all!(AtomicI16: Radium
- );
assert_impl_all!(AtomicU16: Radium
- );
assert_impl_all!(Atom: Radium
- );
assert_impl_all!(Atom: Radium
- );
}
#[cfg(target_has_atomic = "32")]
{
assert_impl_all!(AtomicI32: Radium
- );
assert_impl_all!(AtomicU32: Radium
- );
assert_impl_all!(Atom: Radium
- );
assert_impl_all!(Atom: Radium
- );
}
#[cfg(target_has_atomic = "64")]
{
assert_impl_all!(AtomicI64: Radium
- );
assert_impl_all!(AtomicU64: Radium
- );
assert_impl_all!(Atom: Radium
- );
assert_impl_all!(Atom: Radium
- );
}
#[cfg(target_has_atomic = "ptr")]
{
assert_impl_all!(AtomicIsize: Radium
- );
assert_impl_all!(AtomicUsize: Radium
- );
assert_impl_all!(AtomicPtr<()>: Radium
- );
assert_impl_all!(Atom: Radium
- );
assert_impl_all!(Atom: Radium
- );
assert_impl_all!(Atom<*mut ()>: Radium
- );
}
}
}
radium-1.1.0/src/marker.rs 0000644 0000000 0000000 00000003246 00726746425 0013557 0 ustar 0000000 0000000 //! Marker traits used to gate `Radium` methods and newtype parameters.
use core::ops::{
Add,
BitAnd,
BitOr,
BitXor,
Not,
Sub,
};
use crate::Radium;
/// Indicates that the type supports bit-wise operations.
pub trait BitOps:
Sized
+ BitAnd