1use crate::{
17 cast, checked_cast, overflowing_cast, saturating_cast, wrapping_cast, Cast, CheckedCast,
18 OverflowingCast, Round, SaturatingCast, UnwrappedCast, WrappingCast,
19};
20use core::{mem, num::Wrapping};
21
22macro_rules! bool_to_int {
23 ($Dst:ty) => {
24 impl Cast<$Dst> for bool {
25 #[inline]
26 fn cast(self) -> $Dst {
27 self as $Dst
28 }
29 }
30
31 impl CheckedCast<$Dst> for bool {
32 #[inline]
33 fn checked_cast(self) -> Option<$Dst> {
34 Some(self as $Dst)
35 }
36 }
37
38 impl SaturatingCast<$Dst> for bool {
39 #[inline]
40 fn saturating_cast(self) -> $Dst {
41 self as $Dst
42 }
43 }
44
45 impl WrappingCast<$Dst> for bool {
46 #[inline]
47 fn wrapping_cast(self) -> $Dst {
48 self as $Dst
49 }
50 }
51
52 impl OverflowingCast<$Dst> for bool {
53 #[inline]
54 fn overflowing_cast(self) -> ($Dst, bool) {
55 (self as $Dst, false)
56 }
57 }
58
59 impl UnwrappedCast<$Dst> for bool {
60 #[inline]
61 fn unwrapped_cast(self) -> $Dst {
62 self as $Dst
63 }
64 }
65 };
66}
67
68macro_rules! common {
69 ($Src:ty => $Dst:ty) => {
70 impl Cast<$Dst> for $Src {
71 #[inline]
72 #[cfg_attr(track_caller, track_caller)]
73 fn cast(self) -> $Dst {
74 let (wrapped, overflow) = overflowing_cast(self);
75 debug_assert!(!overflow, "{} overflows", self);
76 let _ = overflow;
77 wrapped
78 }
79 }
80
81 impl CheckedCast<$Dst> for $Src {
82 #[inline]
83 fn checked_cast(self) -> Option<$Dst> {
84 match overflowing_cast(self) {
85 (value, false) => Some(value),
86 (_, true) => None,
87 }
88 }
89 }
90
91 impl SaturatingCast<$Dst> for $Src {
92 #[inline]
93 fn saturating_cast(self) -> $Dst {
94 match overflowing_cast(self) {
95 (value, false) => value,
96 (_, true) => {
97 if self > 0 {
98 <$Dst>::max_value()
99 } else {
100 <$Dst>::min_value()
101 }
102 }
103 }
104 }
105 }
106
107 impl WrappingCast<$Dst> for $Src {
108 #[inline]
109 fn wrapping_cast(self) -> $Dst {
110 overflowing_cast(self).0
111 }
112 }
113
114 impl UnwrappedCast<$Dst> for $Src {
115 #[inline]
116 fn unwrapped_cast(self) -> $Dst {
117 match overflowing_cast(self) {
118 (value, false) => value,
119 (_, true) => panic!("overflow"),
120 }
121 }
122 }
123 };
124}
125
126macro_rules! same_signedness {
127 ($($Src:ty),* => $Dst:ty) => { $(
128 common! { $Src => $Dst }
129
130 impl OverflowingCast<$Dst> for $Src {
131 #[inline]
132 fn overflowing_cast(self) -> ($Dst, bool) {
133 let wrapped = self as $Dst;
134 let overflow = self != wrapped as $Src;
135 (wrapped, overflow)
136 }
137 }
138 )* };
139}
140
141macro_rules! signed_to_unsigned {
142 ($($Src:ty),* => $Dst:ty) => { $(
143 common! { $Src => $Dst }
144
145 impl OverflowingCast<$Dst> for $Src {
146 #[inline]
147 fn overflowing_cast(self) -> ($Dst, bool) {
148 let wrapped = self as $Dst;
149 let overflow = self < 0 || self != wrapped as $Src;
150 (wrapped, overflow)
151 }
152 }
153 )* };
154}
155
156macro_rules! unsigned_to_signed {
157 ($($Src:ty),* => $Dst:ty) => { $(
158 common! { $Src => $Dst }
159
160 impl OverflowingCast<$Dst> for $Src {
161 #[inline]
162 fn overflowing_cast(self) -> ($Dst, bool) {
163 let wrapped = self as $Dst;
164 let overflow = wrapped < 0 || self != wrapped as $Src;
165 (wrapped, overflow)
166 }
167 }
168 )* };
169}
170
171macro_rules! wrapping_int {
172 ($($Src:ty),* => $Dst:ty) => { $(
173 impl Cast<Wrapping<$Dst>> for $Src {
174 #[inline]
175 fn cast(self) -> Wrapping<$Dst> {
176 Wrapping(wrapping_cast(self))
177 }
178 }
179
180 impl CheckedCast<Wrapping<$Dst>> for $Src {
181 #[inline]
182 fn checked_cast(self) -> Option<Wrapping<$Dst>> {
183 Some(cast(self))
184 }
185 }
186
187 impl UnwrappedCast<Wrapping<$Dst>> for $Src {
188 #[inline]
189 fn unwrapped_cast(self) -> Wrapping<$Dst> {
190 cast(self)
191 }
192 }
193 )* };
194}
195
196macro_rules! float_to_int {
197 ($Src:ty, $ViaU:ty, $ViaI:ty => $($Dst:ty)*) => { $(
198 impl Cast<$Dst> for $Src {
199 #[inline]
200 #[cfg_attr(track_caller, track_caller)]
201 fn cast(self) -> $Dst {
202 let (wrapped, overflow) = overflowing_cast(self);
203 debug_assert!(!overflow, "{} overflows", self);
204 let _ = overflow;
205 wrapped
206 }
207 }
208
209 impl CheckedCast<$Dst> for $Src {
210 fn checked_cast(self) -> Option<$Dst> {
211 let f: Float<$ViaU> = self.into();
212 match f.kind {
213 FloatKind::Nan | FloatKind::Infinite | FloatKind::Overflowing(_, true) => None,
214 FloatKind::Overflowing(abs, false) => {
215 if f.neg {
216 let i = abs as $ViaI;
217 if i == <$ViaI>::min_value() {
218 checked_cast(i)
219 } else if i < 0 {
220 None
221 } else {
222 checked_cast(-i)
223 }
224 } else {
225 checked_cast(abs)
226 }
227 }
228 }
229 }
230 }
231
232 impl SaturatingCast<$Dst> for $Src {
233 #[cfg_attr(track_caller, track_caller)]
234 fn saturating_cast(self) -> $Dst {
235 let f: Float<$ViaU> = self.into();
236 let saturated = if f.neg {
237 <$Dst>::min_value()
238 } else {
239 <$Dst>::max_value()
240 };
241 match f.kind {
242 FloatKind::Nan => panic!("NaN"),
243 FloatKind::Infinite | FloatKind::Overflowing(_, true) => saturated,
244 FloatKind::Overflowing(abs, false) => {
245 if f.neg {
246 let i = abs as $ViaI;
247 if i == <$ViaI>::min_value() {
248 saturating_cast(i)
249 } else if i < 0 {
250 saturated
251 } else {
252 saturating_cast(-i)
253 }
254 } else {
255 saturating_cast(abs)
256 }
257 }
258 }
259 }
260 }
261
262 impl WrappingCast<$Dst> for $Src {
263 #[inline]
264 #[cfg_attr(track_caller, track_caller)]
265 fn wrapping_cast(self) -> $Dst {
266 overflowing_cast(self).0
267 }
268 }
269
270 impl OverflowingCast<$Dst> for $Src {
271 #[cfg_attr(track_caller, track_caller)]
272 fn overflowing_cast(self) -> ($Dst, bool) {
273 let f: Float<$ViaU> = self.into();
274 match f.kind {
275 FloatKind::Nan => panic!("NaN"),
276 FloatKind::Infinite => panic!("infinite"),
277 FloatKind::Overflowing(abs, overflow) => {
278 if f.neg {
279 let i = abs as $ViaI;
280 let (wrapped, overflow2) = if i == <$ViaI>::min_value() {
281 overflowing_cast(i)
282 } else if i < 0 {
283 (wrapping_cast::<_, $Dst>(abs).wrapping_neg(), true)
284 } else {
285 overflowing_cast(-i)
286 };
287 (wrapped, overflow | overflow2)
288 } else {
289 let (wrapped, overflow2) = overflowing_cast(abs);
290 (wrapped, overflow | overflow2)
291 }
292 }
293 }
294 }
295 }
296
297 impl UnwrappedCast<$Dst> for $Src {
298 #[inline]
299 fn unwrapped_cast(self) -> $Dst {
300 match overflowing_cast(self) {
301 (val, false) => val,
302 (_, true) => panic!("overflow"),
303 }
304 }
305 }
306
307 impl Cast<Wrapping<$Dst>> for $Src {
308 #[inline]
309 #[cfg_attr(track_caller, track_caller)]
310 fn cast(self) -> Wrapping<$Dst> {
311 Wrapping(wrapping_cast(self))
312 }
313 }
314
315 impl CheckedCast<Wrapping<$Dst>> for $Src {
316 fn checked_cast(self) -> Option<Wrapping<$Dst>> {
317 let f: Float<$ViaU> = self.into();
318 match f.kind {
319 FloatKind::Nan | FloatKind::Infinite => None,
320 FloatKind::Overflowing(abs, _) => {
321 let wrapped = if f.neg {
322 let i = abs as $ViaI;
323 if i == <$ViaI>::min_value() {
324 wrapping_cast(i)
325 } else if i < 0 {
326 wrapping_cast::<_, $Dst>(abs).wrapping_neg()
327 } else {
328 wrapping_cast(-i)
329 }
330 } else {
331 wrapping_cast(abs)
332 };
333 Some(Wrapping(wrapped))
334 }
335 }
336 }
337 }
338
339 impl UnwrappedCast<Wrapping<$Dst>> for $Src {
340 #[inline]
341 fn unwrapped_cast(self) -> Wrapping<$Dst> {
342 cast(self)
343 }
344 }
345 )* };
346}
347
348float_to_int! { f32, u32, i32 => i8 i16 i32 }
349float_to_int! { f32, u64, i64 => i64 }
350float_to_int! { f32, u128, i128 => i128 }
351#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
352float_to_int! { f32, u32, i32 => isize }
353#[cfg(target_pointer_width = "64")]
354float_to_int! { f32, u64, i64 => isize }
355float_to_int! { f32, u32, i32 => u8 u16 u32 }
356float_to_int! { f32, u64, i64 => u64 }
357float_to_int! { f32, u128, i128 => u128 }
358#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
359float_to_int! { f32, u32, i32 => usize }
360#[cfg(target_pointer_width = "64")]
361float_to_int! { f32, u64, i64 => usize }
362
363float_to_int! { f64, u64, i64 => i8 i16 i32 i64 }
364float_to_int! { f64, u128, i128 => i128 }
365float_to_int! { f64, u64, i64 => isize }
366float_to_int! { f64, u64, i64 => u8 u16 u32 u64 }
367float_to_int! { f64, u128, i128 => u128 }
368float_to_int! { f64, u64, i64 => usize }
369
370float_to_int! { Round<f32>, u32, i32 => i8 i16 i32 }
371float_to_int! { Round<f32>, u64, i64 => i64 }
372float_to_int! { Round<f32>, u128, i128 => i128 }
373#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
374float_to_int! { Round<f32>, u32, i32 => isize }
375#[cfg(target_pointer_width = "64")]
376float_to_int! { Round<f32>, u64, i64 => isize }
377float_to_int! { Round<f32>, u32, i32 => u8 u16 u32 }
378float_to_int! { Round<f32>, u64, i64 => u64 }
379float_to_int! { Round<f32>, u128, i128 => u128 }
380#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
381float_to_int! { Round<f32>, u32, i32 => usize }
382#[cfg(target_pointer_width = "64")]
383float_to_int! { Round<f32>, u64, i64 => usize }
384
385float_to_int! { Round<f64>, u64, i64 => i8 i16 i32 i64 }
386float_to_int! { Round<f64>, u128, i128 => i128 }
387float_to_int! { Round<f64>, u64, i64 => isize }
388float_to_int! { Round<f64>, u64, i64 => u8 u16 u32 u64 }
389float_to_int! { Round<f64>, u128, i128 => u128 }
390float_to_int! { Round<f64>, u64, i64 => usize }
391
392macro_rules! signed {
393 ($($Dst:ty),*) => { $(
394 bool_to_int! { $Dst }
395 same_signedness! { i8, i16, i32, i64, i128, isize => $Dst }
396 unsigned_to_signed! { u8, u16, u32, u64, u128, usize => $Dst }
397 wrapping_int! {
398 bool, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize => $Dst
399 }
400 )* };
401}
402
403macro_rules! unsigned {
404 ($($Dst:ty),*) => { $(
405 bool_to_int! { $Dst }
406 signed_to_unsigned! { i8, i16, i32, i64, i128, isize => $Dst }
407 same_signedness! { u8, u16, u32, u64, u128, usize => $Dst }
408 wrapping_int! {
409 bool, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize => $Dst
410 }
411 )* };
412}
413
414signed! { i8, i16, i32, i64, i128, isize }
415unsigned! { u8, u16, u32, u64, u128, usize }
416
417enum FloatKind<Uns> {
418 Nan,
419 Infinite,
420 Overflowing(Uns, bool),
421}
422struct Float<Uns> {
423 neg: bool,
424 kind: FloatKind<Uns>,
425}
426
427macro_rules! from_for_float {
428 ($Src:ty, $Uns:ty, $PREC:expr => $($Dst:ty),*) => { $(
429 impl From<$Src> for Float<$Dst> {
430 fn from(src: $Src) -> Self {
431 const SRC_NBITS: i32 = mem::size_of::<$Src>() as i32 * 8;
432 const DST_NBITS: i32 = mem::size_of::<$Dst>() as i32 * 8;
433 const MANT_NBITS: i32 = $PREC - 1;
434 const EXP_NBITS: i32 = SRC_NBITS - MANT_NBITS - 1;
435 const EXP_BIAS: i32 = (1 << (EXP_NBITS - 1)) - 1;
436 const SIGN_MASK: $Uns = !(!0 >> 1);
437 const MANT_MASK: $Uns = !(!0 << MANT_NBITS);
438 const EXP_MASK: $Uns = !(SIGN_MASK | MANT_MASK);
439
440 let u = src.to_bits();
441 let neg = (u & SIGN_MASK) != 0;
442 let biased_exp = u & EXP_MASK;
443 if biased_exp == EXP_MASK {
444 let kind = if (u & MANT_MASK) == 0 {
445 FloatKind::Infinite
446 } else {
447 FloatKind::Nan
448 };
449 return Float { neg, kind };
450 }
451 let shift = (biased_exp >> MANT_NBITS) as i32 - (EXP_BIAS + MANT_NBITS);
452
453 if shift < -MANT_NBITS {
456 let kind = FloatKind::Overflowing(0, false);
457 return Float { neg, kind };
458 }
459
460 if shift >= DST_NBITS {
462 let kind = FloatKind::Overflowing(0, true);
463 return Float { neg, kind };
464 }
465
466 let mut significand: $Dst = (u & MANT_MASK).into();
467 significand |= 1 << MANT_NBITS;
469 let kind = if shift < 0 {
470 FloatKind::Overflowing(significand >> -shift, false)
471 } else {
472 let wrapped = significand << shift;
473 let overflow = (wrapped >> shift) != significand;
474 FloatKind::Overflowing(wrapped, overflow)
475 };
476 Float { neg, kind }
477 }
478 }
479
480 impl From<Round<$Src>> for Float<$Dst> {
481 fn from(src: Round<$Src>) -> Self {
482 const SRC_NBITS: i32 = mem::size_of::<$Src>() as i32 * 8;
483 const DST_NBITS: i32 = mem::size_of::<$Dst>() as i32 * 8;
484 const MANT_NBITS: i32 = $PREC - 1;
485 const EXP_NBITS: i32 = SRC_NBITS - MANT_NBITS - 1;
486 const EXP_BIAS: i32 = (1 << (EXP_NBITS - 1)) - 1;
487 const SIGN_MASK: $Uns = !(!0 >> 1);
488 const MANT_MASK: $Uns = !(!0 << MANT_NBITS);
489 const EXP_MASK: $Uns = !(SIGN_MASK | MANT_MASK);
490
491 let src = src.0;
492 let u = src.to_bits();
493 let neg = (u & SIGN_MASK) != 0;
494 let biased_exp = u & EXP_MASK;
495 if biased_exp == EXP_MASK {
496 let kind = if (u & MANT_MASK) == 0 {
497 FloatKind::Infinite
498 } else {
499 FloatKind::Nan
500 };
501 return Float { neg, kind };
502 }
503 let shift = (biased_exp >> MANT_NBITS) as i32 - (EXP_BIAS + MANT_NBITS);
504
505 if shift < -MANT_NBITS - 1 {
510 let kind = FloatKind::Overflowing(0, false);
511 return Float { neg, kind };
512 }
513
514 if shift >= DST_NBITS {
516 let kind = FloatKind::Overflowing(0, true);
517 return Float { neg, kind };
518 }
519
520 let mut significand: $Dst = (u & MANT_MASK).into();
521 significand |= 1 << MANT_NBITS;
523 let kind = if shift < 0 {
524 let right = -shift;
525 let round_bit = 1 << (right - 1);
526 if (significand & round_bit) != 0 && (significand & (3 * round_bit - 1)) != 0 {
527 significand += round_bit;
528 }
529 FloatKind::Overflowing(significand >> right, false)
530 } else {
531 let wrapped = significand << shift;
532 let overflow = (wrapped >> shift) != significand;
533 FloatKind::Overflowing(wrapped, overflow)
534 };
535 Float { neg, kind }
536 }
537 }
538 )* };
539}
540
541from_for_float! { f32, u32, 24 => u32, u64, u128 }
542from_for_float! { f64, u64, 53 => u64, u128 }