az/
int.rs

1// Copyright © 2019–2021 Trevor Spiteri
2
3// This library is free software: you can redistribute it and/or
4// modify it under the terms of either
5//
6//   * the Apache License, Version 2.0 or
7//   * the MIT License
8//
9// at your option.
10//
11// You should have recieved copies of the Apache License and the MIT
12// License along with the library. If not, see
13// <https://www.apache.org/licenses/LICENSE-2.0> and
14// <https://opensource.org/licenses/MIT>.
15
16use 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                // Check if the magnitude is smaller than one. Do not return
454                // early if shift == -MANT_NBITS, as there is implicit one.
455                if shift < -MANT_NBITS {
456                    let kind = FloatKind::Overflowing(0, false);
457                    return Float { neg, kind };
458                }
459
460                // Check if the least significant bit will be in a $Dst.
461                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                // Add implicit one.
468                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_BITS, then 1 ≤ x < 2.
506                // If shift = -MANT_BITS - 1, then 0.5 ≤ x < 1, which can be rounded up.
507                // If shift < -MANT_BITS - 1, then x < 0.5, which is rounded down.
508                ////                    || (shift == -MANT_NBITS - 1 && ((u & MANT_MASK) != 0 || x))
509                if shift < -MANT_NBITS - 1 {
510                    let kind = FloatKind::Overflowing(0, false);
511                    return Float { neg, kind };
512                }
513
514                // Check if the least significant bit will be in a $Dst.
515                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                // Add implicit one.
522                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 }