1#![no_std]
2#![warn(
3 invalid_html_tags,
4 missing_debug_implementations,
5 trivial_casts,
6 unused_lifetimes,
7 unused_import_braces
8)]
9#![deny(missing_docs, unaligned_references)]
10
11use core::cmp::Ordering;
37
38
39#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
43#[repr(transparent)]
44pub struct NumOrd<T>(pub T);
45
46
47macro_rules! common_type_impl_body {
48 ($Lhs:ty, $Rhs:ty, $CommonT:ty, $lhs:expr, $rhs:expr, $op:ident, $less:expr, $greater:expr, $nan:expr) => {{
49 ($lhs as $CommonT).$op(&($rhs as $CommonT))
50 }};
51}
52
53macro_rules! int_float_impl_body {
54 ($IntT:ty, $FloatT:ty, $_UnusedT:ty, $lhs:expr, $rhs:expr, $op:ident, $less:expr, $greater:expr, $nan:expr) => {{
55 let lhs = $lhs;
56 let rhs = $rhs;
57
58 const FLOAT_DENSE_INT_MIN: $IntT =
60 (0 as $IntT).saturating_sub(1) << <$FloatT>::MANTISSA_DIGITS;
61 const FLOAT_DENSE_INT_MAX: $IntT = 1 << <$FloatT>::MANTISSA_DIGITS;
62
63 const INT_MAX_POWER_OF_TWO: $IntT = <$IntT>::MAX ^ (<$IntT>::MAX >> 1);
65 const INT_ONE_ABOVE_MAX_AS_FLOAT: $FloatT = 2.0 * (INT_MAX_POWER_OF_TWO as $FloatT);
66
67 if FLOAT_DENSE_INT_MIN <= lhs && lhs <= FLOAT_DENSE_INT_MAX {
68 (lhs as $FloatT).$op(&rhs)
70 } else if INT_ONE_ABOVE_MAX_AS_FLOAT <= rhs {
71 $less
72 } else if <$IntT>::MIN as $FloatT > rhs {
73 $greater
74 } else if rhs.is_nan() {
75 $nan
76 } else {
77 lhs.$op(&(rhs as $IntT))
81 }
82 }};
83}
84
85macro_rules! int_uint_impl_body {
87 ($IntT:ty, $UintT:ty, $_UnusedT:ty, $lhs:expr, $rhs:expr, $op:ident, $less:expr, $greater:expr, $nan:expr) => {{
88 let lhs = $lhs;
89 let rhs = $rhs;
90
91 if lhs < 0 {
92 $less
93 } else {
94 (lhs as $UintT).$op(&rhs)
95 }
96 }};
97}
98
99macro_rules! apply_impl_body {
100 ($impl_body:ident, $Lhs:ty, $Rhs:ty, $CommonT:ty) => {
101 impl PartialEq<NumOrd<$Rhs>> for NumOrd<$Lhs> {
102 fn eq(&self, other: &NumOrd<$Rhs>) -> bool {
103 $impl_body!($Lhs, $Rhs, $CommonT, self.0, other.0, eq, false, false, false)
104 }
105 }
106
107 impl PartialOrd<NumOrd<$Rhs>> for NumOrd<$Lhs> {
108 fn partial_cmp(&self, other: &NumOrd<$Rhs>) -> Option<Ordering> {
109 $impl_body!(
110 $Lhs,
111 $Rhs,
112 $CommonT,
113 self.0,
114 other.0,
115 partial_cmp,
116 Some(Ordering::Less),
117 Some(Ordering::Greater),
118 None
119 )
120 }
121
122 fn lt(&self, other: &NumOrd<$Rhs>) -> bool {
123 $impl_body!($Lhs, $Rhs, $CommonT, self.0, other.0, lt, true, false, false)
124 }
125
126 fn le(&self, other: &NumOrd<$Rhs>) -> bool {
127 $impl_body!($Lhs, $Rhs, $CommonT, self.0, other.0, le, true, false, false)
128 }
129
130 fn gt(&self, other: &NumOrd<$Rhs>) -> bool {
131 $impl_body!($Lhs, $Rhs, $CommonT, self.0, other.0, gt, false, true, false)
132 }
133
134 fn ge(&self, other: &NumOrd<$Rhs>) -> bool {
135 $impl_body!($Lhs, $Rhs, $CommonT, self.0, other.0, ge, false, true, false)
136 }
137 }
138
139 impl PartialEq<NumOrd<$Lhs>> for NumOrd<$Rhs> {
141 fn eq(&self, other: &NumOrd<$Lhs>) -> bool {
142 other == self
143 }
144 }
145
146 impl PartialOrd<NumOrd<$Lhs>> for NumOrd<$Rhs> {
147 fn partial_cmp(&self, other: &NumOrd<$Lhs>) -> Option<Ordering> {
148 other.partial_cmp(self).map(|o| o.reverse())
149 }
150
151 fn lt(&self, other: &NumOrd<$Lhs>) -> bool {
152 other > self
153 }
154
155 fn le(&self, other: &NumOrd<$Lhs>) -> bool {
156 other >= self
157 }
158
159 fn gt(&self, other: &NumOrd<$Lhs>) -> bool {
160 other < self
161 }
162
163 fn ge(&self, other: &NumOrd<$Lhs>) -> bool {
164 other <= self
165 }
166 }
167 };
168}
169
170apply_impl_body!(int_float_impl_body, i64, f32, ());
171apply_impl_body!(int_float_impl_body, i128, f32, ());
172apply_impl_body!(int_float_impl_body, i64, f64, ());
173apply_impl_body!(int_float_impl_body, i128, f64, ());
174apply_impl_body!(int_float_impl_body, u64, f32, ());
175apply_impl_body!(int_float_impl_body, u128, f32, ());
176apply_impl_body!(int_float_impl_body, u64, f64, ());
177apply_impl_body!(int_float_impl_body, u128, f64, ());
178
179apply_impl_body!(int_uint_impl_body, i8, u128, ());
180apply_impl_body!(int_uint_impl_body, i16, u128, ());
181apply_impl_body!(int_uint_impl_body, i32, u128, ());
182apply_impl_body!(int_uint_impl_body, i64, u128, ());
183apply_impl_body!(int_uint_impl_body, i128, u128, ());
184
185
186macro_rules! impl_common_type {
187 ($($T:ty, $U:ty => $C:ty;)*) => {$(
188 apply_impl_body!(common_type_impl_body, $T, $U, $C);
189 )*}
190}
191
192impl_common_type! {
193 u8, i8 => i16;
195 u8, u16 => u16;
196 u8, i16 => i16;
197 u8, u32 => u32;
198 u8, i32 => i32;
199 u8, u64 => u64;
200 u8, i64 => i64;
201 u8, u128 => u128;
202 u8, i128 => i128;
203 u8, f32 => f32;
204 u8, f64 => f64;
205 i8, u16 => i32;
206 i8, i16 => i16;
207 i8, u32 => i64;
208 i8, i32 => i32;
209 i8, u64 => i128;
210 i8, i64 => i64;
211 i8, i128 => i128;
212 i8, f32 => f32;
213 i8, f64 => f64;
214 u16, i16 => i32;
215 u16, u32 => u32;
216 u16, i32 => i32;
217 u16, u64 => u64;
218 u16, i64 => i64;
219 u16, u128 => u128;
220 u16, i128 => i128;
221 u16, f32 => f32;
222 u16, f64 => f64;
223 i16, u32 => i64;
224 i16, i32 => i32;
225 i16, u64 => i128;
226 i16, i64 => i64;
227 i16, i128 => i128;
228 i16, f32 => f32;
229 i16, f64 => f64;
230 u32, i32 => i64;
231 u32, u64 => u64;
232 u32, i64 => i64;
233 u32, u128 => u128;
234 u32, i128 => i128;
235 u32, f32 => f64;
236 u32, f64 => f64;
237 i32, u64 => i128;
238 i32, i64 => i64;
239 i32, i128 => i128;
240 i32, f32 => f64;
241 i32, f64 => f64;
242 u64, i64 => i128;
243 u64, u128 => u128;
244 u64, i128 => i128;
245 i64, i128 => i128;
246 f32, f64 => f64;
247}