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
use std::convert::TryFrom;

use crate::trusted_len::TrustedLen;

use super::NativeType;

/// Sealed trait describing the subset of [`NativeType`] (`i32`, `i64`, `u32` and `u64`)
/// that can be used to index a slot of an array.
pub trait Index:
    NativeType
    + std::ops::AddAssign
    + std::ops::Sub<Output = Self>
    + num_traits::One
    + num_traits::Num
    + num_traits::CheckedAdd
    + PartialOrd
    + Ord
{
    /// Convert itself to [`usize`].
    fn to_usize(&self) -> usize;
    /// Convert itself from [`usize`].
    fn from_usize(index: usize) -> Option<Self>;

    /// An iterator from (inclusive) `start` to (exclusive) `end`.
    fn range(start: usize, end: usize) -> Option<IndexRange<Self>> {
        let start = Self::from_usize(start);
        let end = Self::from_usize(end);
        match (start, end) {
            (Some(start), Some(end)) => Some(IndexRange::new(start, end)),
            _ => None,
        }
    }
}

macro_rules! index {
    ($t:ty) => {
        impl Index for $t {
            #[inline]
            fn to_usize(&self) -> usize {
                *self as usize
            }

            #[inline]
            fn from_usize(value: usize) -> Option<Self> {
                Self::try_from(value).ok()
            }
        }
    };
}

index!(i8);
index!(i16);
index!(i32);
index!(i64);
index!(u8);
index!(u16);
index!(u32);
index!(u64);

/// Range of [`Index`], equivalent to `(a..b)`.
/// `Step` is unstable in Rust, which does not allow us to implement (a..b) for [`Index`].
pub struct IndexRange<I: Index> {
    start: I,
    end: I,
}

impl<I: Index> IndexRange<I> {
    /// Returns a new [`IndexRange`].
    pub fn new(start: I, end: I) -> Self {
        assert!(end >= start);
        Self { start, end }
    }
}

impl<I: Index> Iterator for IndexRange<I> {
    type Item = I;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.start == self.end {
            return None;
        }
        let old = self.start;
        self.start += I::one();
        Some(old)
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = (self.end - self.start).to_usize();
        (len, Some(len))
    }
}

/// Safety: a range is always of known length
unsafe impl<I: Index> TrustedLen for IndexRange<I> {}