closed_interval_set/
primitive_endpoint.rs1macro_rules! def_endpoint {
4 ($($T:ty)*) => {
5 $(
6 impl crate::Endpoint for $T {
7 #[inline(always)]
8 fn min_value() -> $T {
9 <$T>::MIN
10 }
11
12 #[inline(always)]
13 fn max_value() -> $T {
14 <$T>::MAX
15 }
16
17 #[inline(always)]
18 fn is_valid(self) -> bool {
19 true
20 }
21
22 #[inline(always)]
23 fn cmp_end(self, other: Self) -> core::cmp::Ordering {
24 core::cmp::Ord::cmp(&self, &other)
25 }
26
27 #[inline(always)]
28 fn decrease_toward(self, other: $T) -> Option<$T> {
29 if other < self {
30 self.checked_sub(1)
31 } else {
32 None
33 }
34 }
35
36 #[inline(always)]
37 fn increase_toward(self, other: $T) -> Option<$T> {
38 if other > self {
39 self.checked_add(1)
40 } else {
41 None
42 }
43 }
44 }
45 )*
46 };
47}
48
49def_endpoint!(i8 i16 i32 i64 i128 isize
50 u8 u16 u32 u64 u128 usize);
51
52#[inline]
53fn f32_to_i32(x: f32) -> i32 {
54 let bits = x.to_bits() as i32;
60 let mask = ((bits >> 31) as u32) >> 1;
61 bits ^ (mask as i32)
62}
63
64#[inline]
65fn i32_to_f32(bits: i32) -> f32 {
66 let mask = ((bits >> 31) as u32) >> 1;
68
69 f32::from_bits((bits as u32) ^ mask)
70}
71
72#[inline]
73fn f64_to_i64(x: f64) -> i64 {
74 let bits = x.to_bits() as i64;
77 let mask = ((bits >> 63) as u64) >> 1;
78
79 bits ^ (mask as i64)
80}
81
82#[inline]
83fn i64_to_f64(bits: i64) -> f64 {
84 let mask = ((bits >> 63) as u64) >> 1;
86
87 f64::from_bits((bits as u64) ^ mask)
88}
89
90macro_rules! def_float_endpoint {
91 ($($T:ty, $to_int:ident, $from_int:ident)*) => {
92 $(
93 impl crate::Endpoint for $T {
94 #[inline(always)]
95 fn min_value() -> $T {
96 <$T>::NEG_INFINITY
97 }
98
99 #[inline(always)]
100 fn max_value() -> $T {
101 <$T>::INFINITY
102 }
103
104 #[inline(always)]
105 fn is_valid(self) -> bool {
106 !self.is_nan()
107 }
108
109 fn cmp_end(self, other: Self) -> core::cmp::Ordering {
110 $to_int(self).cmp(&$to_int(other))
111 }
112
113 fn decrease_toward(self, other: $T) -> Option<$T> {
114 let this = $to_int(self);
115 let other = $to_int(other);
116 if other < this {
117 this.checked_sub(1).map($from_int)
118 } else {
119 None
120 }
121 }
122
123 fn increase_toward(self, other: $T) -> Option<$T> {
124 let this = $to_int(self);
125 let other = $to_int(other);
126 if other > this {
127 this.checked_add(1).map($from_int)
128 } else {
129 None
130 }
131 }
132 }
133 )*
134 };
135}
136
137def_float_endpoint!(f32, f32_to_i32, i32_to_f32
138 f64, f64_to_i64, i64_to_f64);
139
140#[cfg(test)]
141proptest::proptest! {
142 #[test]
143 fn test_f32_i32(x: f32, y: f32) {
144 use crate::Endpoint;
145
146 assert_eq!(x.to_bits(), i32_to_f32(f32_to_i32(x)).to_bits());
147 assert_eq!(y.to_bits(), i32_to_f32(f32_to_i32(y)).to_bits());
148
149 if x.partial_cmp(&0.0) == Some(core::cmp::Ordering::Equal) && y.partial_cmp(&0.0) == Some(core::cmp::Ordering::Equal) {
150 assert_eq!(x.signum().partial_cmp(&y.signum()).unwrap(), x.cmp_end(y));
151 } else if let Some(ord) = x.partial_cmp(&y) {
152 assert_eq!(ord, x.cmp_end(y));
153 }
154 }
155
156 #[test]
157 fn test_f64_i64(x: f64, y: f64) {
158 use crate::Endpoint;
159
160 assert_eq!(x.to_bits(), i64_to_f64(f64_to_i64(x)).to_bits());
161 assert_eq!(y.to_bits(), i64_to_f64(f64_to_i64(y)).to_bits());
162
163 if x.partial_cmp(&0.0) == Some(core::cmp::Ordering::Equal) && y.partial_cmp(&0.0) == Some(core::cmp::Ordering::Equal) {
164 assert_eq!(x.signum().partial_cmp(&y.signum()).unwrap(), x.cmp_end(y));
165 } else if let Some(ord) = x.partial_cmp(&y) {
166 assert_eq!(ord, x.cmp_end(y));
167 }
168 }
169}