Skip to main content

ordinal_map/
atomic.rs

1use std::fmt;
2use std::fmt::Debug;
3use std::fmt::Formatter;
4use std::marker::PhantomData;
5use std::sync::atomic::AtomicUsize;
6use std::sync::atomic::Ordering;
7
8use crate::Ordinal;
9
10/// [`Ordinal`] stored in [`AtomicUsize`].
11///
12/// # Example
13///
14/// ```
15/// # use std::sync::atomic::Ordering;
16/// # use ordinal_map::AtomicOrdinal;
17/// # use ordinal_map_derive::Ordinal;
18///
19/// #[derive(Ordinal)]
20/// enum Color {
21///     Red,
22///     Green,
23///     Blue,
24/// }
25///
26/// let a = AtomicOrdinal::new(Color::Red);
27/// let ret = a.compare_exchange(
28///     Color::Red,
29///     Color::Blue,
30///     Ordering::Relaxed,
31///     Ordering::Relaxed,
32/// );
33/// assert!(ret.is_ok());
34/// ```
35pub struct AtomicOrdinal<T> {
36    atomic: AtomicUsize,
37    _marker: PhantomData<T>,
38}
39
40impl<T: Ordinal + Debug> Debug for AtomicOrdinal<T> {
41    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
42        let v = self.load(Ordering::Relaxed);
43        Debug::fmt(&v, f)
44    }
45}
46
47/// Default is [`T::default()`](Default::default).
48impl<T: Ordinal + Default> Default for AtomicOrdinal<T> {
49    #[inline]
50    fn default() -> Self {
51        AtomicOrdinal::new(T::default())
52    }
53}
54
55impl<T: Ordinal> AtomicOrdinal<T> {
56    /// Store an ordinal value inside [`AtomicUsize`].
57    #[inline]
58    pub fn new(value: T) -> Self {
59        Self {
60            atomic: AtomicUsize::new(value.ordinal()),
61            _marker: PhantomData,
62        }
63    }
64
65    /// Load an ordinal value from [`AtomicUsize`].
66    pub fn load(&self, ordering: Ordering) -> T {
67        T::from_ordinal(self.atomic.load(ordering)).unwrap()
68    }
69
70    /// Store the ordinal value in [`AtomicUsize`].
71    pub fn store(&self, value: T, ordering: Ordering) {
72        self.atomic.store(value.ordinal(), ordering);
73    }
74
75    /// Compare exchange.
76    pub fn compare_exchange(
77        &self,
78        old: T,
79        new: T,
80        success: Ordering,
81        failure: Ordering,
82    ) -> Result<T, T> {
83        let old_ord = old.ordinal();
84        let new_ord = new.ordinal();
85        let res = self
86            .atomic
87            .compare_exchange(old_ord, new_ord, success, failure);
88        match res {
89            Ok(v) => Ok(T::from_ordinal(v).unwrap()),
90            Err(v) => Err(T::from_ordinal(v).unwrap()),
91        }
92    }
93}