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
114
115
116
117
118
119
120
121
122
123
124
125
use std::fmt::Debug;
use std::iter::{Step, Sum};
use std::sync::atomic::Ordering;

use atoi::FromRadix10;

pub trait Idx:
    Copy
    + std::ops::Add<Output = Self>
    + std::ops::AddAssign
    + std::ops::Sub<Output = Self>
    + std::ops::Div<Output = Self>
    + std::ops::Mul<Output = Self>
    + Ord
    + Debug
    + Send
    + Sum
    + Sync
    + Sized
    + Step
    + 'static
{
    type Atomic: AtomicIdx<Inner = Self>;

    fn new(idx: usize) -> Self;

    fn zero() -> Self;

    fn index(self) -> usize;

    fn atomic(self) -> Self::Atomic;

    fn parse(bytes: &[u8]) -> (Self, usize);
}

pub trait AtomicIdx: Send + Sync {
    type Inner: Idx<Atomic = Self>;

    fn load(&self, order: Ordering) -> Self::Inner;

    fn fetch_add(&self, val: Self::Inner, order: Ordering) -> Self::Inner;

    fn get_and_increment(&self, order: Ordering) -> Self::Inner;

    fn zero() -> Self;

    fn into_inner(self) -> Self::Inner;
}

macro_rules! impl_idx {
    ($TYPE:ty,$ATOMIC_TYPE:ident) => {
        use std::sync::atomic::$ATOMIC_TYPE;

        impl Idx for $TYPE {
            type Atomic = $ATOMIC_TYPE;

            #[inline]
            fn new(idx: usize) -> Self {
                assert!(idx <= <$TYPE>::MAX as usize);
                idx as $TYPE
            }

            #[inline]
            fn zero() -> Self {
                0
            }

            #[inline]
            fn index(self) -> usize {
                self as usize
            }

            #[inline]
            fn atomic(self) -> $ATOMIC_TYPE {
                <$ATOMIC_TYPE>::new(self)
            }

            #[inline]
            fn parse(bytes: &[u8]) -> (Self, usize) {
                FromRadix10::from_radix_10(bytes)
            }
        }

        impl AtomicIdx for $ATOMIC_TYPE {
            type Inner = $TYPE;

            #[inline]
            fn load(&self, order: Ordering) -> Self::Inner {
                self.load(order)
            }

            #[inline]
            fn fetch_add(&self, val: $TYPE, order: Ordering) -> Self::Inner {
                self.fetch_add(val, order)
            }

            #[inline]
            fn get_and_increment(&self, order: Ordering) -> Self::Inner {
                self.fetch_add(1, order)
            }

            #[inline]
            fn zero() -> Self {
                <$ATOMIC_TYPE>::new(0)
            }

            #[inline]
            fn into_inner(self) -> Self::Inner {
                self.into_inner()
            }
        }
    };
}

impl_idx!(u8, AtomicU8);
impl_idx!(u16, AtomicU16);
impl_idx!(u32, AtomicU32);
impl_idx!(u64, AtomicU64);
impl_idx!(usize, AtomicUsize);

impl_idx!(i8, AtomicI8);
impl_idx!(i16, AtomicI16);
impl_idx!(i32, AtomicI32);
impl_idx!(i64, AtomicI64);
impl_idx!(isize, AtomicIsize);