Skip to main content

pistonite_cu/
atomic.rs

1use std::sync::atomic::{AtomicUsize, Ordering};
2
3/// An atomic wrapper with an underlying atomic storage and conversion to
4/// a type T.
5///
6/// `Acquire` ordering is used for load and `Release` ordering is used for store.
7///
8/// A proc macro might be provided in the future to simplify declaring a compatible enum type.
9///
10/// ```rust
11/// # use pistonite_cu as cu;
12/// #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
13/// #[repr(u8)]
14/// pub enum MyEnum {
15///    A,
16///    B,
17///    C,
18///    Invalid, //
19/// }
20/// impl From<u8> for MyEnum {
21///     fn from(value: u8) -> Self {
22///         match value {
23///             0 => Self::A,
24///             1 => Self::B,
25///             2 => Self::C,
26///             _ => Self::Invalid,
27///         }
28///     }
29/// }
30/// impl From<MyEnum> for u8 {
31///     fn from(value: MyEnum) -> Self {
32///         value as Self
33///     }
34/// }
35///
36/// # fn main() {
37/// let value: cu::Atomic<u8, MyEnum> = cu::Atomic::new_u8(MyEnum::A as u8);
38/// assert_eq!(MyEnum::A, value.get());
39/// value.set(MyEnum::C);
40/// assert_eq!(MyEnum::C, value.get());
41/// # }
42/// ```
43#[derive(Debug, Default)]
44pub struct Atomic<S, T>(S::Type, std::marker::PhantomData<T>)
45where
46    S: AtomicType,
47    T: From<S> + Into<S>;
48/// Marker type to associate primitive with their atomic versions
49pub trait AtomicType {
50    type Type;
51}
52macro_rules! impl_atomic_type {
53    ($($t:ident => $Atomic:ident, $newfn:ident),* $(,)?) => { $(
54    impl AtomicType for $t {
55        type Type = std::sync::atomic::$Atomic;
56    }
57    impl<T: From<$t> + Into<$t>> Atomic<$t, T> {
58        pub const fn $newfn(value: $t) -> Self {
59            Self(std::sync::atomic::$Atomic::new(value), std::marker::PhantomData)
60        }
61        pub fn get(&self) -> T {
62            self.0.load(std::sync::atomic::Ordering::Acquire).into()
63        }
64        pub fn set(&self, value: T) {
65            self.0.store(value.into(), std::sync::atomic::Ordering::Release)
66        }
67    }
68    )* }
69}
70impl_atomic_type! {
71    i8 => AtomicI8, new_i8,
72    i16 => AtomicI16, new_i16,
73    i32 => AtomicI32, new_i32,
74    i64 => AtomicI64, new_i64,
75    u8 => AtomicU8, new_u8,
76    u16 => AtomicU16, new_u16,
77    u32 => AtomicU32, new_u32,
78    u64 => AtomicU64, new_u64,
79    bool => AtomicBool, new_bool,
80    isize => AtomicIsize, new_isize,
81    usize => AtomicUsize, new_usize,
82}
83
84#[allow(unused)]
85pub(crate) fn next_atomic_usize() -> usize {
86    static ID: AtomicUsize = AtomicUsize::new(1);
87    ID.fetch_add(1, Ordering::SeqCst)
88}