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}