atomic-maybe-uninit 0.3.18

Atomic operations on potentially uninitialized integers.
Documentation
// SPDX-License-Identifier: Apache-2.0 OR MIT

macro_rules! test_atomic_all {
    () => {
        #[cfg(not(any(
            target_arch = "avr",
            target_arch = "msp430",
            target_arch = "sparc",
            target_os = "linux",
        )))]
        {
            cfg_has_atomic_cas! {
                println!("target_has_cas: true");
            }
            cfg_no_atomic_cas! {
                println!("target_has_cas: false");
            }
        }
        // Skip AVR/MSP430 because they always provides RMW operations.
        #[cfg(any(target_arch = "sparc", target_os = "linux"))]
        {
            cfg_has_atomic_cas! {
                print_str!("target_has_cas: true\n");
            }
            cfg_no_atomic_cas! {
                print_str!("target_has_cas: false\n");
            }
        }
        #[cfg_attr(target_arch = "m68k", cfg(feature = "isize"))]
        test_atomic!(isize);
        #[cfg_attr(target_arch = "m68k", cfg(feature = "usize"))]
        test_atomic!(usize);
        #[cfg_attr(target_arch = "m68k", cfg(feature = "i8"))]
        test_atomic!(i8);
        #[cfg_attr(target_arch = "m68k", cfg(feature = "u8"))]
        test_atomic!(u8);
        #[cfg_attr(target_arch = "m68k", cfg(feature = "i16"))]
        test_atomic!(i16);
        #[cfg_attr(target_arch = "m68k", cfg(feature = "u16"))]
        test_atomic!(u16);
        cfg_has_atomic_32! {
            #[cfg_attr(target_arch = "m68k", cfg(feature = "i32"))]
            test_atomic!(i32);
            #[cfg_attr(target_arch = "m68k", cfg(feature = "u32"))]
            test_atomic!(u32);
        }
        cfg_has_atomic_64! {
            #[cfg_attr(target_arch = "m68k", cfg(feature = "i64"))]
            test_atomic!(i64);
            #[cfg_attr(target_arch = "m68k", cfg(feature = "u64"))]
            test_atomic!(u64);
        }
        cfg_has_atomic_128! {
            test_atomic!(i128);
            test_atomic!(u128);
        }
    };
}

macro_rules! test_atomic {
    ($ty:ident) => {
        paste::paste! {
            fn [<test_atomic_ $ty>]() {
                __test_atomic!($ty);
            }
            #[cfg(not(any(
                target_arch = "avr",
                target_arch = "msp430",
                target_arch = "sparc",
                target_os = "linux",
            )))]
            {
                print!("{}", concat!("test test_atomic_", stringify!($ty), " ... "));
                [<test_atomic_ $ty>]();
                println!("ok");
            }
            #[cfg(any(
                target_arch = "avr",
                target_arch = "msp430",
                target_arch = "sparc",
                target_os = "linux",
            ))]
            {
                print_str!(concat!("test test_atomic_", stringify!($ty), " ... "));
                [<test_atomic_ $ty>]();
                print_str!("ok\n");
            }
        }
    };
}

