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                          ;
28     i16   => f32, f64,          i32, isize, i64                          ;
29     i32   => f32, f64,                      i64                          ;
30     isize => f32, f64,                      i64                          ;
31     i64   => f32, f64                                                    ;
32     u8    => f32, f64,     i16, i32, isize, i64,     u16, u32, usize, u64;
33     u16   => f32, f64,          i32, isize, i64,          u32, usize, u64;
34     u32   => f32, f64,                      i64,                      u64;
35     usize => f32, f64,                      i64,                      u64;
36     u64   => f32, f64                                                    ;
37 }
38 
39 #[cfg(target_pointer_width = "64")]
40 promote_and_back! {
41     i8    => f32, f64,     i16, i32, i64, isize                          ;
42     i16   => f32, f64,          i32, i64, isize                          ;
43     i32   => f32, f64,               i64, isize                          ;
44     i64   => f32, f64                                                    ;
45     isize => f32, f64                                                    ;
46     u8    => f32, f64,     i16, i32, i64, isize,     u16, u32, u64, usize;
47     u16   => f32, f64,          i32, i64, isize,          u32, u64, usize;
48     u32   => f32, f64,               i64, isize,               u64, usize;
49     u64   => f32, f64                                                    ;
50     usize => f32, f64                                                    ;
51 }
52 
53 // TODO uncomment this once quickcheck supports Arbitrary for i128/u128
54 // https://github.com/BurntSushi/quickcheck/issues/162
55 /*#[cfg(feature = "x128")]
56 promote_and_back! {
57     i8    =>           i128      ;
58     i16   =>           i128      ;
59     i32   =>           i128      ;
60     isize =>           i128      ;
61     i64   =>           i128      ;
62     i128  => f32, f64            ;
63     u8    =>           i128, u128;
64     u16   =>           i128, u128;
65     u32   =>           i128, u128;
66     usize =>           i128, u128;
67     u64   =>           i128, u128;
68     u128  => f32, f64            ;
69 }*/
70 
71 // If it's Ok to cast `src` to `$dst`, it must also be Ok to cast `dst` back to
72 // `$src`
73 macro_rules! symmetric_cast_between {
74     ($($src:ident => $($dst:ident),+);+;) => {
75         mod symmetric_cast_between {
76             $(
77                 mod $src {
78                     mod and {
79                         use quickcheck::TestResult;
80 
81                         use crate::From;
82 
83                         $(
84                             quickcheck! {
85                                 fn $dst(src: $src) -> TestResult {
86                                     if let Ok(dst) = $dst::cast(src) {
87                                         TestResult::from_bool(
88                                             $src::cast(dst).is_ok())
89                                     } else {
90                                         TestResult::discard()
91                                     }
92                                 }
93                             }
94                          )+
95                     }
96                 }
97              )+
98         }
99     }
100 }
101 
102 #[cfg(target_pointer_width = "32")]
103 symmetric_cast_between! {
104     u8    =>           i8                      ;
105     u16   =>           i8, i16                 ;
106     u32   =>           i8, i16, i32            ;
107     usize =>           i8, i16, i32            ;
108     u64   =>           i8, i16, i32, i64, isize;
109 }
110 
111 #[cfg(target_pointer_width = "64")]
112 symmetric_cast_between! {
113     u8    =>           i8                      ;
114     u16   =>           i8, i16                 ;
115     u32   =>           i8, i16, i32            ;
116     u64   =>           i8, i16, i32, i64, isize;
117     usize =>           i8, i16, i32, i64, isize;
118 }
119 
120 // TODO uncomment this once quickcheck supports Arbitrary for i128/u128
121 // https://github.com/BurntSushi/quickcheck/issues/162
122 /*#[cfg(feature = "x128")]
123 symmetric_cast_between! {
124     u128  => i8, i16, i32, isize, i64, i128;
125 }*/
126 
127 macro_rules! from_float {
128     ($($src:ident => $($dst:ident),+);+;) => {
129         $(
130             mod $src {
131                 mod inf {
132                     mod to {
133                         use crate::{Error, From};
134 
135                         $(
136                             #[test]
137                             fn $dst() {
138                                 let _0: $src = 0.;
139                                 let _1: $src = 1.;
140                                 let inf = _1 / _0;
141                                 let neg_inf = -_1 / _0;
142 
143                                 assert_eq!($dst::cast(inf),
144                                            Err(Error::Infinite));
145                                 assert_eq!($dst::cast(neg_inf),
146                                            Err(Error::Infinite));
147                             }
148                          )+
149                     }
150                 }
151 
152                 mod nan {
153                     mod to {
154                         use crate::{Error, From};
155 
156                         $(
157                             #[test]
158                             fn $dst() {
159                                 let _0: $src = 0.;
160                                 let nan = _0 / _0;
161 
162                                 assert_eq!($dst::cast(nan),
163                                            Err(Error::NaN));
164                             }
165                          )+
166                     }
167                 }
168             }
169          )+
170     }
171 }
172 
173 from_float! {
174     f32 => i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
175     f64 => i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
176 }
177 
178 // TODO uncomment this once quickcheck supports Arbitrary for i128/u128
179 // https://github.com/BurntSushi/quickcheck/issues/162
180 /*#[cfg(feature = "x128")]
181 from_float! {
182     f32 => i128, u128;
183     f64 => i128, u128;
184 }*/
185 
186 #[test]
187 #[cfg(feature = "x128")]
test_fl_conversion()188 fn test_fl_conversion() {
189     use u128;
190     assert_eq!(u128(42.0f32), Ok(42));
191 }
192 
193 #[test]
gh16()194 fn gh16() {
195     assert_eq!(super::u64(-0.01_f64), Ok(0));
196     assert_eq!(super::u64(-0.99_f32), Ok(0));
197 
198     assert_eq!(super::u32(-0.99_f64), Ok(0));
199     assert_eq!(super::u32(-0.01_f32), Ok(0));
200 
201     assert_eq!(super::u64(0.01_f64), Ok(0));
202     assert_eq!(super::u64(0.99_f32), Ok(0));
203 
204     assert_eq!(super::u32(0.99_f64), Ok(0));
205     assert_eq!(super::u32(0.01_f32), Ok(0));
206 }
207 
208 #[test]
gh15()209 fn gh15() {
210     assert_eq!(super::u32(32_f32.exp2()), Err(super::Error::Overflow));
211     assert_eq!(super::u32(32_f64.exp2()), Err(super::Error::Overflow));
212 
213     assert_eq!(super::u64(64_f32.exp2()), Err(super::Error::Overflow));
214     assert_eq!(super::u64(64_f64.exp2()), Err(super::Error::Overflow));
215 
216     assert_eq!(super::u8(8_f32.exp2()), Err(super::Error::Overflow));
217     assert_eq!(super::u8(8_f64.exp2()), Err(super::Error::Overflow));
218 
219     assert_eq!(super::u16(16_f32.exp2()), Err(super::Error::Overflow));
220     assert_eq!(super::u16(16_f64.exp2()), Err(super::Error::Overflow));
221 }
222