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
47impl<T: Ordinal> AtomicOrdinal<T> {
48    /// Store an ordinal value inside [`AtomicUsize`].
49    #[inline]
50    pub fn new(value: T) -> Self {
51        Self {
52            atomic: AtomicUsize::new(value.ordinal()),
53            _marker: PhantomData,
54        }
55    }
56
57    /// Load an ordinal value from [`AtomicUsize`].
58    pub fn load(&self, ordering: Ordering) -> T {
59        T::from_ordinal(self.atomic.load(ordering)).unwrap()
60    }
61
62    /// Store the ordinal value in [`AtomicUsize`].
63    pub fn store(&self, value: T, ordering: Ordering) {
64        self.atomic.store(value.ordinal(), ordering);
65    }
66
67    /// Compare exchange.
68    pub fn compare_exchange(
69        &self,
70        old: T,
71        new: T,
72        success: Ordering,
73        failure: Ordering,
74    ) -> Result<T, T> {
75        let old_ord = old.ordinal();
76        let new_ord = new.ordinal();
77        let res = self
78            .atomic
79            .compare_exchange(old_ord, new_ord, success, failure);
80        match res {
81            Ok(v) => Ok(T::from_ordinal(v).unwrap()),
82            Err(v) => Err(T::from_ordinal(v).unwrap()),
83        }
84    }
85}