1#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2pub enum ExactError {
3 Inexact,
4 Overflow,
5}
6
7pub trait ExactFrom<T>: Sized {
8 type Error;
9 fn exact_from(value: T) -> Result<Self, Self::Error>;
10}
11
12pub trait ExactInto<T> {
13 type Error;
14 fn exact_into(self) -> Result<T, Self::Error>;
15}
16
17impl<T, U> ExactInto<U> for T
18where
19 U: ExactFrom<T>,
20{
21 type Error = <U as ExactFrom<T>>::Error;
22 fn exact_into(self) -> Result<U, Self::Error> {
23 <U as ExactFrom<T>>::exact_from(self)
24 }
25}
26
27macro_rules! float_to_int {
28 ($($F:ty),* => $n:literal: $U:ty, $S:ty) => {$(
29 impl ExactFrom<$F> for $U {
30 type Error = ExactError;
31 fn exact_from(value: $F) -> Result<$U, Self::Error> {
32 let min: $F = 0 as $F;
33 let max: $F = (2 as $F).powi($n);
34 if min <= value && value < max {
35 if value.trunc() == value {
36 Ok(value as $U)
37 } else {
38 Err(ExactError::Inexact)
39 }
40 } else {
41 Err(ExactError::Overflow)
42 }
43 }
44 }
45 impl ExactFrom<$F> for $S {
46 type Error = ExactError;
47 fn exact_from(value: $F) -> Result<$S, Self::Error> {
48 let max: $F = (2 as $F).powi($n - 1);
49 let min: $F = -max;
50 if min <= value && value < max {
51 if value.trunc() == value {
52 Ok(value as $S)
53 } else {
54 Err(ExactError::Inexact)
55 }
56 } else {
57 Err(ExactError::Overflow)
58 }
59 }
60 }
61 )*};
62}
63
64float_to_int!(f32, f64 => 8: u8, i8);
65float_to_int!(f32, f64 => 16: u16, i16);
66float_to_int!(f32, f64 => 32: u32, i32);
67float_to_int!(f32, f64 => 64: u64, i64);
68float_to_int!(f32, f64 => 128: u128, i128);
69
70#[cfg(target_pointer_width = "16")]
71float_to_int!(f32, f64 => 16: usize, isize);
72
73#[cfg(target_pointer_width = "32")]
74float_to_int!(f32, f64 => 32: usize, isize);
75
76#[cfg(target_pointer_width = "64")]
77float_to_int!(f32, f64 => 64: usize, isize);
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn f32_to_unsigned() {
85 assert_eq!(0_f32.exact_into(), Ok(0_u8));
86 assert_eq!(0_f32.exact_into(), Ok(0_u16));
87 assert_eq!(0_f32.exact_into(), Ok(0_u32));
88 assert_eq!(0_f32.exact_into(), Ok(0_u64));
89 assert_eq!(0_f32.exact_into(), Ok(0_u128));
90
91 assert_eq!(255_f32.exact_into(), Ok(u8::MAX));
92 assert_eq!(65535_f32.exact_into(), Ok(u16::MAX));
93 assert_eq!(4294967040_f32.exact_into(), Ok(4294967040_u32));
94 assert_eq!(
95 18446742974197923840_f32.exact_into(),
96 Ok(18446742974197923840_u64)
97 );
98 assert_eq!(
99 340282346638528859811704183484516925440_f32.exact_into(),
100 Ok(340282346638528859811704183484516925440_u128)
101 );
102 }
103
104 #[test]
105 fn f32_to_signed() {
106 assert_eq!((-128_f32).exact_into(), Ok(i8::MIN));
107 assert_eq!((-32768_f32).exact_into(), Ok(i16::MIN));
108 assert_eq!((-2147483648_f32).exact_into(), Ok(-2147483648_i32));
109 assert_eq!(
110 (-9223372036854775808_f32).exact_into(),
111 Ok(-9223372036854775808_i64)
112 );
113 assert_eq!(
114 (-170141183460469231731687303715884105728_f32).exact_into(),
115 Ok(-170141183460469231731687303715884105728_i128)
116 );
117
118 assert_eq!(127_f32.exact_into(), Ok(i8::MAX));
119 assert_eq!(32767_f32.exact_into(), Ok(i16::MAX));
120 assert_eq!(2147483520_f32.exact_into(), Ok(2147483520_i32));
121 assert_eq!(
122 9223371487098961920_f32.exact_into(),
123 Ok(9223371487098961920_i64)
124 );
125 assert_eq!(
126 170141173319264429905852091742258462720_f32.exact_into(),
127 Ok(170141173319264429905852091742258462720_i128)
128 );
129 }
130
131 #[test]
132 fn f64_to_unsigned() {
133 assert_eq!(0_f64.exact_into(), Ok(0_u8));
134 assert_eq!(0_f64.exact_into(), Ok(0_u16));
135 assert_eq!(0_f64.exact_into(), Ok(0_u32));
136 assert_eq!(0_f64.exact_into(), Ok(0_u64));
137 assert_eq!(0_f64.exact_into(), Ok(0_u128));
138
139 assert_eq!(255_f64.exact_into(), Ok(u8::MAX));
140 assert_eq!(65535_f64.exact_into(), Ok(u16::MAX));
141 assert_eq!(4294967295_f64.exact_into(), Ok(u32::MAX));
142 assert_eq!(
143 18446744073709549568_f64.exact_into(),
144 Ok(18446744073709549568_u64)
145 );
146 assert_eq!(
147 340282366920938425684442744474606501888_f64.exact_into(),
148 Ok(340282366920938425684442744474606501888_u128)
149 );
150 }
151
152 #[test]
153 fn f64_to_signed() {
154 assert_eq!((-128_f64).exact_into(), Ok(i8::MIN));
155 assert_eq!((-32768_f64).exact_into(), Ok(i16::MIN));
156 assert_eq!((-2147483648_f64).exact_into(), Ok(i32::MIN));
157 assert_eq!(
158 (-9223372036854775808_f64).exact_into(),
159 Ok(-9223372036854775808_i64)
160 );
161 assert_eq!(
162 (-170141183460469231731687303715884105728_f64).exact_into(),
163 Ok(-170141183460469231731687303715884105728_i128)
164 );
165
166 assert_eq!(127_f64.exact_into(), Ok(i8::MAX));
167 assert_eq!(32767_f64.exact_into(), Ok(i16::MAX));
168 assert_eq!(2147483647_f64.exact_into(), Ok(i32::MAX));
169 assert_eq!(
170 9223372036854774784_f64.exact_into(),
171 Ok(9223372036854774784_i64)
172 );
173 assert_eq!(
174 170141183460469212842221372237303250944_f64.exact_into(),
175 Ok(170141183460469212842221372237303250944_i128)
176 );
177 }
178
179 #[test]
180 fn inexact() {
181 assert_eq!(i8::exact_from(3.14_f32), Err(ExactError::Inexact));
182 }
183
184 #[test]
185 fn f32_to_unsigned_overflow() {
186 assert_eq!(u8::exact_from(-1_f32), Err(ExactError::Overflow));
187 assert_eq!(u16::exact_from(-1_f32), Err(ExactError::Overflow));
188 assert_eq!(u32::exact_from(-1_f32), Err(ExactError::Overflow));
189 assert_eq!(u64::exact_from(-1_f32), Err(ExactError::Overflow));
190 assert_eq!(u128::exact_from(-1_f32), Err(ExactError::Overflow));
191
192 assert_eq!(u8::exact_from((2_f32).powi(8)), Err(ExactError::Overflow));
193 assert_eq!(u16::exact_from((2_f32).powi(16)), Err(ExactError::Overflow));
194 assert_eq!(u32::exact_from((2_f32).powi(32)), Err(ExactError::Overflow));
195 assert_eq!(u64::exact_from((2_f32).powi(64)), Err(ExactError::Overflow));
196 assert_eq!(
197 u128::exact_from((2_f32).powi(128)),
198 Err(ExactError::Overflow)
199 );
200 }
201
202 #[test]
203 fn f32_to_signed_overflow() {
204 assert_eq!(
205 i8::exact_from(-(2_f32).powi(8 - 1) - 1_f32),
206 Err(ExactError::Overflow)
207 );
208 assert_eq!(
209 i16::exact_from(-(2_f32).powi(16 - 1) - 1_f32),
210 Err(ExactError::Overflow)
211 );
212 assert_eq!(i32::exact_from(-2147483904_f32), Err(ExactError::Overflow));
213 assert_eq!(
214 i64::exact_from(-9223373136366403584_f32),
215 Err(ExactError::Overflow)
216 );
217 assert_eq!(
218 i128::exact_from(-170141203742878835383357727663135391744_f32),
219 Err(ExactError::Overflow)
220 );
221
222 assert_eq!(
223 i8::exact_from((2_f32).powi(8 - 1)),
224 Err(ExactError::Overflow)
225 );
226 assert_eq!(
227 i16::exact_from((2_f32).powi(16 - 1)),
228 Err(ExactError::Overflow)
229 );
230 assert_eq!(
231 i32::exact_from((2_f32).powi(32 - 1)),
232 Err(ExactError::Overflow)
233 );
234 assert_eq!(
235 i64::exact_from((2_f32).powi(64 - 1)),
236 Err(ExactError::Overflow)
237 );
238 assert_eq!(
239 i128::exact_from((2_f32).powi(128 - 1)),
240 Err(ExactError::Overflow)
241 );
242 }
243
244 #[test]
245 fn f64_to_unsigned_overflow() {
246 assert_eq!(u8::exact_from(-1_f64), Err(ExactError::Overflow));
247 assert_eq!(u16::exact_from(-1_f64), Err(ExactError::Overflow));
248 assert_eq!(u32::exact_from(-1_f64), Err(ExactError::Overflow));
249 assert_eq!(u64::exact_from(-1_f64), Err(ExactError::Overflow));
250 assert_eq!(u128::exact_from(-1_f64), Err(ExactError::Overflow));
251
252 assert_eq!(u8::exact_from((2_f64).powi(8)), Err(ExactError::Overflow));
253 assert_eq!(u16::exact_from((2_f64).powi(16)), Err(ExactError::Overflow));
254 assert_eq!(u32::exact_from((2_f64).powi(32)), Err(ExactError::Overflow));
255 assert_eq!(u64::exact_from((2_f64).powi(64)), Err(ExactError::Overflow));
256 assert_eq!(
257 u128::exact_from((2_f64).powi(128)),
258 Err(ExactError::Overflow)
259 );
260 }
261
262 #[test]
263 fn f64_to_signed_overflow() {
264 assert_eq!(
265 i8::exact_from(-(2_f64).powi(8 - 1) - 1_f64),
266 Err(ExactError::Overflow)
267 );
268 assert_eq!(
269 i16::exact_from(-(2_f64).powi(16 - 1) - 1_f64),
270 Err(ExactError::Overflow)
271 );
272 assert_eq!(
273 i32::exact_from(-(2_f64).powi(32 - 1) - 1_f64),
274 Err(ExactError::Overflow)
275 );
276 assert_eq!(
277 i64::exact_from(-9223372036854777856_f64),
278 Err(ExactError::Overflow)
279 );
280 assert_eq!(
281 i128::exact_from(-170141183460469269510619166673045815296_f64),
282 Err(ExactError::Overflow)
283 );
284
285 assert_eq!(
286 i8::exact_from((2_f64).powi(8 - 1)),
287 Err(ExactError::Overflow)
288 );
289 assert_eq!(
290 i16::exact_from((2_f64).powi(16 - 1)),
291 Err(ExactError::Overflow)
292 );
293 assert_eq!(
294 i32::exact_from((2_f64).powi(32 - 1)),
295 Err(ExactError::Overflow)
296 );
297 assert_eq!(
298 i64::exact_from((2_f64).powi(64 - 1)),
299 Err(ExactError::Overflow)
300 );
301 assert_eq!(
302 i128::exact_from((2_f64).powi(128 - 1)),
303 Err(ExactError::Overflow)
304 );
305 }
306}
307
308pub trait IEEE754 {
309 const BITS: i16;
310 const EXP_BITS: i16;
311 const SIG_BITS: i16;
312 type Unsigned;
313 const EXP_MASK: Self::Unsigned; const SIG_MASK: Self::Unsigned; const EXP_BIAS: Self::Unsigned;
316}
317
318impl IEEE754 for f32 {
319 const BITS: i16 = 32;
320 const EXP_BITS: i16 = 8;
321 const SIG_BITS: i16 = 23;
322 type Unsigned = u32;
323 const EXP_MASK: Self::Unsigned = ((1 << Self::EXP_BITS) - 1) << Self::SIG_BITS;
324 const SIG_MASK: Self::Unsigned = (1 << Self::SIG_BITS) - 1;
325 const EXP_BIAS: Self::Unsigned = (1 << (Self::EXP_BITS - 1)) - 1;
326}
327
328impl IEEE754 for f64 {
329 const BITS: i16 = 64;
330 const EXP_BITS: i16 = 11;
331 const SIG_BITS: i16 = 52;
332 type Unsigned = u64;
333 const EXP_MASK: Self::Unsigned = ((1 << Self::EXP_BITS) - 1) << Self::SIG_BITS;
334 const SIG_MASK: Self::Unsigned = (1 << Self::SIG_BITS) - 1;
335 const EXP_BIAS: Self::Unsigned = (1 << (Self::EXP_BITS - 1)) - 1;
336}