diff --git a/.gitignore b/.gitignore index 96ef6c0..1b9ff89 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target Cargo.lock +/.idea/ diff --git a/README.md b/README.md index 0be8db5..9a47c3a 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,30 @@ Traits over atomic primitive integer types. +## Example + +```rust +fn incr(value: &T) -> Result<::Prim, ::Prim> { + value.fetch_update( + Ordering::SeqCst, + Ordering::SeqCst, + |i| Some(if i == T::MAX { T::MIN } else { i + T::ONE }) + ) +} + +let value = AtomicU8::new(255); +assert_eq!(incr(&value), Ok(255)); +assert_eq!(incr(&value), Ok(0)); +``` + ## Notes -* Enable feature `nightly` to get `min`, `max`, `fetch_update` and - `as_mut_ptr` when you have a nightly compiler available. +* Enable feature `nightly` to get `as_mut_ptr` when you have a nightly compiler available. +* Rust 1.45.0 or newer is required. ## Copyright and License - Copyright (c) 2020 James Laver, atomic_prim_traits contributors. + Copyright (c) 2020-2023 James Laver, atomic_prim_traits contributors. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/src/lib.rs b/src/lib.rs index 503e9ff..8c1d99f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![cfg_attr(feature = "nightly", feature(atomic_min_max, atomic_mut_ptr, no_more_cas))] +#![cfg_attr(feature = "nightly", feature(atomic_mut_ptr))] use std::sync::atomic::{self, Ordering}; use std::hash::Hash; use std::fmt::{Debug, Display}; @@ -14,17 +14,23 @@ use std::ops::{ pub trait AtomicInt : Default + Send + Sync + RefUnwindSafe + UnwindSafe { type Prim : Copy + Debug + Display + Eq + Hash + Ord + Sized - + Add + AddAssign - + BitAnd + BitAndAssign - + BitOr + BitOrAssign - + BitXor + BitXorAssign - + Div + DivAssign - + Mul + MulAssign - + Not - + Rem + RemAssign - + Shl + ShlAssign - + Shr + ShrAssign - + Sub + SubAssign; + + Add::Prim> + AddAssign + + BitAnd::Prim> + BitAndAssign + + BitOr::Prim> + BitOrAssign + + BitXor::Prim> + BitXorAssign + + Div::Prim> + DivAssign + + Mul::Prim> + MulAssign + + Not::Prim> + + Rem::Prim> + RemAssign + + Shl::Prim> + ShlAssign + + Shr::Prim> + ShrAssign + + Sub::Prim> + SubAssign; + + const ZERO: ::Prim; + const ONE: ::Prim; + + const MIN: ::Prim; + const MAX: ::Prim; fn new(val: ::Prim) -> Self; @@ -64,18 +70,15 @@ pub trait AtomicInt : Default + Send + Sync + RefUnwindSafe + UnwindSafe { ordering: Ordering ) -> ::Prim; - #[cfg(feature="nightly")] fn fetch_min(&self, val: ::Prim, order: Ordering) -> ::Prim; - #[cfg(feature="nightly")] fn fetch_max(&self, val: ::Prim, order: Ordering) -> ::Prim; - #[cfg(feature="nightly")] fn fetch_update( &self, - f: F, + set_order: Ordering, fetch_order: Ordering, - set_order: Ordering + f: F ) -> Result<::Prim, ::Prim> where F: FnMut(::Prim) -> Option<::Prim>; @@ -89,13 +92,6 @@ pub trait AtomicInt : Default + Send + Sync + RefUnwindSafe + UnwindSafe { fn swap(&self, val: ::Prim, order: Ordering) -> ::Prim; - fn compare_and_swap( - &self, - current: ::Prim, - new: ::Prim, - ordering: Ordering - ) -> ::Prim; - fn compare_exchange( &self, current: ::Prim, @@ -119,6 +115,12 @@ pub trait AtomicInt : Default + Send + Sync + RefUnwindSafe + UnwindSafe { macro_rules! impl_atomic_int { ($atomic:ty = $prim:ty) => { impl AtomicInt for $atomic { + const ZERO: $prim = 0; + const ONE: $prim = 1; + + const MIN: $prim = <$prim>::MIN; + const MAX: $prim = <$prim>::MAX; + type Prim = $prim; fn new(val: $prim) -> Self { @@ -173,7 +175,6 @@ macro_rules! impl_atomic_int { self.fetch_xor(new, ordering) } - #[cfg(feature = "nightly")] fn fetch_min( &self, val: $prim, @@ -182,7 +183,6 @@ macro_rules! impl_atomic_int { self.fetch_min(val, ordering) } - #[cfg(feature = "nightly")] fn fetch_max( &self, val: $prim, @@ -191,17 +191,16 @@ macro_rules! impl_atomic_int { self.fetch_max(val, ordering) } - #[cfg(feature = "nightly")] fn fetch_update( &self, - f: F, - fetch_order: Ordering, set_order: Ordering, + fetch_order: Ordering, + f: F, ) -> Result<$prim, $prim> where F: FnMut($prim) -> Option<$prim>, { - self.fetch_update(f, fetch_order, set_order) + self.fetch_update(set_order, fetch_order, f) } fn get_mut(&mut self) -> &mut $prim { @@ -224,15 +223,6 @@ macro_rules! impl_atomic_int { self.swap(val, order) } - fn compare_and_swap( - &self, - current: $prim, - new: $prim, - ordering: Ordering - ) -> $prim { - self.compare_and_swap(current, new, ordering) - } - fn compare_exchange( &self, current: $prim, @@ -272,3 +262,28 @@ impl_atomic_int!(atomic::AtomicI16 = i16); impl_atomic_int!(atomic::AtomicI32 = i32); impl_atomic_int!(atomic::AtomicI64 = i64); impl_atomic_int!(atomic::AtomicIsize = isize); + +#[cfg(test)] +mod test { + use std::sync::atomic::AtomicU8; + use super::*; + + #[test] + fn test_fetch_update() { + fn incr(value: &T) -> Result<::Prim, ::Prim> { + value.fetch_update( + Ordering::SeqCst, + Ordering::SeqCst, + |i| Some(if i == T::MAX { T::MIN } else { i + T::ONE }) + ) + } + + let value = AtomicU8::new(0); + assert_eq!(incr(&value), Ok(0)); + assert_eq!(incr(&value), Ok(1)); + + let value = AtomicU8::new(255); + assert_eq!(incr(&value), Ok(255)); + assert_eq!(incr(&value), Ok(0)); + } +} \ No newline at end of file