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