macro_rules! __test_atomic {
    ($ty:ident) => {
        load_store();
        fn load_store() {
            static VAR: AtomicMaybeUninit<$ty> =
                AtomicMaybeUninit::<$ty>::new(MaybeUninit::new(10));
            for (load_order, store_order) in LOAD_ORDERINGS.into_iter().zip(STORE_ORDERINGS) {
                unsafe {
                    assert_eq!(VAR.load(load_order).assume_init(), 10);
                    VAR.store(MaybeUninit::new(5), store_order);
                    assert_eq!(VAR.load(load_order).assume_init(), 5);
                    VAR.store(MaybeUninit::uninit(), store_order);
                    let _v = VAR.load(load_order);
                    VAR.store(MaybeUninit::new(10), store_order);

                    let a = AtomicMaybeUninit::<$ty>::new(MaybeUninit::new(1));
                    assert_eq!(a.load(load_order).assume_init(), 1);
                    a.store(MaybeUninit::new($ty::MIN), store_order);
                    assert_eq!(a.load(load_order).assume_init(), $ty::MIN);
                    a.store(MaybeUninit::new($ty::MAX), store_order);
                    assert_eq!(a.load(load_order).assume_init(), $ty::MAX);
                    let a = AtomicMaybeUninit::<$ty>::new(MaybeUninit::uninit());
                    let _v = a.load(load_order);
                    a.store(MaybeUninit::new(2), store_order);
                    assert_eq!(a.load(load_order).assume_init(), 2);
                    a.store(MaybeUninit::uninit(), store_order);
                    let _v = a.load(load_order);
                }
            }
        }
        cfg_has_atomic_cas! {
        swap();
        fn swap() {
            for order in SWAP_ORDERINGS {
                unsafe {
                    let a = AtomicMaybeUninit::<$ty>::new(MaybeUninit::new(5));
                    assert_eq!(a.swap(MaybeUninit::new($ty::MIN), order).assume_init(), 5);
                    assert_eq!(a.swap(MaybeUninit::new($ty::MAX), order).assume_init(), $ty::MIN);
                    assert_eq!(a.swap(MaybeUninit::new(10), order).assume_init(), $ty::MAX);
                    assert_eq!(a.swap(MaybeUninit::uninit(), order).assume_init(), 10);
                    let _v = a.swap(MaybeUninit::new(15), order);
                    let a = AtomicMaybeUninit::<$ty>::new(MaybeUninit::uninit());
                    let _v = a.swap(MaybeUninit::new(10), order);
                    assert_eq!(a.swap(MaybeUninit::uninit(), order).assume_init(), 10);
                }
            }
        }
        compare_exchange();
        fn compare_exchange() {
            for (success, failure) in COMPARE_EXCHANGE_ORDERINGS {
                unsafe {
                    for (x, y) in [(5, 10), ($ty::MAX, $ty::MIN), ($ty::MIN, $ty::MAX)] {
                        let a = AtomicMaybeUninit::<$ty>::new(MaybeUninit::new(x));
                        assert_eq!(
                            a.compare_exchange(
                                MaybeUninit::new(x),
                                MaybeUninit::new(y),
                                success,
                                failure
                            )
                            .unwrap()
                            .assume_init(),
                            x
                        );
                        assert_eq!(a.load(Ordering::Relaxed).assume_init(), y);
                        assert_eq!(
                            a.compare_exchange(
                                MaybeUninit::new(6),
                                MaybeUninit::new(12),
                                success,
                                failure
                            )
                            .unwrap_err()
                            .assume_init(),
                            y
                        );
                        assert_eq!(a.load(Ordering::Relaxed).assume_init(), y);
                    }

                    for base in [0, !0] {
                        for bit in 0..$ty::BITS {
                            let flipped = base ^ (1 << bit);
                            let a = AtomicMaybeUninit::<$ty>::new(MaybeUninit::new(base));
                            assert_eq!(
                                a.compare_exchange(
                                    MaybeUninit::new(flipped),
                                    MaybeUninit::new(flipped),
                                    success,
                                    failure
                                )
                                .unwrap_err()
                                .assume_init(),
                                base,
                                "flipped bit: {bit}"
                            );
                            let a = AtomicMaybeUninit::<$ty>::new(MaybeUninit::new(flipped));
                            assert_eq!(
                                a.compare_exchange(
                                    MaybeUninit::new(base),
                                    MaybeUninit::new(base),
                                    success,
                                    failure
                                )
                                .unwrap_err()
                                .assume_init(),
                                flipped,
                                "flipped bit: {bit}"
                            );
                        }
                    }
                }
            }
        }
        compare_exchange_weak();
        fn compare_exchange_weak() {
            for (success, failure) in COMPARE_EXCHANGE_ORDERINGS {
                unsafe {
                    for x in [4, $ty::MAX, $ty::MIN] {
                        let a = AtomicMaybeUninit::<$ty>::new(MaybeUninit::new(x));
                        assert_eq!(
                            a.compare_exchange_weak(
                                MaybeUninit::new(6),
                                MaybeUninit::new(8),
                                success,
                                failure
                            )
                            .unwrap_err()
                            .assume_init(),
                            x
                        );
                        let mut old = a.load(Ordering::Relaxed);
                        loop {
                            let new = MaybeUninit::new(old.assume_init().wrapping_add(2));
                            match a.compare_exchange_weak(old, new, success, failure) {
                                Ok(_) => break,
                                Err(x) => old = x,
                            }
                        }
                        assert_eq!(a.load(Ordering::Relaxed).assume_init(), x.wrapping_add(2));
                    }

                    for base in [0, !0] {
                        for bit in 0..$ty::BITS {
                            let flipped = base ^ (1 << bit);
                            let a = AtomicMaybeUninit::<$ty>::new(MaybeUninit::new(base));
                            assert_eq!(
                                a.compare_exchange(
                                    MaybeUninit::new(flipped),
                                    MaybeUninit::new(flipped),
                                    success,
                                    failure
                                )
                                .unwrap_err()
                                .assume_init(),
                                base,
                                "flipped bit: {bit}"
                            );
                            let a = AtomicMaybeUninit::<$ty>::new(MaybeUninit::new(flipped));
                            assert_eq!(
                                a.compare_exchange(
                                    MaybeUninit::new(base),
                                    MaybeUninit::new(base),
                                    success,
                                    failure
                                )
                                .unwrap_err()
                                .assume_init(),
                                flipped,
                                "flipped bit: {bit}"
                            );
                        }
                    }
                }
            }
        }
        fetch_update();
        fn fetch_update() {
            for (success, failure) in COMPARE_EXCHANGE_ORDERINGS {
                unsafe {
                    let a = AtomicMaybeUninit::<$ty>::new(MaybeUninit::new(7));
                    assert_eq!(
                        a.fetch_update(success, failure, |_| None).unwrap_err().assume_init(),
                        7
                    );
                    assert_eq!(
                        a.fetch_update(success, failure, |x| Some(MaybeUninit::new(
                            x.assume_init() + 1
                        )))
                        .unwrap()
                        .assume_init(),
                        7
                    );
                    assert_eq!(
                        a.fetch_update(success, failure, |x| Some(MaybeUninit::new(
                            x.assume_init() + 1
                        )))
                        .unwrap()
                        .assume_init(),
                        8
                    );
                    assert_eq!(a.load(Ordering::Relaxed).assume_init(), 9);
                }
            }
        }
        }
    };
}

