Skip to content

Commit

Permalink
Add Atomic*::into_inner (#327)
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e authored Aug 9, 2023
1 parent a2f289e commit 053377c
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 30 deletions.
8 changes: 8 additions & 0 deletions src/sync/atomic/bool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ impl AtomicBool {
self.0.unsync_load()
}

/// Consumes the atomic and returns the contained value.
#[track_caller]
pub fn into_inner(self) -> bool {
// SAFETY: ownership guarantees that no other threads are concurrently
// accessing the atomic value.
unsafe { self.unsync_load() }
}

/// Loads a value from the atomic bool.
#[track_caller]
pub fn load(&self, order: Ordering) -> bool {
Expand Down
68 changes: 38 additions & 30 deletions src/sync/atomic/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ use std::sync::atomic::Ordering;

#[rustfmt::skip] // rustfmt cannot properly format multi-line concat!.
macro_rules! atomic_int {
($name: ident, $atomic_type: ty) => {
($name: ident, $int_type: ty) => {
#[doc = concat!(
" Mock implementation of `std::sync::atomic::", stringify!($name), "`.\n\n\
NOTE: Unlike `std::sync::atomic::", stringify!($name), "`, \
this type has a different in-memory representation than `",
stringify!($atomic_type), "`.",
stringify!($int_type), "`.",
)]
#[derive(Debug)]
pub struct $name(Atomic<$atomic_type>);
pub struct $name(Atomic<$int_type>);

impl $name {
#[doc = concat!(" Creates a new instance of `", stringify!($name), "`.")]
#[track_caller]
pub fn new(v: $atomic_type) -> Self {
pub fn new(v: $int_type) -> Self {
Self(Atomic::new(v, location!()))
}

/// Get access to a mutable reference to the inner value.
#[track_caller]
pub fn with_mut<R>(&mut self, f: impl FnOnce(&mut $atomic_type) -> R) -> R {
pub fn with_mut<R>(&mut self, f: impl FnOnce(&mut $int_type) -> R) -> R {
self.0.with_mut(f)
}

Expand All @@ -36,108 +36,116 @@ macro_rules! atomic_int {
/// this *should* always be equivalent to a non-atomic load of an un-shared
/// integer value.
#[track_caller]
pub unsafe fn unsync_load(&self) -> $atomic_type {
pub unsafe fn unsync_load(&self) -> $int_type {
self.0.unsync_load()
}

/// Consumes the atomic and returns the contained value.
#[track_caller]
pub fn into_inner(self) -> $int_type {
// SAFETY: ownership guarantees that no other threads are concurrently
// accessing the atomic value.
unsafe { self.unsync_load() }
}

/// Loads a value from the atomic integer.
#[track_caller]
pub fn load(&self, order: Ordering) -> $atomic_type {
pub fn load(&self, order: Ordering) -> $int_type {
self.0.load(order)
}

/// Stores a value into the atomic integer.
#[track_caller]
pub fn store(&self, val: $atomic_type, order: Ordering) {
pub fn store(&self, val: $int_type, order: Ordering) {
self.0.store(val, order)
}

/// Stores a value into the atomic integer, returning the previous value.
#[track_caller]
pub fn swap(&self, val: $atomic_type, order: Ordering) -> $atomic_type {
pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
self.0.swap(val, order)
}

/// Stores a value into the atomic integer if the current value is the same as the `current` value.
#[track_caller]
pub fn compare_and_swap(
&self,
current: $atomic_type,
new: $atomic_type,
current: $int_type,
new: $int_type,
order: Ordering,
) -> $atomic_type {
) -> $int_type {
self.0.compare_and_swap(current, new, order)
}

/// Stores a value into the atomic if the current value is the same as the `current` value.
#[track_caller]
pub fn compare_exchange(
&self,
current: $atomic_type,
new: $atomic_type,
current: $int_type,
new: $int_type,
success: Ordering,
failure: Ordering,
) -> Result<$atomic_type, $atomic_type> {
) -> Result<$int_type, $int_type> {
self.0.compare_exchange(current, new, success, failure)
}

/// Stores a value into the atomic if the current value is the same as the current value.
#[track_caller]
pub fn compare_exchange_weak(
&self,
current: $atomic_type,
new: $atomic_type,
current: $int_type,
new: $int_type,
success: Ordering,
failure: Ordering,
) -> Result<$atomic_type, $atomic_type> {
) -> Result<$int_type, $int_type> {
self.compare_exchange(current, new, success, failure)
}

/// Adds to the current value, returning the previous value.
#[track_caller]
pub fn fetch_add(&self, val: $atomic_type, order: Ordering) -> $atomic_type {
pub fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
self.0.rmw(|v| v.wrapping_add(val), order)
}

/// Subtracts from the current value, returning the previous value.
#[track_caller]
pub fn fetch_sub(&self, val: $atomic_type, order: Ordering) -> $atomic_type {
pub fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
self.0.rmw(|v| v.wrapping_sub(val), order)
}

/// Bitwise "and" with the current value.
#[track_caller]
pub fn fetch_and(&self, val: $atomic_type, order: Ordering) -> $atomic_type {
pub fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
self.0.rmw(|v| v & val, order)
}

/// Bitwise "nand" with the current value.
#[track_caller]
pub fn fetch_nand(&self, val: $atomic_type, order: Ordering) -> $atomic_type {
pub fn fetch_nand(&self, val: $int_type, order: Ordering) -> $int_type {
self.0.rmw(|v| !(v & val), order)
}

/// Bitwise "or" with the current value.
#[track_caller]
pub fn fetch_or(&self, val: $atomic_type, order: Ordering) -> $atomic_type {
pub fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
self.0.rmw(|v| v | val, order)
}

/// Bitwise "xor" with the current value.
#[track_caller]
pub fn fetch_xor(&self, val: $atomic_type, order: Ordering) -> $atomic_type {
pub fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
self.0.rmw(|v| v ^ val, order)
}

/// Stores the maximum of the current and provided value, returning the previous value
#[track_caller]
pub fn fetch_max(&self, val: $atomic_type, order: Ordering) -> $atomic_type {
pub fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
self.0.rmw(|v| v.max(val), order)
}

/// Stores the minimum of the current and provided value, returning the previous value
#[track_caller]
pub fn fetch_min(&self, val: $atomic_type, order: Ordering) -> $atomic_type {
pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
self.0.rmw(|v| v.min(val), order)
}

Expand All @@ -150,9 +158,9 @@ macro_rules! atomic_int {
set_order: Ordering,
fetch_order: Ordering,
f: F,
) -> Result<$atomic_type, $atomic_type>
) -> Result<$int_type, $int_type>
where
F: FnMut($atomic_type) -> Option<$atomic_type>,
F: FnMut($int_type) -> Option<$int_type>,
{
self.0.fetch_update(set_order, fetch_order, f)
}
Expand All @@ -164,8 +172,8 @@ macro_rules! atomic_int {
}
}

impl From<$atomic_type> for $name {
fn from(v: $atomic_type) -> Self {
impl From<$int_type> for $name {
fn from(v: $int_type) -> Self {
Self::new(v)
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/sync/atomic/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ impl<T> AtomicPtr<T> {
self.0.with_mut(f)
}

/// Consumes the atomic and returns the contained value.
#[track_caller]
pub fn into_inner(self) -> *mut T {
// SAFETY: ownership guarantees that no other threads are concurrently
// accessing the atomic value.
unsafe { self.unsync_load() }
}

/// Loads a value from the pointer.
#[track_caller]
pub fn load(&self, order: Ordering) -> *mut T {
Expand Down

0 comments on commit 053377c

Please sign in to comment.