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