use core::fmt;
use core::marker::PhantomData;
use core::sync::atomic::Ordering;
use super::order::{AtomicOrder, OrderingSource};
use super::traits::Atomic;
use crate::token::{InvariantLifetime, ReadPermit, WritePermit};
#[repr(transparent)]
pub struct BrandedAtomic<'brand, A: Atomic> {
inner: A,
_brand: InvariantLifetime<'brand>,
}
macro_rules! order_pair {
(
$(#[$doc:meta])*
fn $name:ident;
$(#[$doc_with:meta])*
fn $name_with:ident;
before: ( $( $arg:ident : $argty:ty ),* $(,)? );
after: ( $( $tail:ident : $tailty:ty ),* $(,)? );
generics: ( $( $extra:ident ),* $(,)? );
bounds: ( $( [ $($bound:tt)* ] ),* $(,)? );
order: $order_name:ident;
ret: $ret:ty;
body: $($body:tt)*
) => {
$(#[$doc])*
#[inline]
pub fn $name<P $(, $extra)*>(
&self,
$( $arg: $argty, )*
_permit: P,
$order_name: Ordering,
$( $tail: $tailty, )*
) -> $ret
where
P: ReadPermit<'brand>
$(, $($bound)*)*
{
self.$($body)*
}
$(#[$doc_with])*
#[inline]
pub fn $name_with<P, O $(, $extra)*>(
&self,
$( $arg: $argty, )*
_permit: P,
$order_name: O,
$( $tail: $tailty, )*
) -> $ret
where
P: ReadPermit<'brand>,
O: AtomicOrder
$(, $($bound)*)*
{
self.$($body)*
}
};
(
$(#[$doc:meta])*
fn $name:ident;
$(#[$doc_with:meta])*
fn $name_with:ident;
before: ( $( $arg:ident : $argty:ty ),* $(,)? );
orders: ( $order_a:ident , $order_b:ident );
after: ( $( $tail:ident : $tailty:ty ),* $(,)? );
generics: ( $( $extra:ident ),* $(,)? );
bounds: ( $( [ $($bound:tt)* ] ),* $(,)? );
ret: $ret:ty;
body: $($body:tt)*
) => {
$(#[$doc])*
#[inline]
pub fn $name<P $(, $extra)*>(
&self,
$( $arg: $argty, )*
$order_a: Ordering,
$order_b: Ordering,
_permit: P,
$( $tail: $tailty, )*
) -> $ret
where
P: ReadPermit<'brand>
$(, $($bound)*)*
{
self.$($body)*
}
$(#[$doc_with])*
#[inline]
pub fn $name_with<P, O $(, $extra)*>(
&self,
$( $arg: $argty, )*
_permit: P,
order: O,
$( $tail: $tailty, )*
) -> $ret
where
P: ReadPermit<'brand>,
O: AtomicOrder
$(, $($bound)*)*
{
let $order_a = order;
let $order_b = order;
self.$($body)*
}
};
}
mod integer;
impl<'brand, A: Atomic> BrandedAtomic<'brand, A> {
#[inline]
pub fn new(value: A::Value) -> Self {
Self {
inner: A::new_atomic(value),
_brand: PhantomData,
}
}
#[inline]
#[must_use]
pub fn from_mut(atomic: &mut A) -> &mut Self {
unsafe { &mut *core::ptr::from_mut(atomic).cast::<Self>() }
}
#[inline]
#[must_use]
pub fn as_atomic<'a, P>(&'a self, _permit: P) -> &'a A
where
P: ReadPermit<'brand> + 'a,
{
&self.inner
}
#[inline]
#[must_use]
pub fn as_atomic_mut(&mut self) -> &mut A {
&mut self.inner
}
#[inline]
#[must_use]
pub fn into_atomic(self) -> A {
self.inner
}
#[inline]
pub fn with_exclusive<P, R>(&self, _permit: P, f: impl FnOnce(&mut A::Value) -> R) -> R
where
P: WritePermit<'brand>,
{
f(unsafe { &mut *self.inner.value_ptr() })
}
#[inline]
pub fn load_exclusive<P>(&self, permit: P) -> A::Value
where
P: WritePermit<'brand>,
{
self.with_exclusive(permit, |v| *v)
}
#[inline]
pub fn store_exclusive<P>(&self, value: A::Value, permit: P)
where
P: WritePermit<'brand>,
{
self.with_exclusive(permit, |v| *v = value);
}
#[inline]
pub fn get_mut(&mut self) -> &mut A::Value {
self.inner.atomic_get_mut()
}
#[inline]
pub fn into_inner(self) -> A::Value {
self.inner.atomic_into_inner()
}
#[inline]
fn load_ordered<O: OrderingSource>(&self, order: O) -> A::Value {
self.inner.atomic_load(order.load_order())
}
#[inline]
fn store_ordered<O: OrderingSource>(&self, value: A::Value, order: O) {
self.inner.atomic_store(value, order.store_order());
}
#[inline]
fn swap_ordered<O: OrderingSource>(&self, value: A::Value, order: O) -> A::Value {
self.inner.atomic_swap(value, order.rmw_order())
}
#[inline]
fn compare_exchange_ordered<Success, Failure>(
&self,
current: A::Value,
new: A::Value,
success: Success,
failure: Failure,
) -> Result<A::Value, A::Value>
where
Success: OrderingSource,
Failure: OrderingSource,
{
self.inner.atomic_compare_exchange(
current,
new,
success.rmw_order(),
failure.failure_order(),
)
}
#[inline]
fn fetch_update_ordered<SetOrder, FetchOrder, F>(
&self,
set_order: SetOrder,
fetch_order: FetchOrder,
f: F,
) -> Result<A::Value, A::Value>
where
SetOrder: OrderingSource,
FetchOrder: OrderingSource,
F: FnMut(A::Value) -> Option<A::Value>,
{
self.inner
.atomic_fetch_update(set_order.rmw_order(), fetch_order.failure_order(), f)
}
order_pair! {
fn load;
fn load_with;
before: ();
after: ();
generics: ();
bounds: ();
order: order;
ret: A::Value;
body: load_ordered(order)
}
order_pair! {
fn store;
fn store_with;
before: (value: A::Value);
after: ();
generics: ();
bounds: ();
order: order;
ret: ();
body: store_ordered(value, order)
}
order_pair! {
fn swap;
fn swap_with;
before: (value: A::Value);
after: ();
generics: ();
bounds: ();
order: order;
ret: A::Value;
body: swap_ordered(value, order)
}
order_pair! {
fn compare_exchange;
fn compare_exchange_with;
before: (current: A::Value, new: A::Value);
orders: (success, failure);
after: ();
generics: ();
bounds: ();
ret: Result<A::Value, A::Value>;
body: compare_exchange_ordered(current, new, success, failure)
}
order_pair! {
fn fetch_update;
fn fetch_update_with;
before: ();
orders: (set_order, fetch_order);
after: (f: F);
generics: (F);
bounds: ([F: FnMut(A::Value) -> Option<A::Value>]);
ret: Result<A::Value, A::Value>;
body: fetch_update_ordered(set_order, fetch_order, f)
}
}
impl<'brand, A: Atomic + fmt::Debug> fmt::Debug for BrandedAtomic<'brand, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("BrandedAtomic").field(&self.inner).finish()
}
}