From 053377ccbc8bc94d88c8144ef6e19e91b68c7366 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Wed, 9 Aug 2023 23:06:00 +0900 Subject: [PATCH] Add Atomic*::into_inner (#327) --- src/sync/atomic/bool.rs | 8 +++++ src/sync/atomic/int.rs | 68 +++++++++++++++++++++++------------------ src/sync/atomic/ptr.rs | 8 +++++ 3 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/sync/atomic/bool.rs b/src/sync/atomic/bool.rs index 7e8c1414..64f9bb6a 100644 --- a/src/sync/atomic/bool.rs +++ b/src/sync/atomic/bool.rs @@ -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 { diff --git a/src/sync/atomic/int.rs b/src/sync/atomic/int.rs index de4bc829..f4375667 100644 --- a/src/sync/atomic/int.rs +++ b/src/sync/atomic/int.rs @@ -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(&mut self, f: impl FnOnce(&mut $atomic_type) -> R) -> R { + pub fn with_mut(&mut self, f: impl FnOnce(&mut $int_type) -> R) -> R { self.0.with_mut(f) } @@ -36,25 +36,33 @@ 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) } @@ -62,10 +70,10 @@ macro_rules! atomic_int { #[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) } @@ -73,11 +81,11 @@ macro_rules! atomic_int { #[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) } @@ -85,59 +93,59 @@ macro_rules! atomic_int { #[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) } @@ -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) } @@ -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) } } diff --git a/src/sync/atomic/ptr.rs b/src/sync/atomic/ptr.rs index 69bf983f..591918ee 100644 --- a/src/sync/atomic/ptr.rs +++ b/src/sync/atomic/ptr.rs @@ -39,6 +39,14 @@ impl AtomicPtr { 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 {