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
use std::mem::{size_of, transmute};
use arith_traits::IMinMax;
use num::BigInt;
use into_iter_ri::IntoIterRi;
use crate::traits::{IRange, IRangeFinite, IRangeFrom, IRangeIntoIterator, IRangeTo, IRangeToInclusive, ITyEq};
mod into_iter_ri;
#[cfg(test)]
mod unit_tests;
macro_rules! impl_range_inclusive {
($($ValueType:ident $UnsignedValueType:ident $WidenedValueType:ident $RangeName:ident,)+) => {
$(
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct $RangeName<const START: $ValueType, const END: $ValueType>;
impl<const START: $ValueType, const END: $ValueType> Drop for $RangeName<START, END> {
#[allow(clippy::let_unit_value)]
fn drop(&mut self) { let _invariants = Self::INVARIANTS; }
}
impl<const START: $ValueType, const END: $ValueType> IntoIterator for $RangeName<START, END> {
type IntoIter = IntoIterRi<$ValueType>;
type Item = $ValueType;
fn into_iter(self) -> IntoIterRi<$ValueType> { IntoIterRi::<$ValueType> { range: START..=END } }
}
impl<const START: $ValueType, const END: $ValueType> const IMinMax<$ValueType> for $RangeName<START, END> {
const MAX: $ValueType = END;
const MIN: $ValueType = START;
}
impl<const START: $ValueType, const END: $ValueType> const IRange for $RangeName<START, END> {
const INVARIANTS: () = assert!(START <= END);
type ValueType = $ValueType;
type WidenedValueType = $WidenedValueType;
fn contains(value: &Self::ValueType) -> bool { *value >= START && *value <= END }
}
#[allow(clippy::useless_transmute)]
impl<const START: $ValueType, const END: $ValueType> const IRangeFinite<$ValueType> for $RangeName<START, END>
where
($ValueType, Self::ValueType): ITyEq,
{
#[allow(clippy::inline_always)]
#[inline(always)]
fn is_empty() -> bool { false }
#[allow(unsafe_code)]
fn len() -> Option<usize> {
let offset = unsafe { transmute::<$ValueType, $UnsignedValueType>($ValueType::MIN) };
let u_start = unsafe { transmute::<$ValueType, $UnsignedValueType>(START) }.wrapping_add(offset);
let u_end = unsafe { transmute::<$ValueType, $UnsignedValueType>(END) }.wrapping_add(offset);
#[allow(clippy::integer_arithmetic, clippy::cast_possible_truncation, clippy::checked_conversions)]
match (size_of::<$UnsignedValueType>() < size_of::<usize>(), u_end - u_start) {
(true, diff) => (diff as usize).checked_add(1),
(false, diff) => match diff < usize::MAX as $UnsignedValueType {
true => (diff as usize).checked_add(1),
false => None,
}
}
}
}
impl<const START: $ValueType, const END: $ValueType> const IRangeFrom for $RangeName<START, END> {
fn start() -> <Self as IRange>::ValueType { START }
}
impl<const START: $ValueType, const END: $ValueType> IRangeIntoIterator for $RangeName<START, END> {
type IntoIter = IntoIterRi<$ValueType>;
fn into_iter() -> <Self as IRangeIntoIterator>::IntoIter {
IntoIterator::into_iter(Self)
}
}
impl<const START: $ValueType, const END: $ValueType> const IRangeTo for $RangeName<START, END> {
fn end() -> <Self as IRange>::ValueType { END }
}
impl<const START: $ValueType, const END: $ValueType> IRangeToInclusive for $RangeName<START, END> {}
)+
}
}
impl_range_inclusive!(
i8 u8 i16 RiI8,
i16 u16 i32 RiI16,
i32 u32 i64 RiI32,
i64 u64 i128 RiI64,
i128 u128 BigInt RiI128,
isize usize BigInt RiIsize,
u8 u8 i16 RiU8,
u16 u16 i32 RiU16,
u32 u32 i64 RiU32,
u64 u64 i128 RiU64,
u128 u128 BigInt RiU128,
usize usize BigInt RiUsize,
);