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
52fn f32_to_i32(x: f32) -> i32 {
53 let bits = x.to_bits();
56 let top = 1u32 << 31;
57 let mask = bits & top;
58
59 (bits ^ (mask - (mask >> 31))) as i32
60}
61
62fn i32_to_f32(bits: i32) -> f32 {
63 let bits = bits as u32;
65 let top = 1u32 << 31;
66 let mask = bits & top;
67
68 f32::from_bits(bits ^ (mask - (mask >> 31)))
69}
70
71fn f64_to_i64(x: f64) -> i64 {
72 let bits = x.to_bits();
75 let top = 1u64 << 63;
76 let mask = bits & top;
77
78 (bits ^ (mask - (mask >> 63))) as i64
79}
80
81fn i64_to_f64(bits: i64) -> f64 {
82 let bits = bits as u64;
84 let top = 1u64 << 63;
85 let mask = bits & top;
86
87 f64::from_bits(bits ^ (mask - (mask >> 63)))
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 #[inline(always)]
110 fn cmp_end(self, other: Self) -> core::cmp::Ordering {
111 $to_int(self).cmp(&$to_int(other))
112 }
113
114 #[inline(always)]
115 fn decrease_toward(self, other: $T) -> Option<$T> {
116 let this = $to_int(self);
117 let other = $to_int(other);
118 if other < this {
119 this.checked_sub(1).map($from_int)
120 } else {
121 None
122 }
123 }
124
125 #[inline(always)]
126 fn increase_toward(self, other: $T) -> Option<$T> {
127 let this = $to_int(self);
128 let other = $to_int(other);
129 if other > this {
130 this.checked_add(1).map($from_int)
131 } else {
132 None
133 }
134 }
135 }
136 )*
137 };
138}
139
140def_float_endpoint!(f32, f32_to_i32, i32_to_f32
141 f64, f64_to_i64, i64_to_f64);
142
143#[cfg(test)]
144proptest::proptest! {
145 #[test]
146 fn test_f32_i32(x: f32, y: f32) {
147 use crate::Endpoint;
148
149 assert_eq!(x.to_bits(), i32_to_f32(f32_to_i32(x)).to_bits());
150 assert_eq!(y.to_bits(), i32_to_f32(f32_to_i32(y)).to_bits());
151
152 if x.partial_cmp(&0.0) == Some(core::cmp::Ordering::Equal) && y.partial_cmp(&0.0) == Some(core::cmp::Ordering::Equal) {
153 assert_eq!(x.signum().partial_cmp(&y.signum()).unwrap(), x.cmp_end(y));
154 } else if let Some(ord) = x.partial_cmp(&y) {
155 assert_eq!(ord, x.cmp_end(y));
156 }
157 }
158
159 #[test]
160 fn test_f64_i64(x: f64, y: f64) {
161 use crate::Endpoint;
162
163 assert_eq!(x.to_bits(), i64_to_f64(f64_to_i64(x)).to_bits());
164 assert_eq!(y.to_bits(), i64_to_f64(f64_to_i64(y)).to_bits());
165
166 if x.partial_cmp(&0.0) == Some(core::cmp::Ordering::Equal) && y.partial_cmp(&0.0) == Some(core::cmp::Ordering::Equal) {
167 assert_eq!(x.signum().partial_cmp(&y.signum()).unwrap(), x.cmp_end(y));
168 } else if let Some(ord) = x.partial_cmp(&y) {
169 assert_eq!(ord, x.cmp_end(y));
170 }
171 }
172}