aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Vander Stoep <jeffv@google.com>2024-01-31 18:55:35 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2024-01-31 18:55:35 +0000
commitffc4a5b6cd3f1bb444e9dba28db7679c00aa8fc7 (patch)
tree60ab42877b507a5508e7eb0bca613d8ef46ade79
parent4eb167967de93e5ec9aeec8f0815e3daf250f992 (diff)
parent839041b30bcf84a102f662c83870a4ca6db9a6b4 (diff)
downloadatomic-master.tar.gz
Upgrade atomic to 0.6.0 am: 839041b30bHEADmastermain
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/atomic/+/2939603 Change-Id: Idf88a8335e8856f3a2933a3bfbcdf7c1e4db1af5 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.cargo_vcs_info.json6
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml18
-rw-r--r--Android.bp13
-rw-r--r--Cargo.toml18
-rw-r--r--Cargo.toml.orig11
-rw-r--r--METADATA24
-rw-r--r--README.md8
-rw-r--r--build.rs16
-rw-r--r--src/fallback.rs22
-rw-r--r--src/lib.rs128
-rw-r--r--src/ops.rs63
12 files changed, 198 insertions, 131 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..8498c3a
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+ "git": {
+ "sha1": "79ace14a69d8d4a45cc7f6cd06ff0cbb5849b2fd"
+ },
+ "path_in_vcs": ""
+} \ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a9d37c5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+target
+Cargo.lock
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..eb618e1
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,18 @@
+language: rust
+sudo: false
+
+rust:
+- nightly
+- beta
+- stable
+- 1.45.0
+
+script:
+- cargo build
+- cargo test
+- cargo doc
+- if [ $TRAVIS_RUST_VERSION = nightly ]; then rustup target add aarch64-unknown-none; fi
+- if [ $TRAVIS_RUST_VERSION = nightly ]; then RUSTFLAGS="-Zcrate-attr=feature(integer_atomics)" cargo check --target=aarch64-unknown-none; fi
+
+notifications:
+ email: false
diff --git a/Android.bp b/Android.bp
index 6809e2e..9165de8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -42,23 +42,14 @@ rust_library {
host_supported: true,
crate_name: "atomic",
cargo_env_compat: true,
- cargo_pkg_version: "0.5.1",
+ cargo_pkg_version: "0.6.0",
srcs: ["src/lib.rs"],
edition: "2018",
features: [
"fallback",
"std",
],
- cfgs: [
- "has_atomic_i16",
- "has_atomic_i32",
- "has_atomic_i64",
- "has_atomic_i8",
- "has_atomic_u16",
- "has_atomic_u32",
- "has_atomic_u64",
- "has_atomic_u8",
- ],
+ rustlibs: ["libbytemuck"],
apex_available: [
"//apex_available:platform",
"//apex_available:anyapex",
diff --git a/Cargo.toml b/Cargo.toml
index fedd21b..88db472 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,18 +12,26 @@
[package]
edition = "2018"
name = "atomic"
-version = "0.5.1"
+version = "0.6.0"
authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
description = "Generic Atomic<T> wrapper type"
-documentation = "https://amanieu.github.io/atomic-rs/atomic/index.html"
readme = "README.md"
-keywords = ["atomic", "no_std"]
+keywords = [
+ "atomic",
+ "no_std",
+]
license = "Apache-2.0/MIT"
repository = "https://github.com/Amanieu/atomic-rs"
-[build-dependencies.autocfg]
-version = "1"
+
+[dependencies.bytemuck]
+version = "1.13.1"
+
+[dev-dependencies.bytemuck]
+version = "1.13.1"
+features = ["derive"]
[features]
default = ["fallback"]
fallback = []
+nightly = []
std = []
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 80b613b..60faf7c 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,10 +1,9 @@
[package]
name = "atomic"
-version = "0.5.1"
+version = "0.6.0"
edition = "2018"
authors = ["Amanieu d'Antras <amanieu@gmail.com>"]
description = "Generic Atomic<T> wrapper type"
-documentation = "https://amanieu.github.io/atomic-rs/atomic/index.html"
license = "Apache-2.0/MIT"
repository = "https://github.com/Amanieu/atomic-rs"
readme = "README.md"
@@ -14,6 +13,10 @@ keywords = ["atomic", "no_std"]
default = ["fallback"]
std = []
fallback = []
+nightly = []
-[build-dependencies]
-autocfg = "1"
+[dependencies]
+bytemuck = "1.13.1"
+
+[dev-dependencies]
+bytemuck = { version = "1.13.1", features = ["derive"] }
diff --git a/METADATA b/METADATA
index ada5837..917773f 100644
--- a/METADATA
+++ b/METADATA
@@ -1,20 +1,20 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update external/rust/crates/atomic
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+
name: "atomic"
description: "Generic Atomic<T> wrapper type"
third_party {
- url {
- type: HOMEPAGE
- value: "https://crates.io/crates/atomic"
- }
- url {
- type: ARCHIVE
- value: "https://static.crates.io/crates/atomic/atomic-0.5.1.crate"
- }
- version: "0.5.1"
- # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
license_type: NOTICE
last_upgrade_date {
- year: 2023
+ year: 2024
month: 1
- day: 17
+ day: 31
+ }
+ homepage: "https://crates.io/crates/atomic"
+ identifier {
+ type: "Archive"
+ value: "https://static.crates.io/crates/atomic/atomic-0.6.0.crate"
+ version: "0.6.0"
}
}
diff --git a/README.md b/README.md
index ea2c0cb..3dedec7 100644
--- a/README.md
+++ b/README.md
@@ -3,13 +3,15 @@ Generic `Atomic<T>` for Rust
[![Build Status](https://travis-ci.org/Amanieu/atomic-rs.svg?branch=master)](https://travis-ci.org/Amanieu/atomic-rs) [![Crates.io](https://img.shields.io/crates/v/atomic.svg)](https://crates.io/crates/atomic)
-A Rust library which provides a generic `Atomic<T>` type for all `T: Copy` types, unlike the standard library which only provides a few fixed atomic types (`AtomicBool`, `AtomicIsize`, `AtomicUsize`, `AtomicPtr`).
+A Rust library which provides a generic `Atomic<T>` type for all `T: NoUninit` types, unlike the standard library which only provides a few fixed atomic types (`AtomicBool`, `AtomicIsize`, `AtomicUsize`, `AtomicPtr`). The `NoUninit` bound is from the [bytemuck] crate, and indicates that a type has no internal padding bytes. You will need to derive or implement this trait for all types used with `Atomic<T>`.
This library will use native atomic instructions if possible, and will otherwise fall back to a lock-based mechanism. You can use the `Atomic::<T>::is_lock_free()` function to check whether native atomic operations are supported for a given type. Note that a type must have a power-of-2 size and alignment in order to be used by native atomic instructions.
This crate uses `#![no_std]` and only depends on libcore.
-[Documentation](https://amanieu.github.io/atomic-rs/atomic/index.html)
+[bytemuck]: https://docs.rs/bytemuck
+
+[Documentation](https://docs.rs/atomic)
## Usage
@@ -17,7 +19,7 @@ Add this to your `Cargo.toml`:
```toml
[dependencies]
-atomic = "0.5"
+atomic = "0.6"
```
and this to your crate root:
diff --git a/build.rs b/build.rs
deleted file mode 100644
index 4cf4274..0000000
--- a/build.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-fn main() {
- let ac = autocfg::new();
-
- for root in &["core", "std"] {
- for size in &[8, 16, 32, 64, 128] {
- ac.emit_expression_cfg(
- &format!("{}::sync::atomic::AtomicU{}::compare_exchange", root, size),
- &format!("has_atomic_u{}", size),
- );
- ac.emit_expression_cfg(
- &format!("{}::sync::atomic::AtomicI{}::compare_exchange", root, size),
- &format!("has_atomic_i{}", size),
- );
- }
- }
-}
diff --git a/src/fallback.rs b/src/fallback.rs
index 8b7e861..949bbf3 100644
--- a/src/fallback.rs
+++ b/src/fallback.rs
@@ -6,12 +6,13 @@
// copied, modified, or distributed except according to those terms.
use core::cmp;
-use core::mem;
+use core::hint;
use core::num::Wrapping;
use core::ops;
use core::ptr;
-use core::slice;
-use core::sync::atomic::{self, AtomicUsize, Ordering};
+use core::sync::atomic::{AtomicUsize, Ordering};
+
+use bytemuck::NoUninit;
// We use an AtomicUsize instead of an AtomicBool because it performs better
// on architectures that don't have byte-sized atomics.
@@ -28,7 +29,7 @@ impl SpinLock {
.is_err()
{
while self.0.load(Ordering::Relaxed) != 0 {
- atomic::spin_loop_hint();
+ hint::spin_loop();
}
}
}
@@ -116,15 +117,16 @@ pub unsafe fn atomic_swap<T>(dst: *mut T, val: T) -> T {
}
#[inline]
-pub unsafe fn atomic_compare_exchange<T>(dst: *mut T, current: T, new: T) -> Result<T, T> {
+pub unsafe fn atomic_compare_exchange<T: NoUninit>(
+ dst: *mut T,
+ current: T,
+ new: T,
+) -> Result<T, T> {
let _l = lock(dst as usize);
let result = ptr::read(dst);
// compare_exchange compares with memcmp instead of Eq
- let a = slice::from_raw_parts(&result as *const _ as *const u8, mem::size_of_val(&result));
- let b = slice::from_raw_parts(
- &current as *const _ as *const u8,
- mem::size_of_val(&current),
- );
+ let a = bytemuck::bytes_of(&result);
+ let b = bytemuck::bytes_of(&current);
if a == b {
ptr::write(dst, new);
Ok(result)
diff --git a/src/lib.rs b/src/lib.rs
index 09ad879..c4ff297 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,10 +11,14 @@
//! threads, and are the building blocks of other concurrent types.
//!
//! This library defines a generic atomic wrapper type `Atomic<T>` for all
-//! `T: Copy` types.
+//! `T: NoUninit` types.
//! Atomic types present operations that, when used correctly, synchronize
//! updates between threads.
//!
+//! The `NoUninit` bound is from the [bytemuck] crate, and indicates that a
+//! type has no internal padding bytes. You will need to derive or implement
+//! this trait for all types used with `Atomic<T>`.
+//!
//! Each method takes an `Ordering` which represents the strength of
//! the memory barrier for that operation. These orderings are the
//! same as [LLVM atomic orderings][1].
@@ -29,15 +33,19 @@
//! Most atomic types may be stored in static variables, initialized using
//! the `const fn` constructors. Atomic statics are often used for lazy global
//! initialization.
+//!
+//! [bytemuck]: https://docs.rs/bytemuck
#![warn(missing_docs)]
#![warn(rust_2018_idioms)]
#![no_std]
+#![cfg_attr(feature = "nightly", feature(integer_atomics))]
#[cfg(any(test, feature = "std"))]
#[macro_use]
extern crate std;
+use core::mem::MaybeUninit;
// Re-export some useful definitions from libcore
pub use core::sync::atomic::{fence, Ordering};
@@ -47,6 +55,8 @@ use core::fmt;
#[cfg(feature = "std")]
use std::panic::RefUnwindSafe;
+use bytemuck::NoUninit;
+
#[cfg(feature = "fallback")]
mod fallback;
mod ops;
@@ -55,7 +65,8 @@ mod ops;
/// between threads.
#[repr(transparent)]
pub struct Atomic<T> {
- v: UnsafeCell<T>,
+ // The MaybeUninit is here to work around rust-lang/rust#87341.
+ v: UnsafeCell<MaybeUninit<T>>,
}
// Atomic<T> is only Sync if T is Send
@@ -68,16 +79,16 @@ unsafe impl<T: Copy + Send> Sync for Atomic<T> {}
// `Atomic` API does not allow doing any panic-inducing operation after writing
// to the target object.
#[cfg(feature = "std")]
-impl<T: Copy + RefUnwindSafe> RefUnwindSafe for Atomic<T> {}
+impl<T: RefUnwindSafe> RefUnwindSafe for Atomic<T> {}
-impl<T: Copy + Default> Default for Atomic<T> {
+impl<T: Default> Default for Atomic<T> {
#[inline]
fn default() -> Self {
Self::new(Default::default())
}
}
-impl<T: Copy + fmt::Debug> fmt::Debug for Atomic<T> {
+impl<T: NoUninit + fmt::Debug> fmt::Debug for Atomic<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Atomic")
.field(&self.load(Ordering::SeqCst))
@@ -90,7 +101,7 @@ impl<T> Atomic<T> {
#[inline]
pub const fn new(v: T) -> Atomic<T> {
Atomic {
- v: UnsafeCell::new(v),
+ v: UnsafeCell::new(MaybeUninit::new(v)),
}
}
@@ -105,14 +116,19 @@ impl<T> Atomic<T> {
}
}
-impl<T: Copy> Atomic<T> {
+impl<T: NoUninit> Atomic<T> {
+ #[inline]
+ fn inner_ptr(&self) -> *mut T {
+ self.v.get() as *mut T
+ }
+
/// Returns a mutable reference to the underlying type.
///
/// This is safe because the mutable reference guarantees that no other threads are
/// concurrently accessing the atomic data.
#[inline]
pub fn get_mut(&mut self) -> &mut T {
- unsafe { &mut *self.v.get() }
+ unsafe { &mut *self.inner_ptr() }
}
/// Consumes the atomic and returns the contained value.
@@ -121,7 +137,7 @@ impl<T: Copy> Atomic<T> {
/// concurrently accessing the atomic data.
#[inline]
pub fn into_inner(self) -> T {
- self.v.into_inner()
+ unsafe { self.v.into_inner().assume_init() }
}
/// Loads a value from the `Atomic`.
@@ -134,7 +150,7 @@ impl<T: Copy> Atomic<T> {
/// Panics if `order` is `Release` or `AcqRel`.
#[inline]
pub fn load(&self, order: Ordering) -> T {
- unsafe { ops::atomic_load(self.v.get(), order) }
+ unsafe { ops::atomic_load(self.inner_ptr(), order) }
}
/// Stores a value into the `Atomic`.
@@ -148,7 +164,7 @@ impl<T: Copy> Atomic<T> {
#[inline]
pub fn store(&self, val: T, order: Ordering) {
unsafe {
- ops::atomic_store(self.v.get(), val, order);
+ ops::atomic_store(self.inner_ptr(), val, order);
}
}
@@ -158,7 +174,7 @@ impl<T: Copy> Atomic<T> {
/// of this operation.
#[inline]
pub fn swap(&self, val: T, order: Ordering) -> T {
- unsafe { ops::atomic_swap(self.v.get(), val, order) }
+ unsafe { ops::atomic_swap(self.inner_ptr(), val, order) }
}
/// Stores a value into the `Atomic` if the current value is the same as the
@@ -181,7 +197,7 @@ impl<T: Copy> Atomic<T> {
success: Ordering,
failure: Ordering,
) -> Result<T, T> {
- unsafe { ops::atomic_compare_exchange(self.v.get(), current, new, success, failure) }
+ unsafe { ops::atomic_compare_exchange(self.inner_ptr(), current, new, success, failure) }
}
/// Stores a value into the `Atomic` if the current value is the same as the
@@ -206,7 +222,9 @@ impl<T: Copy> Atomic<T> {
success: Ordering,
failure: Ordering,
) -> Result<T, T> {
- unsafe { ops::atomic_compare_exchange_weak(self.v.get(), current, new, success, failure) }
+ unsafe {
+ ops::atomic_compare_exchange_weak(self.inner_ptr(), current, new, success, failure)
+ }
}
/// Fetches the value, and applies a function to it that returns an optional
@@ -275,7 +293,7 @@ impl Atomic<bool> {
/// Returns the previous value.
#[inline]
pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
- unsafe { ops::atomic_and(self.v.get(), val, order) }
+ unsafe { ops::atomic_and(self.inner_ptr(), val, order) }
}
/// Logical "or" with a boolean value.
@@ -286,7 +304,7 @@ impl Atomic<bool> {
/// Returns the previous value.
#[inline]
pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
- unsafe { ops::atomic_or(self.v.get(), val, order) }
+ unsafe { ops::atomic_or(self.inner_ptr(), val, order) }
}
/// Logical "xor" with a boolean value.
@@ -297,7 +315,7 @@ impl Atomic<bool> {
/// Returns the previous value.
#[inline]
pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
- unsafe { ops::atomic_xor(self.v.get(), val, order) }
+ unsafe { ops::atomic_xor(self.inner_ptr(), val, order) }
}
}
@@ -307,31 +325,31 @@ macro_rules! atomic_ops_common {
/// Add to the current value, returning the previous value.
#[inline]
pub fn fetch_add(&self, val: $t, order: Ordering) -> $t {
- unsafe { ops::atomic_add(self.v.get(), val, order) }
+ unsafe { ops::atomic_add(self.inner_ptr(), val, order) }
}
/// Subtract from the current value, returning the previous value.
#[inline]
pub fn fetch_sub(&self, val: $t, order: Ordering) -> $t {
- unsafe { ops::atomic_sub(self.v.get(), val, order) }
+ unsafe { ops::atomic_sub(self.inner_ptr(), val, order) }
}
/// Bitwise and with the current value, returning the previous value.
#[inline]
pub fn fetch_and(&self, val: $t, order: Ordering) -> $t {
- unsafe { ops::atomic_and(self.v.get(), val, order) }
+ unsafe { ops::atomic_and(self.inner_ptr(), val, order) }
}
/// Bitwise or with the current value, returning the previous value.
#[inline]
pub fn fetch_or(&self, val: $t, order: Ordering) -> $t {
- unsafe { ops::atomic_or(self.v.get(), val, order) }
+ unsafe { ops::atomic_or(self.inner_ptr(), val, order) }
}
/// Bitwise xor with the current value, returning the previous value.
#[inline]
pub fn fetch_xor(&self, val: $t, order: Ordering) -> $t {
- unsafe { ops::atomic_xor(self.v.get(), val, order) }
+ unsafe { ops::atomic_xor(self.inner_ptr(), val, order) }
}
}
)*);
@@ -344,13 +362,13 @@ macro_rules! atomic_ops_signed {
/// Minimum with the current value.
#[inline]
pub fn fetch_min(&self, val: $t, order: Ordering) -> $t {
- unsafe { ops::atomic_min(self.v.get(), val, order) }
+ unsafe { ops::atomic_min(self.inner_ptr(), val, order) }
}
/// Maximum with the current value.
#[inline]
pub fn fetch_max(&self, val: $t, order: Ordering) -> $t {
- unsafe { ops::atomic_max(self.v.get(), val, order) }
+ unsafe { ops::atomic_max(self.inner_ptr(), val, order) }
}
}
)*
@@ -364,13 +382,13 @@ macro_rules! atomic_ops_unsigned {
/// Minimum with the current value.
#[inline]
pub fn fetch_min(&self, val: $t, order: Ordering) -> $t {
- unsafe { ops::atomic_umin(self.v.get(), val, order) }
+ unsafe { ops::atomic_umin(self.inner_ptr(), val, order) }
}
/// Maximum with the current value.
#[inline]
pub fn fetch_max(&self, val: $t, order: Ordering) -> $t {
- unsafe { ops::atomic_umax(self.v.get(), val, order) }
+ unsafe { ops::atomic_umax(self.inner_ptr(), val, order) }
}
}
)*
@@ -382,19 +400,26 @@ atomic_ops_unsigned! { u8 u16 u32 u64 usize u128 }
#[cfg(test)]
mod tests {
use super::{Atomic, Ordering::*};
+ use bytemuck::NoUninit;
use core::mem;
- #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
+ #[derive(Copy, Clone, Eq, PartialEq, Debug, Default, NoUninit)]
+ #[repr(C)]
struct Foo(u8, u8);
- #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
+ #[derive(Copy, Clone, Eq, PartialEq, Debug, Default, NoUninit)]
+ #[repr(C)]
struct Bar(u64, u64);
- #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
+ #[derive(Copy, Clone, Eq, PartialEq, Debug, Default, NoUninit)]
+ #[repr(C)]
struct Quux(u32);
#[test]
fn atomic_bool() {
let a = Atomic::new(false);
- assert_eq!(Atomic::<bool>::is_lock_free(), cfg!(has_atomic_u8),);
+ assert_eq!(
+ Atomic::<bool>::is_lock_free(),
+ cfg!(target_has_atomic = "8"),
+ );
assert_eq!(format!("{:?}", a), "Atomic(false)");
assert_eq!(a.load(SeqCst), false);
a.store(true, SeqCst);
@@ -410,7 +435,7 @@ mod tests {
#[test]
fn atomic_i8() {
let a = Atomic::new(0i8);
- assert_eq!(Atomic::<i8>::is_lock_free(), cfg!(has_atomic_u8));
+ assert_eq!(Atomic::<i8>::is_lock_free(), cfg!(target_has_atomic = "8"));
assert_eq!(format!("{:?}", a), "Atomic(0)");
assert_eq!(a.load(SeqCst), 0);
a.store(1, SeqCst);
@@ -431,7 +456,10 @@ mod tests {
#[test]
fn atomic_i16() {
let a = Atomic::new(0i16);
- assert_eq!(Atomic::<i16>::is_lock_free(), cfg!(has_atomic_u16));
+ assert_eq!(
+ Atomic::<i16>::is_lock_free(),
+ cfg!(target_has_atomic = "16")
+ );
assert_eq!(format!("{:?}", a), "Atomic(0)");
assert_eq!(a.load(SeqCst), 0);
a.store(1, SeqCst);
@@ -451,7 +479,10 @@ mod tests {
#[test]
fn atomic_i32() {
let a = Atomic::new(0i32);
- assert_eq!(Atomic::<i32>::is_lock_free(), cfg!(has_atomic_u32));
+ assert_eq!(
+ Atomic::<i32>::is_lock_free(),
+ cfg!(target_has_atomic = "32")
+ );
assert_eq!(format!("{:?}", a), "Atomic(0)");
assert_eq!(a.load(SeqCst), 0);
a.store(1, SeqCst);
@@ -473,7 +504,7 @@ mod tests {
let a = Atomic::new(0i64);
assert_eq!(
Atomic::<i64>::is_lock_free(),
- cfg!(has_atomic_u64) && mem::align_of::<i64>() == 8
+ cfg!(target_has_atomic = "64") && mem::align_of::<i64>() == 8
);
assert_eq!(format!("{:?}", a), "Atomic(0)");
assert_eq!(a.load(SeqCst), 0);
@@ -494,7 +525,10 @@ mod tests {
#[test]
fn atomic_i128() {
let a = Atomic::new(0i128);
- assert_eq!(Atomic::<i128>::is_lock_free(), cfg!(has_atomic_u128));
+ assert_eq!(
+ Atomic::<i128>::is_lock_free(),
+ cfg!(feature = "nightly") & cfg!(target_has_atomic = "128")
+ );
assert_eq!(format!("{:?}", a), "Atomic(0)");
assert_eq!(a.load(SeqCst), 0);
a.store(1, SeqCst);
@@ -533,7 +567,7 @@ mod tests {
#[test]
fn atomic_u8() {
let a = Atomic::new(0u8);
- assert_eq!(Atomic::<u8>::is_lock_free(), cfg!(has_atomic_u8));
+ assert_eq!(Atomic::<u8>::is_lock_free(), cfg!(target_has_atomic = "8"));
assert_eq!(format!("{:?}", a), "Atomic(0)");
assert_eq!(a.load(SeqCst), 0);
a.store(1, SeqCst);
@@ -553,7 +587,10 @@ mod tests {
#[test]
fn atomic_u16() {
let a = Atomic::new(0u16);
- assert_eq!(Atomic::<u16>::is_lock_free(), cfg!(has_atomic_u16));
+ assert_eq!(
+ Atomic::<u16>::is_lock_free(),
+ cfg!(target_has_atomic = "16")
+ );
assert_eq!(format!("{:?}", a), "Atomic(0)");
assert_eq!(a.load(SeqCst), 0);
a.store(1, SeqCst);
@@ -573,7 +610,10 @@ mod tests {
#[test]
fn atomic_u32() {
let a = Atomic::new(0u32);
- assert_eq!(Atomic::<u32>::is_lock_free(), cfg!(has_atomic_u32));
+ assert_eq!(
+ Atomic::<u32>::is_lock_free(),
+ cfg!(target_has_atomic = "32")
+ );
assert_eq!(format!("{:?}", a), "Atomic(0)");
assert_eq!(a.load(SeqCst), 0);
a.store(1, SeqCst);
@@ -595,7 +635,7 @@ mod tests {
let a = Atomic::new(0u64);
assert_eq!(
Atomic::<u64>::is_lock_free(),
- cfg!(has_atomic_u64) && mem::align_of::<u64>() == 8
+ cfg!(target_has_atomic = "64") && mem::align_of::<u64>() == 8
);
assert_eq!(format!("{:?}", a), "Atomic(0)");
assert_eq!(a.load(SeqCst), 0);
@@ -616,7 +656,10 @@ mod tests {
#[test]
fn atomic_u128() {
let a = Atomic::new(0u128);
- assert_eq!(Atomic::<u128>::is_lock_free(), cfg!(has_atomic_u128));
+ assert_eq!(
+ Atomic::<u128>::is_lock_free(),
+ cfg!(feature = "nightly") & cfg!(target_has_atomic = "128")
+ );
assert_eq!(format!("{:?}", a), "Atomic(0)");
assert_eq!(a.load(SeqCst), 0);
a.store(1, SeqCst);
@@ -693,7 +736,10 @@ mod tests {
#[test]
fn atomic_quxx() {
let a = Atomic::default();
- assert_eq!(Atomic::<Quux>::is_lock_free(), cfg!(has_atomic_u32));
+ assert_eq!(
+ Atomic::<Quux>::is_lock_free(),
+ cfg!(target_has_atomic = "32")
+ );
assert_eq!(format!("{:?}", a), "Atomic(Quux(0))");
assert_eq!(a.load(SeqCst), Quux(0));
a.store(Quux(1), SeqCst);
diff --git a/src/ops.rs b/src/ops.rs
index 808335c..1f54fa5 100644
--- a/src/ops.rs
+++ b/src/ops.rs
@@ -5,6 +5,8 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
+use bytemuck::NoUninit;
+
#[cfg(feature = "fallback")]
use crate::fallback;
use core::cmp;
@@ -16,31 +18,31 @@ use core::sync::atomic::Ordering;
macro_rules! match_atomic {
($type:ident, $atomic:ident, $impl:expr, $fallback_impl:expr) => {
match mem::size_of::<$type>() {
- #[cfg(has_atomic_u8)]
+ #[cfg(target_has_atomic = "8")]
1 if mem::align_of::<$type>() >= 1 => {
type $atomic = core::sync::atomic::AtomicU8;
$impl
}
- #[cfg(has_atomic_u16)]
+ #[cfg(target_has_atomic = "16")]
2 if mem::align_of::<$type>() >= 2 => {
type $atomic = core::sync::atomic::AtomicU16;
$impl
}
- #[cfg(has_atomic_u32)]
+ #[cfg(target_has_atomic = "32")]
4 if mem::align_of::<$type>() >= 4 => {
type $atomic = core::sync::atomic::AtomicU32;
$impl
}
- #[cfg(has_atomic_u64)]
+ #[cfg(target_has_atomic = "64")]
8 if mem::align_of::<$type>() >= 8 => {
type $atomic = core::sync::atomic::AtomicU64;
$impl
}
- #[cfg(has_atomic_u128)]
+ #[cfg(all(feature = "nightly", target_has_atomic = "128"))]
16 if mem::align_of::<$type>() >= 16 => {
type $atomic = core::sync::atomic::AtomicU128;
@@ -57,31 +59,31 @@ macro_rules! match_atomic {
macro_rules! match_signed_atomic {
($type:ident, $atomic:ident, $impl:expr, $fallback_impl:expr) => {
match mem::size_of::<$type>() {
- #[cfg(has_atomic_i8)]
+ #[cfg(target_has_atomic = "8")]
1 if mem::align_of::<$type>() >= 1 => {
type $atomic = core::sync::atomic::AtomicI8;
$impl
}
- #[cfg(has_atomic_i16)]
+ #[cfg(target_has_atomic = "16")]
2 if mem::align_of::<$type>() >= 2 => {
type $atomic = core::sync::atomic::AtomicI16;
$impl
}
- #[cfg(has_atomic_i32)]
+ #[cfg(target_has_atomic = "32")]
4 if mem::align_of::<$type>() >= 4 => {
type $atomic = core::sync::atomic::AtomicI32;
$impl
}
- #[cfg(has_atomic_i64)]
+ #[cfg(target_has_atomic = "64")]
8 if mem::align_of::<$type>() >= 8 => {
type $atomic = core::sync::atomic::AtomicI64;
$impl
}
- #[cfg(has_atomic_u128)]
+ #[cfg(all(feature = "nightly", target_has_atomic = "128"))]
16 if mem::align_of::<$type>() >= 16 => {
type $atomic = core::sync::atomic::AtomicI128;
@@ -100,15 +102,18 @@ pub const fn atomic_is_lock_free<T>() -> bool {
let size = mem::size_of::<T>();
let align = mem::align_of::<T>();
- (cfg!(has_atomic_u8) & (size == 1) & (align >= 1))
- | (cfg!(has_atomic_u16) & (size == 2) & (align >= 2))
- | (cfg!(has_atomic_u32) & (size == 4) & (align >= 4))
- | (cfg!(has_atomic_u64) & (size == 8) & (align >= 8))
- | (cfg!(has_atomic_u128) & (size == 16) & (align >= 16))
+ (cfg!(target_has_atomic = "8") & (size == 1) & (align >= 1))
+ | (cfg!(target_has_atomic = "16") & (size == 2) & (align >= 2))
+ | (cfg!(target_has_atomic = "32") & (size == 4) & (align >= 4))
+ | (cfg!(target_has_atomic = "64") & (size == 8) & (align >= 8))
+ | (cfg!(feature = "nightly")
+ & cfg!(target_has_atomic = "128")
+ & (size == 16)
+ & (align >= 16))
}
#[inline]
-pub unsafe fn atomic_load<T>(dst: *mut T, order: Ordering) -> T {
+pub unsafe fn atomic_load<T: NoUninit>(dst: *mut T, order: Ordering) -> T {
match_atomic!(
T,
A,
@@ -118,7 +123,7 @@ pub unsafe fn atomic_load<T>(dst: *mut T, order: Ordering) -> T {
}
#[inline]
-pub unsafe fn atomic_store<T>(dst: *mut T, val: T, order: Ordering) {
+pub unsafe fn atomic_store<T: NoUninit>(dst: *mut T, val: T, order: Ordering) {
match_atomic!(
T,
A,
@@ -128,7 +133,7 @@ pub unsafe fn atomic_store<T>(dst: *mut T, val: T, order: Ordering) {
}
#[inline]
-pub unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
+pub unsafe fn atomic_swap<T: NoUninit>(dst: *mut T, val: T, order: Ordering) -> T {
match_atomic!(
T,
A,
@@ -146,7 +151,7 @@ unsafe fn map_result<T, U>(r: Result<T, T>) -> Result<U, U> {
}
#[inline]
-pub unsafe fn atomic_compare_exchange<T>(
+pub unsafe fn atomic_compare_exchange<T: NoUninit>(
dst: *mut T,
current: T,
new: T,
@@ -167,7 +172,7 @@ pub unsafe fn atomic_compare_exchange<T>(
}
#[inline]
-pub unsafe fn atomic_compare_exchange_weak<T>(
+pub unsafe fn atomic_compare_exchange_weak<T: NoUninit>(
dst: *mut T,
current: T,
new: T,
@@ -188,7 +193,7 @@ pub unsafe fn atomic_compare_exchange_weak<T>(
}
#[inline]
-pub unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T
+pub unsafe fn atomic_add<T: NoUninit>(dst: *mut T, val: T, order: Ordering) -> T
where
Wrapping<T>: ops::Add<Output = Wrapping<T>>,
{
@@ -201,7 +206,7 @@ where
}
#[inline]
-pub unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T
+pub unsafe fn atomic_sub<T: NoUninit>(dst: *mut T, val: T, order: Ordering) -> T
where
Wrapping<T>: ops::Sub<Output = Wrapping<T>>,
{
@@ -214,7 +219,7 @@ where
}
#[inline]
-pub unsafe fn atomic_and<T: Copy + ops::BitAnd<Output = T>>(
+pub unsafe fn atomic_and<T: NoUninit + ops::BitAnd<Output = T>>(
dst: *mut T,
val: T,
order: Ordering,
@@ -228,7 +233,7 @@ pub unsafe fn atomic_and<T: Copy + ops::BitAnd<Output = T>>(
}
#[inline]
-pub unsafe fn atomic_or<T: Copy + ops::BitOr<Output = T>>(
+pub unsafe fn atomic_or<T: NoUninit + ops::BitOr<Output = T>>(
dst: *mut T,
val: T,
order: Ordering,
@@ -242,7 +247,7 @@ pub unsafe fn atomic_or<T: Copy + ops::BitOr<Output = T>>(
}
#[inline]
-pub unsafe fn atomic_xor<T: Copy + ops::BitXor<Output = T>>(
+pub unsafe fn atomic_xor<T: NoUninit + ops::BitXor<Output = T>>(
dst: *mut T,
val: T,
order: Ordering,
@@ -256,7 +261,7 @@ pub unsafe fn atomic_xor<T: Copy + ops::BitXor<Output = T>>(
}
#[inline]
-pub unsafe fn atomic_min<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
+pub unsafe fn atomic_min<T: NoUninit + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
match_signed_atomic!(
T,
A,
@@ -266,7 +271,7 @@ pub unsafe fn atomic_min<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Orderin
}
#[inline]
-pub unsafe fn atomic_max<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
+pub unsafe fn atomic_max<T: NoUninit + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
match_signed_atomic!(
T,
A,
@@ -276,7 +281,7 @@ pub unsafe fn atomic_max<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Orderin
}
#[inline]
-pub unsafe fn atomic_umin<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
+pub unsafe fn atomic_umin<T: NoUninit + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
match_atomic!(
T,
A,
@@ -286,7 +291,7 @@ pub unsafe fn atomic_umin<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Orderi
}
#[inline]
-pub unsafe fn atomic_umax<T: Copy + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
+pub unsafe fn atomic_umax<T: NoUninit + cmp::Ord>(dst: *mut T, val: T, order: Ordering) -> T {
match_atomic!(
T,
A,