portable-atomic 1.0.1

Portable atomic types including support for 128-bit atomics, atomic float, etc.
Documentation
#![allow(
    clippy::alloc_instead_of_core,
    clippy::std_instead_of_alloc,
    clippy::std_instead_of_core,
    clippy::undocumented_unsafe_blocks,
    clippy::wildcard_imports
)]

#[macro_use]
pub(crate) mod helper;

#[cfg(feature = "critical-section")]
mod critical_section_std;
#[cfg(feature = "serde")]
mod serde;

use super::*;

test_atomic_bool_pub!();
test_atomic_ptr_pub!();

test_atomic_int_pub!(isize);
test_atomic_int_pub!(usize);
test_atomic_int_pub!(i8);
test_atomic_int_pub!(u8);
test_atomic_int_pub!(i16);
test_atomic_int_pub!(u16);
test_atomic_int_pub!(i32);
test_atomic_int_pub!(u32);
test_atomic_int_pub!(i64);
test_atomic_int_pub!(u64);

// As of qemu 7.0.0 , using lqarx/stqcx. with qemu-user hangs.
// To test this, use real powerpc64le hardware or use POWER Functional
// Simulator. See DEVELOPMENT.md for more.
#[cfg_attr(
    all(
        target_arch = "powerpc64",
        portable_atomic_asm_experimental_arch,
        any(
            target_feature = "quadword-atomics",
            portable_atomic_target_feature = "quadword-atomics"
        )
    ),
    cfg(not(qemu))
)]
test_atomic_int_pub!(i128);
#[cfg_attr(
    all(
        target_arch = "powerpc64",
        portable_atomic_asm_experimental_arch,
        any(
            target_feature = "quadword-atomics",
            portable_atomic_target_feature = "quadword-atomics"
        )
    ),
    cfg(not(qemu))
)]
test_atomic_int_pub!(u128);
#[cfg(qemu)]
#[cfg(all(
    target_arch = "powerpc64",
    portable_atomic_asm_experimental_arch,
    any(target_feature = "quadword-atomics", portable_atomic_target_feature = "quadword-atomics")
))]
test_atomic_int_load_store_pub!(i128);
#[cfg(qemu)]
#[cfg(all(
    target_arch = "powerpc64",
    portable_atomic_asm_experimental_arch,
    any(target_feature = "quadword-atomics", portable_atomic_target_feature = "quadword-atomics")
))]
test_atomic_int_load_store_pub!(u128);

#[cfg(feature = "float")]
test_atomic_float_pub!(f32);
#[cfg(feature = "float")]
test_atomic_float_pub!(f64);

#[deny(improper_ctypes)]
extern "C" {
    fn _atomic_bool_ffi_safety(_: AtomicBool);
    fn _atomic_ptr_ffi_safety(_: AtomicPtr<u8>);
    fn _atomic_isize_ffi_safety(_: AtomicIsize);
    fn _atomic_usize_ffi_safety(_: AtomicUsize);
    fn _atomic_i8_ffi_safety(_: AtomicI8);
    fn _atomic_u8_ffi_safety(_: AtomicU8);
    fn _atomic_i16_ffi_safety(_: AtomicI16);
    fn _atomic_u16_ffi_safety(_: AtomicU16);
    fn _atomic_i32_ffi_safety(_: AtomicI32);
    fn _atomic_u32_ffi_safety(_: AtomicU32);
    fn _atomic_i64_ffi_safety(_: AtomicI64);
    fn _atomic_u64_ffi_safety(_: AtomicU64);
    // TODO: 128-bit integers are not FFI safe
    // https://github.com/rust-lang/unsafe-code-guidelines/issues/119
    // https://github.com/rust-lang/rust/issues/54341
    // fn _atomic_i128_ffi_safety(_: AtomicI128);
    // fn _atomic_u128_ffi_safety(_: AtomicU128);
    #[cfg(feature = "float")]
    fn _atomic_f32_ffi_safety(_: AtomicF32);
    #[cfg(feature = "float")]
    fn _atomic_f64_ffi_safety(_: AtomicF64);
}

#[rustversion::since(1.60)]
#[test]
fn test_is_lock_free() {
    assert!(AtomicI8::is_always_lock_free());
    assert!(AtomicI8::is_lock_free());
    assert!(AtomicU8::is_always_lock_free());
    assert!(AtomicU8::is_lock_free());
    assert!(AtomicI16::is_always_lock_free());
    assert!(AtomicI16::is_lock_free());
    assert!(AtomicU16::is_always_lock_free());
    assert!(AtomicU16::is_lock_free());
    assert!(AtomicI32::is_always_lock_free());
    assert!(AtomicI32::is_lock_free());
    assert!(AtomicU32::is_always_lock_free());
    assert!(AtomicU32::is_lock_free());
    if cfg!(target_has_atomic = "64") {
        assert!(AtomicI64::is_always_lock_free());
        assert!(AtomicI64::is_lock_free());
        assert!(AtomicU64::is_always_lock_free());
        assert!(AtomicU64::is_lock_free());
    } else {
        assert!(!AtomicI64::is_always_lock_free());
        assert!(!AtomicI64::is_lock_free());
        assert!(!AtomicU64::is_always_lock_free());
        assert!(!AtomicU64::is_lock_free());
    }
    if cfg!(any(
        target_arch = "aarch64",
        all(
            target_arch = "powerpc64",
            portable_atomic_asm_experimental_arch,
            any(
                target_feature = "quadword-atomics",
                portable_atomic_target_feature = "quadword-atomics"
            )
        ),
        all(target_arch = "s390x", portable_atomic_asm_experimental_arch),
        all(
            target_arch = "x86_64",
            any(target_feature = "cmpxchg16b", portable_atomic_target_feature = "cmpxchg16b")
        ),
    )) {
        assert!(AtomicI128::is_always_lock_free());
        assert!(AtomicI128::is_lock_free());
        assert!(AtomicU128::is_always_lock_free());
        assert!(AtomicU128::is_lock_free());
    } else {
        assert!(!AtomicI128::is_always_lock_free());
        assert!(!AtomicU128::is_always_lock_free());
        #[cfg(not(target_arch = "x86_64"))]
        {
            assert!(!AtomicI128::is_lock_free());
            assert!(!AtomicU128::is_lock_free());
        }
        #[cfg(target_arch = "x86_64")]
        // Miri doesn't support inline assembly used in is_x86_feature_detected
        #[cfg(not(miri))]
        {
            let has_cmpxchg16b = cfg!(portable_atomic_cmpxchg16b_dynamic)
                && std::is_x86_feature_detected!("cmpxchg16b");
            assert_eq!(AtomicI128::is_lock_free(), has_cmpxchg16b);
            assert_eq!(AtomicU128::is_lock_free(), has_cmpxchg16b);
        }
    }
}