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
126
127
128
129
130
131
132
133
#![no_std]

/// A trait for values that permit contiguous subranges.
///
/// Implementations that override the provided functions must ensure
/// their custom implementations are equivalent to the provided ones.
///
/// Implementations must uphold the following invariants:
/// 1. `ix.in_range(min, max)` if and only if `Ix::range(min, max).any(|x| x == ix)`
/// 2. If `ix.in_range(min, max)`, then `Ix::range(min, max).nth(ix.index(min, max)).unwrap() == ix`
/// 3. `Ix::range(min, max).map(|x| x.index(min, max))` yields equal items to `0..Ix::range_size(min, max)`
/// 4. `Ix::range_size(min, max)` = `Ix::range(min, max).count()`
///
/// # Examples
///
/// ```
/// # use ix_rs::Ix;
/// for (ix, i) in Ix::range(-45i128, 483).zip(0..) {
///     assert_eq!(ix.index(-45, 483), i);
/// } // Property 3
/// ```
/// ```
/// # use ix_rs::Ix;
/// assert!(20i32.in_range(17, 5432));
/// assert_eq!(Ix::range(17i32, 5432).nth(20i32.index(17, 5432)).unwrap(), 20);
/// // Property 2
/// ```
/// ```
/// # use ix_rs::Ix;
/// assert!(!(-30289i16).in_range(-746, 15564));
/// ```
/// ```
/// # use ix_rs::Ix;
/// assert!(0.in_range(-31597i16, 16417));
/// assert_eq!(Ix::range(-31597i16, 16417).nth(0.index(-31597i16, 16417)).unwrap(), 0);
/// // Property 2
/// ```
/// ```
/// # use ix_rs::Ix;
/// assert_eq!(
///     2410117514u32.in_range(2073922791, 3401563124),
///     Ix::range(2073922791u32, 3401563124).any(|x| x == 2410117514)
/// ); // Property 1
/// ```
/// ```
/// # use ix_rs::Ix;
/// assert_eq!(Ix::range(8079u32, 1836091).count(), Ix::range_size(8079u32, 1836091))
/// // Property 4
/// ```
pub trait Ix: PartialOrd + Sized {
    /// An iterator over the elements in a range of the implementing type.
    type Range: Iterator<Item = Self>;
    /// Generate an iterator over a range starting from `min` and stopping at `max`.
    /// The resulting iterator must produce `min` and `max` at some point, each.
    ///
    /// # Panics
    ///
    /// Should panic if `min` is greater than `max`.
    fn range(min: Self, max: Self) -> Self::Range;
    /// Get the position of a value inside a range.
    ///
    /// # Panics
    ///
    /// Should panic if `min` is greater than `max`.
    ///
    /// Should panic if the value is not in the range (as determined by [`in_range`]).
    ///
    /// Panics if the resulting index is not representable as a [`usize`].
    /// The default implementation does this by unwrapping the return value of [`index_checked`].
    ///
    /// [`in_range`]: Ix::in_range
    /// [`index_checked`]: Ix::index_checked
    fn index(self, min: Self, max: Self) -> usize {
        self.index_checked(min, max).expect("index too large")
    }
    /// Get the position of a value inside a range.
    /// Checked version of [`index`].
    ///
    /// # Panics
    ///
    /// Should panic if `min` is greater than `max`.
    ///
    /// Should panic if the value is not in the range (as determined by [`in_range`]).
    ///
    /// [`index`]: Ix::index
    /// [`in_range`]: Ix::in_range
    fn index_checked(self, min: Self, max: Self) -> Option<usize>;
    /// Check if a given value is inside a range.
    ///
    /// # Panics
    ///
    /// Should panic if `min` is greater than `max`.
    fn in_range(self, min: Self, max: Self) -> bool;
    /// Get the length of a range.
    ///
    /// # Panics
    ///
    /// Should panic if `min` is greater than `max`.
    ///
    /// Panics if the resulting index is not representable as a [`usize`].
    /// The default implementation does this by unwrapping the return value of [`range_size_checked`].
    ///
    /// [`range_size_checked`]: Ix::range_size_checked
    fn range_size(min: Self, max: Self) -> usize {
        Ix::range_size_checked(min, max).expect("range size too large")
    }
    /// Get the length of a range.
    /// Checked version of [`range_size`].
    ///
    /// # Panics
    ///
    /// Should panic if `min` is greater than `max`.
    ///
    /// [`range_size`]: Ix::range_size
    fn range_size_checked(min: Self, max: Self) -> Option<usize>;
}

mod macros;
pub mod usize_like;
use macros::impl_ix_numeric;

impl_ix_numeric!(u8);
impl_ix_numeric!(u16);
impl_ix_numeric!(u32);
impl_ix_numeric!(u64);
impl_ix_numeric!(u128);
impl_ix_numeric!(i8);
impl_ix_numeric!(i16);
impl_ix_numeric!(i32);
impl_ix_numeric!(i64);
impl_ix_numeric!(i128);
impl_ix_numeric!(usize);
impl_ix_numeric!(isize);