1// If `src` can be promoted to `$dst`, then it must be Ok to cast `dst` back to
2// `$src`
3macro_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")]
26promote_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")]
40promote_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`
55macro_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")]
85symmetric_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")]
94symmetric_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
103macro_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
149from_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]
155fn test_fl_conversion() {
156 use crate::u128;
157 assert_eq!(u128(42.0f32), Ok(42));
158}
159
160#[test]
161fn 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]
176fn 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]
191fn 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