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] |
155 | fn test_fl_conversion() { |
156 | use crate::u128; |
157 | assert_eq!(u128(42.0f32), Ok(42)); |
158 | } |
159 | |
160 | #[test] |
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] |
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] |
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 | |