1 // If `src` can be promoted to `$dst`, then it must be Ok to cast `dst` back to
2 // `$src`
3 macro_rules! promote_and_back {
4     ($($src:ident => $($dst:ident),+);+;) => {
5         mod demoting_to {
6             $(
7                 mod $src {
8                     mod from {
9                         use crate::From;
10 
11                         $(
12                             quickcheck! {
13                                 fn $dst(src: $src) -> bool {
14                                     $src::cast($dst::cast(src)).is_ok()
15                                 }
16                             }
17                          )+
18                     }
19                 }
20              )+
21         }
22     }
23 }
24 
25 #[cfg(target_pointer_width = "32")]
26 promote_and_back! {
27     i8    => f32, f64,     i16, i32, isize, i64, i128                            ;
28     i16   => f32, f64,          i32, isize, i64, i128                            ;
29     i32   =>      f64,                      i64, i128                            ;
30     isize =>      f64,                      i64, i128                            ;
31     i64   =>                                     i128                            ;
32     u8    => f32, f64,     i16, i32, isize, i64, i128, u16, u32, usize, u64, u128;
33     u16   => f32, f64,          i32, isize, i64, i128,      u32, usize, u64, u128;
34     u32   =>      f64,                      i64, i128,                  u64, u128;
35     usize =>      f64,                      i64, i128,                  u64, u128;
36     u64   =>                                     i128,                       u128;
37 }
38 
39 #[cfg(target_pointer_width = "64")]
40 promote_and_back! {
41     i8    => f32, f64,     i16, i32, i64, isize, i128                            ;
42     i16   => f32, f64,          i32, i64, isize, i128                            ;
43     i32   =>      f64,               i64, isize, i128                            ;
44     i64   =>                                     i128                            ;
45     isize =>                                     i128                            ;
46     u8    => f32, f64,     i16, i32, i64, isize, i128, u16, u32, u64, usize, u128;
47     u16   => f32, f64,          i32, i64, isize, i128,      u32, u64, usize, u128;
48     u32   =>      f64,               i64, isize, i128,           u64, usize, u128;
49     u64   =>                                     i128,                       u128;
50     usize =>                                     i128,                       u128;
51 }
52 
53 // If it's Ok to cast `src` to `$dst`, it must also be Ok to cast `dst` back to
54 // `$src`
55 macro_rules! symmetric_cast_between {
56     ($($src:ident => $($dst:ident),+);+;) => {
57         mod symmetric_cast_between {
58             $(
59                 mod $src {
60                     mod and {
61                         use quickcheck::TestResult;
62 
63                         use crate::From;
64 
65                         $(
66                             quickcheck! {
67                                 fn $dst(src: $src) -> TestResult {
68                                     if let Ok(dst) = $dst::cast(src) {
69                                         TestResult::from_bool(
70                                             $src::cast(dst).is_ok())
71                                     } else {
72                                         TestResult::discard()
73                                     }
74                                 }
75                             }
76                          )+
77                     }
78                 }
79              )+
80         }
81     }
82 }
83 
84 #[cfg(target_pointer_width = "32")]
85 symmetric_cast_between! {
86     u8    =>           i8                      ;
87     u16   =>           i8, i16                 ;
88     u32   =>           i8, i16, i32            ;
89     usize =>           i8, i16, i32            ;
90     u64   =>           i8, i16, i32, i64, isize;
91 }
92 
93 #[cfg(target_pointer_width = "64")]
94 symmetric_cast_between! {
95     u8    =>           i8                            ;
96     u16   =>           i8, i16                       ;
97     u32   =>           i8, i16, i32                  ;
98     u64   =>           i8, i16, i32, i64, isize      ;
99     usize =>           i8, i16, i32, i64, isize      ;
100     u128  =>           i8, i16, i32, i64, isize, i128;
101 }
102 
103 macro_rules! from_float {
104     ($($src:ident => $($dst:ident),+);+;) => {
105         $(
106             mod $src {
107                 mod inf {
108                     mod to {
109                         use crate::{Error, From};
110 
111                         $(
112                             #[test]
113                             fn $dst() {
114                                 let _0: $src = 0.;
115                                 let _1: $src = 1.;
116                                 let inf = _1 / _0;
117                                 let neg_inf = -_1 / _0;
118 
119                                 assert_eq!($dst::cast(inf),
120                                            Err(Error::Infinite));
121                                 assert_eq!($dst::cast(neg_inf),
122                                            Err(Error::Infinite));
123                             }
124                          )+
125                     }
126                 }
127 
128                 mod nan {
129                     mod to {
130                         use crate::{Error, From};
131 
132                         $(
133                             #[test]
134                             fn $dst() {
135                                 let _0: $src = 0.;
136                                 let nan = _0 / _0;
137 
138                                 assert_eq!($dst::cast(nan),
139                                            Err(Error::NaN));
140                             }
141                          )+
142                     }
143                 }
144             }
145          )+
146     }
147 }
148 
149 from_float! {
150     f32 => i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize;
151     f64 => i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize;
152 }
153 
154 #[test]
test_fl_conversion()155 fn test_fl_conversion() {
156     use crate::u128;
157     assert_eq!(u128(42.0f32), Ok(42));
158 }
159 
160 #[test]
gh16()161 fn gh16() {
162     assert_eq!(super::u64(-0.01_f64), Ok(0));
163     assert_eq!(super::u64(-0.99_f32), Ok(0));
164 
165     assert_eq!(super::u32(-0.99_f64), Ok(0));
166     assert_eq!(super::u32(-0.01_f32), Ok(0));
167 
168     assert_eq!(super::u64(0.01_f64), Ok(0));
169     assert_eq!(super::u64(0.99_f32), Ok(0));
170 
171     assert_eq!(super::u32(0.99_f64), Ok(0));
172     assert_eq!(super::u32(0.01_f32), Ok(0));
173 }
174 
175 #[test]
gh15()176 fn gh15() {
177     assert_eq!(super::u32(32_f32.exp2()), Err(super::Error::Overflow));
178     assert_eq!(super::u32(32_f64.exp2()), Err(super::Error::Overflow));
179 
180     assert_eq!(super::u64(64_f32.exp2()), Err(super::Error::Overflow));
181     assert_eq!(super::u64(64_f64.exp2()), Err(super::Error::Overflow));
182 
183     assert_eq!(super::u8(8_f32.exp2()), Err(super::Error::Overflow));
184     assert_eq!(super::u8(8_f64.exp2()), Err(super::Error::Overflow));
185 
186     assert_eq!(super::u16(16_f32.exp2()), Err(super::Error::Overflow));
187     assert_eq!(super::u16(16_f64.exp2()), Err(super::Error::Overflow));
188 }
189 
190 #[test]
gh23_lossless_integer_max_min_to_float()191 fn gh23_lossless_integer_max_min_to_float() {
192     // f32::MANTISSA_DIGITS = 24
193     assert_eq!(Ok(u8::MAX), super::u8(255f32));
194     assert_eq!(Ok(u16::MAX), super::u16(65_535f32));
195 
196     // f64::MANTISSA_DIGITS = 53
197     assert_eq!(Ok(u8::MAX), super::u8(255f64));
198     assert_eq!(Ok(u16::MAX), super::u16(65_535f64));
199     assert_eq!(Ok(u32::MAX), super::u32(4_294_967_295f64));
200 
201     // also check negative values (not part of the original bug)
202     assert_eq!(Ok(i8::MIN), super::i8(-128f32));
203     assert_eq!(Ok(i16::MIN), super::i16(-32_768f32));
204 
205     assert_eq!(Ok(i8::MIN), super::i8(-128f64));
206     assert_eq!(Ok(i16::MIN), super::i16(-32_768f64));
207     assert_eq!(Ok(i32::MIN), super::i32(-2_147_483_648f64));
208 }
209