1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use crate::{Shared, Shield, Tag};
use std::{
    marker::PhantomData,
    mem,
    sync::atomic::{AtomicUsize, Ordering},
};

fn map_both<T, U, F>(result: Result<T, T>, f: F) -> Result<U, U>
where
    F: FnOnce(T) -> U,
{
    match result {
        Ok(v) => Ok(f(v)),
        Err(v) => Err(f(v)),
    }
}

#[repr(transparent)]
pub struct Atomic<V, T>
where
    T: Tag,
{
    pub(crate) data: AtomicUsize,
    _m0: PhantomData<V>,
    _m1: PhantomData<T>,
}

impl<V, T> Atomic<V, T>
where
    T: Tag,
{
    /// # Safety
    /// Marked unsafe because this is not usually what the user wants.
    /// `Atomic::null` should be preferred when possible.
    pub unsafe fn from_raw(raw: usize) -> Self {
        Self {
            data: AtomicUsize::new(raw),
            _m0: PhantomData,
            _m1: PhantomData,
        }
    }

    pub fn null() -> Self {
        unsafe { Self::from_raw(0) }
    }

    pub fn null_vec(len: usize) -> Vec<Self> {
        unsafe {
            #[allow(clippy::unsound_collection_transmute)]
            mem::transmute(vec![0_usize; len])
        }
    }

    pub fn load<'shield>(
        &self,
        ordering: Ordering,
        _shield: &'shield Shield<'_>,
    ) -> Shared<'shield, V, T> {
        let raw = self.data.load(ordering);
        unsafe { Shared::from_raw(raw) }
    }

    pub fn store<'shield>(
        &self,
        data: Shared<'_, V, T>,
        ordering: Ordering,
        _shield: &'shield Shield<'_>,
    ) {
        let raw = data.into_raw();
        self.data.store(raw, ordering);
    }

    pub fn swap<'shield>(
        &self,
        new: Shared<'_, V, T>,
        ordering: Ordering,
        _shield: &'shield Shield<'_>,
    ) -> Shared<'shield, V, T> {
        let new_raw = new.into_raw();
        let old_raw = self.data.swap(new_raw, ordering);
        unsafe { Shared::from_raw(old_raw) }
    }

    pub fn compare_and_swap<'shield>(
        &self,
        current: Shared<'_, V, T>,
        new: Shared<'_, V, T>,
        order: Ordering,
        _shield: &'shield Shield<'_>,
    ) -> Shared<'shield, V, T> {
        let current_raw = current.into_raw();
        let new_raw = new.into_raw();
        let old_raw = self.data.compare_and_swap(current_raw, new_raw, order);
        unsafe { Shared::from_raw(old_raw) }
    }

    pub fn compare_exchange_weak<'shield>(
        &self,
        current: Shared<'_, V, T>,
        new: Shared<'_, V, T>,
        success: Ordering,
        failure: Ordering,
        _shield: &'shield Shield<'_>,
    ) -> Result<Shared<'shield, V, T>, Shared<'shield, V, T>> {
        let current_raw = current.into_raw();
        let new_raw = new.into_raw();
        let result = self
            .data
            .compare_exchange_weak(current_raw, new_raw, success, failure);

        map_both(result, |raw| unsafe { Shared::from_raw(raw) })
    }
}