const LOAD_ORDERINGS: [Ordering; 3] = [Ordering::Relaxed, Ordering::Acquire, Ordering::SeqCst];
const STORE_ORDERINGS: [Ordering; 3] = [Ordering::Relaxed, Ordering::Release, Ordering::SeqCst];
cfg_has_atomic_cas! {
const SWAP_ORDERINGS: [Ordering; 5] =
    [Ordering::Relaxed, Ordering::Release, Ordering::Acquire, Ordering::AcqRel, Ordering::SeqCst];
const COMPARE_EXCHANGE_ORDERINGS: [(Ordering, Ordering); 15] = [
    (Ordering::Relaxed, Ordering::Relaxed),
    (Ordering::Relaxed, Ordering::Acquire),
    (Ordering::Relaxed, Ordering::SeqCst),
    (Ordering::Acquire, Ordering::Relaxed),
    (Ordering::Acquire, Ordering::Acquire),
    (Ordering::Acquire, Ordering::SeqCst),
    (Ordering::Release, Ordering::Relaxed),
    (Ordering::Release, Ordering::Acquire),
    (Ordering::Release, Ordering::SeqCst),
    (Ordering::AcqRel, Ordering::Relaxed),
    (Ordering::AcqRel, Ordering::Acquire),
    (Ordering::AcqRel, Ordering::SeqCst),
    (Ordering::SeqCst, Ordering::Relaxed),
    (Ordering::SeqCst, Ordering::Acquire),
    (Ordering::SeqCst, Ordering::SeqCst),
];
}