use crate::util::Address;
use core::sync::atomic::*;
use num_traits::{FromPrimitive, ToPrimitive};
use num_traits::{Unsigned, WrappingAdd, WrappingSub, Zero};
pub trait Bits {
const BITS: u32;
const LOG2: u32;
}
macro_rules! impl_bits_trait {
($t: ty) => {
impl Bits for $t {
const BITS: u32 = <$t>::BITS;
const LOG2: u32 = Self::BITS.trailing_zeros();
}
};
}
impl_bits_trait!(u8);
impl_bits_trait!(u16);
impl_bits_trait!(u32);
impl_bits_trait!(u64);
impl_bits_trait!(usize);
pub trait BitwiseOps {
fn bitand(self, other: Self) -> Self;
fn bitor(self, other: Self) -> Self;
fn bitxor(self, other: Self) -> Self;
fn inv(self) -> Self;
}
macro_rules! impl_bitwise_ops_trait {
($t: ty) => {
impl BitwiseOps for $t {
fn bitand(self, other: Self) -> Self {
self & other
}
fn bitor(self, other: Self) -> Self {
self | other
}
fn bitxor(self, other: Self) -> Self {
self ^ other
}
fn inv(self) -> Self {
!self
}
}
};
}
impl_bitwise_ops_trait!(u8);
impl_bitwise_ops_trait!(u16);
impl_bitwise_ops_trait!(u32);
impl_bitwise_ops_trait!(u64);
impl_bitwise_ops_trait!(usize);
pub trait MetadataValue:
Unsigned
+ Zero
+ WrappingAdd
+ WrappingSub
+ Bits
+ BitwiseOps
+ ToPrimitive
+ Copy
+ FromPrimitive
+ std::fmt::Display
+ std::fmt::Debug
{
unsafe fn load(addr: Address) -> Self;
unsafe fn load_atomic(addr: Address, order: Ordering) -> Self;
unsafe fn store(addr: Address, value: Self);
unsafe fn store_atomic(addr: Address, value: Self, order: Ordering);
unsafe fn compare_exchange(
addr: Address,
current: Self,
new: Self,
success: Ordering,
failure: Ordering,
) -> Result<Self, Self>;
unsafe fn fetch_add(addr: Address, value: Self, order: Ordering) -> Self;
unsafe fn fetch_sub(addr: Address, value: Self, order: Ordering) -> Self;
unsafe fn fetch_and(addr: Address, value: Self, order: Ordering) -> Self;
unsafe fn fetch_or(addr: Address, value: Self, order: Ordering) -> Self;
unsafe fn fetch_update<F>(
addr: Address,
set_order: Ordering,
fetch_order: Ordering,
f: F,
) -> Result<Self, Self>
where
F: FnMut(Self) -> Option<Self>;
}
macro_rules! impl_metadata_value_trait {
($non_atomic: ty, $atomic: ty) => {
impl MetadataValue for $non_atomic {
unsafe fn load(addr: Address) -> Self {
addr.load::<$non_atomic>()
}
unsafe fn load_atomic(addr: Address, order: Ordering) -> Self {
addr.as_ref::<$atomic>().load(order)
}
unsafe fn store(addr: Address, value: Self) {
addr.store::<$non_atomic>(value)
}
unsafe fn store_atomic(addr: Address, value: Self, order: Ordering) {
addr.as_ref::<$atomic>().store(value, order)
}
unsafe fn compare_exchange(
addr: Address,
current: Self,
new: Self,
success: Ordering,
failure: Ordering,
) -> Result<Self, Self> {
addr.as_ref::<$atomic>()
.compare_exchange(current, new, success, failure)
}
unsafe fn fetch_add(addr: Address, value: Self, order: Ordering) -> Self {
addr.as_ref::<$atomic>().fetch_add(value, order)
}
unsafe fn fetch_sub(addr: Address, value: Self, order: Ordering) -> Self {
addr.as_ref::<$atomic>().fetch_sub(value, order)
}
unsafe fn fetch_and(addr: Address, value: Self, order: Ordering) -> Self {
addr.as_ref::<$atomic>().fetch_and(value, order)
}
unsafe fn fetch_or(addr: Address, value: Self, order: Ordering) -> Self {
addr.as_ref::<$atomic>().fetch_or(value, order)
}
unsafe fn fetch_update<F>(
addr: Address,
set_order: Ordering,
fetch_order: Ordering,
f: F,
) -> Result<Self, Self>
where
F: FnMut(Self) -> Option<Self>,
{
addr.as_ref::<$atomic>()
.fetch_update(set_order, fetch_order, f)
}
}
};
}
impl_metadata_value_trait!(u8, AtomicU8);
impl_metadata_value_trait!(u16, AtomicU16);
impl_metadata_value_trait!(u32, AtomicU32);
impl_metadata_value_trait!(u64, AtomicU64);
impl_metadata_value_trait!(usize, AtomicUsize);