1 | // Copyright © 2019–2021 Trevor Spiteri |
2 | |
3 | // This library is free software: you can redistribute it and/or |
4 | // modify it under the terms of either |
5 | // |
6 | // * the Apache License, Version 2.0 or |
7 | // * the MIT License |
8 | // |
9 | // at your option. |
10 | // |
11 | // You should have recieved copies of the Apache License and the MIT |
12 | // License along with the library. If not, see |
13 | // <https://www.apache.org/licenses/LICENSE-2.0> and |
14 | // <https://opensource.org/licenses/MIT>. |
15 | |
16 | use crate::{ |
17 | cast, checked_cast, overflowing_cast, saturating_cast, wrapping_cast, Cast, CheckedCast, |
18 | OverflowingCast, Round, SaturatingCast, UnwrappedCast, WrappingCast, |
19 | }; |
20 | use core::{mem, num::Wrapping}; |
21 | |
22 | macro_rules! bool_to_int { |
23 | ($Dst:ty) => { |
24 | impl Cast<$Dst> for bool { |
25 | #[inline] |
26 | fn cast(self) -> $Dst { |
27 | self as $Dst |
28 | } |
29 | } |
30 | |
31 | impl CheckedCast<$Dst> for bool { |
32 | #[inline] |
33 | fn checked_cast(self) -> Option<$Dst> { |
34 | Some(self as $Dst) |
35 | } |
36 | } |
37 | |
38 | impl SaturatingCast<$Dst> for bool { |
39 | #[inline] |
40 | fn saturating_cast(self) -> $Dst { |
41 | self as $Dst |
42 | } |
43 | } |
44 | |
45 | impl WrappingCast<$Dst> for bool { |
46 | #[inline] |
47 | fn wrapping_cast(self) -> $Dst { |
48 | self as $Dst |
49 | } |
50 | } |
51 | |
52 | impl OverflowingCast<$Dst> for bool { |
53 | #[inline] |
54 | fn overflowing_cast(self) -> ($Dst, bool) { |
55 | (self as $Dst, false) |
56 | } |
57 | } |
58 | |
59 | impl UnwrappedCast<$Dst> for bool { |
60 | #[inline] |
61 | fn unwrapped_cast(self) -> $Dst { |
62 | self as $Dst |
63 | } |
64 | } |
65 | }; |
66 | } |
67 | |
68 | macro_rules! common { |
69 | ($Src:ty => $Dst:ty) => { |
70 | impl Cast<$Dst> for $Src { |
71 | #[inline] |
72 | #[cfg_attr(track_caller, track_caller)] |
73 | fn cast(self) -> $Dst { |
74 | let (wrapped, overflow) = overflowing_cast(self); |
75 | debug_assert!(!overflow, "{} overflows" , self); |
76 | let _ = overflow; |
77 | wrapped |
78 | } |
79 | } |
80 | |
81 | impl CheckedCast<$Dst> for $Src { |
82 | #[inline] |
83 | fn checked_cast(self) -> Option<$Dst> { |
84 | match overflowing_cast(self) { |
85 | (value, false) => Some(value), |
86 | (_, true) => None, |
87 | } |
88 | } |
89 | } |
90 | |
91 | impl SaturatingCast<$Dst> for $Src { |
92 | #[inline] |
93 | fn saturating_cast(self) -> $Dst { |
94 | match overflowing_cast(self) { |
95 | (value, false) => value, |
96 | (_, true) => { |
97 | if self > 0 { |
98 | <$Dst>::max_value() |
99 | } else { |
100 | <$Dst>::min_value() |
101 | } |
102 | } |
103 | } |
104 | } |
105 | } |
106 | |
107 | impl WrappingCast<$Dst> for $Src { |
108 | #[inline] |
109 | fn wrapping_cast(self) -> $Dst { |
110 | overflowing_cast(self).0 |
111 | } |
112 | } |
113 | |
114 | impl UnwrappedCast<$Dst> for $Src { |
115 | #[inline] |
116 | fn unwrapped_cast(self) -> $Dst { |
117 | match overflowing_cast(self) { |
118 | (value, false) => value, |
119 | (_, true) => panic!("overflow" ), |
120 | } |
121 | } |
122 | } |
123 | }; |
124 | } |
125 | |
126 | macro_rules! same_signedness { |
127 | ($($Src:ty),* => $Dst:ty) => { $( |
128 | common! { $Src => $Dst } |
129 | |
130 | impl OverflowingCast<$Dst> for $Src { |
131 | #[inline] |
132 | fn overflowing_cast(self) -> ($Dst, bool) { |
133 | let wrapped = self as $Dst; |
134 | let overflow = self != wrapped as $Src; |
135 | (wrapped, overflow) |
136 | } |
137 | } |
138 | )* }; |
139 | } |
140 | |
141 | macro_rules! signed_to_unsigned { |
142 | ($($Src:ty),* => $Dst:ty) => { $( |
143 | common! { $Src => $Dst } |
144 | |
145 | impl OverflowingCast<$Dst> for $Src { |
146 | #[inline] |
147 | fn overflowing_cast(self) -> ($Dst, bool) { |
148 | let wrapped = self as $Dst; |
149 | let overflow = self < 0 || self != wrapped as $Src; |
150 | (wrapped, overflow) |
151 | } |
152 | } |
153 | )* }; |
154 | } |
155 | |
156 | macro_rules! unsigned_to_signed { |
157 | ($($Src:ty),* => $Dst:ty) => { $( |
158 | common! { $Src => $Dst } |
159 | |
160 | impl OverflowingCast<$Dst> for $Src { |
161 | #[inline] |
162 | fn overflowing_cast(self) -> ($Dst, bool) { |
163 | let wrapped = self as $Dst; |
164 | let overflow = wrapped < 0 || self != wrapped as $Src; |
165 | (wrapped, overflow) |
166 | } |
167 | } |
168 | )* }; |
169 | } |
170 | |
171 | macro_rules! wrapping_int { |
172 | ($($Src:ty),* => $Dst:ty) => { $( |
173 | impl Cast<Wrapping<$Dst>> for $Src { |
174 | #[inline] |
175 | fn cast(self) -> Wrapping<$Dst> { |
176 | Wrapping(wrapping_cast(self)) |
177 | } |
178 | } |
179 | |
180 | impl CheckedCast<Wrapping<$Dst>> for $Src { |
181 | #[inline] |
182 | fn checked_cast(self) -> Option<Wrapping<$Dst>> { |
183 | Some(cast(self)) |
184 | } |
185 | } |
186 | |
187 | impl UnwrappedCast<Wrapping<$Dst>> for $Src { |
188 | #[inline] |
189 | fn unwrapped_cast(self) -> Wrapping<$Dst> { |
190 | cast(self) |
191 | } |
192 | } |
193 | )* }; |
194 | } |
195 | |
196 | macro_rules! float_to_int { |
197 | ($Src:ty, $ViaU:ty, $ViaI:ty => $($Dst:ty)*) => { $( |
198 | impl Cast<$Dst> for $Src { |
199 | #[inline] |
200 | #[cfg_attr(track_caller, track_caller)] |
201 | fn cast(self) -> $Dst { |
202 | let (wrapped, overflow) = overflowing_cast(self); |
203 | debug_assert!(!overflow, "{} overflows" , self); |
204 | let _ = overflow; |
205 | wrapped |
206 | } |
207 | } |
208 | |
209 | impl CheckedCast<$Dst> for $Src { |
210 | fn checked_cast(self) -> Option<$Dst> { |
211 | let f: Float<$ViaU> = self.into(); |
212 | match f.kind { |
213 | FloatKind::Nan | FloatKind::Infinite | FloatKind::Overflowing(_, true) => None, |
214 | FloatKind::Overflowing(abs, false) => { |
215 | if f.neg { |
216 | let i = abs as $ViaI; |
217 | if i == <$ViaI>::min_value() { |
218 | checked_cast(i) |
219 | } else if i < 0 { |
220 | None |
221 | } else { |
222 | checked_cast(-i) |
223 | } |
224 | } else { |
225 | checked_cast(abs) |
226 | } |
227 | } |
228 | } |
229 | } |
230 | } |
231 | |
232 | impl SaturatingCast<$Dst> for $Src { |
233 | #[cfg_attr(track_caller, track_caller)] |
234 | fn saturating_cast(self) -> $Dst { |
235 | let f: Float<$ViaU> = self.into(); |
236 | let saturated = if f.neg { |
237 | <$Dst>::min_value() |
238 | } else { |
239 | <$Dst>::max_value() |
240 | }; |
241 | match f.kind { |
242 | FloatKind::Nan => panic!("NaN" ), |
243 | FloatKind::Infinite | FloatKind::Overflowing(_, true) => saturated, |
244 | FloatKind::Overflowing(abs, false) => { |
245 | if f.neg { |
246 | let i = abs as $ViaI; |
247 | if i == <$ViaI>::min_value() { |
248 | saturating_cast(i) |
249 | } else if i < 0 { |
250 | saturated |
251 | } else { |
252 | saturating_cast(-i) |
253 | } |
254 | } else { |
255 | saturating_cast(abs) |
256 | } |
257 | } |
258 | } |
259 | } |
260 | } |
261 | |
262 | impl WrappingCast<$Dst> for $Src { |
263 | #[inline] |
264 | #[cfg_attr(track_caller, track_caller)] |
265 | fn wrapping_cast(self) -> $Dst { |
266 | overflowing_cast(self).0 |
267 | } |
268 | } |
269 | |
270 | impl OverflowingCast<$Dst> for $Src { |
271 | #[cfg_attr(track_caller, track_caller)] |
272 | fn overflowing_cast(self) -> ($Dst, bool) { |
273 | let f: Float<$ViaU> = self.into(); |
274 | match f.kind { |
275 | FloatKind::Nan => panic!("NaN" ), |
276 | FloatKind::Infinite => panic!("infinite" ), |
277 | FloatKind::Overflowing(abs, overflow) => { |
278 | if f.neg { |
279 | let i = abs as $ViaI; |
280 | let (wrapped, overflow2) = if i == <$ViaI>::min_value() { |
281 | overflowing_cast(i) |
282 | } else if i < 0 { |
283 | (wrapping_cast::<_, $Dst>(abs).wrapping_neg(), true) |
284 | } else { |
285 | overflowing_cast(-i) |
286 | }; |
287 | (wrapped, overflow | overflow2) |
288 | } else { |
289 | let (wrapped, overflow2) = overflowing_cast(abs); |
290 | (wrapped, overflow | overflow2) |
291 | } |
292 | } |
293 | } |
294 | } |
295 | } |
296 | |
297 | impl UnwrappedCast<$Dst> for $Src { |
298 | #[inline] |
299 | fn unwrapped_cast(self) -> $Dst { |
300 | match overflowing_cast(self) { |
301 | (val, false) => val, |
302 | (_, true) => panic!("overflow" ), |
303 | } |
304 | } |
305 | } |
306 | |
307 | impl Cast<Wrapping<$Dst>> for $Src { |
308 | #[inline] |
309 | #[cfg_attr(track_caller, track_caller)] |
310 | fn cast(self) -> Wrapping<$Dst> { |
311 | Wrapping(wrapping_cast(self)) |
312 | } |
313 | } |
314 | |
315 | impl CheckedCast<Wrapping<$Dst>> for $Src { |
316 | fn checked_cast(self) -> Option<Wrapping<$Dst>> { |
317 | let f: Float<$ViaU> = self.into(); |
318 | match f.kind { |
319 | FloatKind::Nan | FloatKind::Infinite => None, |
320 | FloatKind::Overflowing(abs, _) => { |
321 | let wrapped = if f.neg { |
322 | let i = abs as $ViaI; |
323 | if i == <$ViaI>::min_value() { |
324 | wrapping_cast(i) |
325 | } else if i < 0 { |
326 | wrapping_cast::<_, $Dst>(abs).wrapping_neg() |
327 | } else { |
328 | wrapping_cast(-i) |
329 | } |
330 | } else { |
331 | wrapping_cast(abs) |
332 | }; |
333 | Some(Wrapping(wrapped)) |
334 | } |
335 | } |
336 | } |
337 | } |
338 | |
339 | impl UnwrappedCast<Wrapping<$Dst>> for $Src { |
340 | #[inline] |
341 | fn unwrapped_cast(self) -> Wrapping<$Dst> { |
342 | cast(self) |
343 | } |
344 | } |
345 | )* }; |
346 | } |
347 | |
348 | float_to_int! { f32, u32, i32 => i8 i16 i32 } |
349 | float_to_int! { f32, u64, i64 => i64 } |
350 | float_to_int! { f32, u128, i128 => i128 } |
351 | #[cfg (any(target_pointer_width = "16" , target_pointer_width = "32" ))] |
352 | float_to_int! { f32, u32, i32 => isize } |
353 | #[cfg (target_pointer_width = "64" )] |
354 | float_to_int! { f32, u64, i64 => isize } |
355 | float_to_int! { f32, u32, i32 => u8 u16 u32 } |
356 | float_to_int! { f32, u64, i64 => u64 } |
357 | float_to_int! { f32, u128, i128 => u128 } |
358 | #[cfg (any(target_pointer_width = "16" , target_pointer_width = "32" ))] |
359 | float_to_int! { f32, u32, i32 => usize } |
360 | #[cfg (target_pointer_width = "64" )] |
361 | float_to_int! { f32, u64, i64 => usize } |
362 | |
363 | float_to_int! { f64, u64, i64 => i8 i16 i32 i64 } |
364 | float_to_int! { f64, u128, i128 => i128 } |
365 | float_to_int! { f64, u64, i64 => isize } |
366 | float_to_int! { f64, u64, i64 => u8 u16 u32 u64 } |
367 | float_to_int! { f64, u128, i128 => u128 } |
368 | float_to_int! { f64, u64, i64 => usize } |
369 | |
370 | float_to_int! { Round<f32>, u32, i32 => i8 i16 i32 } |
371 | float_to_int! { Round<f32>, u64, i64 => i64 } |
372 | float_to_int! { Round<f32>, u128, i128 => i128 } |
373 | #[cfg (any(target_pointer_width = "16" , target_pointer_width = "32" ))] |
374 | float_to_int! { Round<f32>, u32, i32 => isize } |
375 | #[cfg (target_pointer_width = "64" )] |
376 | float_to_int! { Round<f32>, u64, i64 => isize } |
377 | float_to_int! { Round<f32>, u32, i32 => u8 u16 u32 } |
378 | float_to_int! { Round<f32>, u64, i64 => u64 } |
379 | float_to_int! { Round<f32>, u128, i128 => u128 } |
380 | #[cfg (any(target_pointer_width = "16" , target_pointer_width = "32" ))] |
381 | float_to_int! { Round<f32>, u32, i32 => usize } |
382 | #[cfg (target_pointer_width = "64" )] |
383 | float_to_int! { Round<f32>, u64, i64 => usize } |
384 | |
385 | float_to_int! { Round<f64>, u64, i64 => i8 i16 i32 i64 } |
386 | float_to_int! { Round<f64>, u128, i128 => i128 } |
387 | float_to_int! { Round<f64>, u64, i64 => isize } |
388 | float_to_int! { Round<f64>, u64, i64 => u8 u16 u32 u64 } |
389 | float_to_int! { Round<f64>, u128, i128 => u128 } |
390 | float_to_int! { Round<f64>, u64, i64 => usize } |
391 | |
392 | macro_rules! signed { |
393 | ($($Dst:ty),*) => { $( |
394 | bool_to_int! { $Dst } |
395 | same_signedness! { i8, i16, i32, i64, i128, isize => $Dst } |
396 | unsigned_to_signed! { u8, u16, u32, u64, u128, usize => $Dst } |
397 | wrapping_int! { |
398 | bool, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize => $Dst |
399 | } |
400 | )* }; |
401 | } |
402 | |
403 | macro_rules! unsigned { |
404 | ($($Dst:ty),*) => { $( |
405 | bool_to_int! { $Dst } |
406 | signed_to_unsigned! { i8, i16, i32, i64, i128, isize => $Dst } |
407 | same_signedness! { u8, u16, u32, u64, u128, usize => $Dst } |
408 | wrapping_int! { |
409 | bool, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize => $Dst |
410 | } |
411 | )* }; |
412 | } |
413 | |
414 | signed! { i8, i16, i32, i64, i128, isize } |
415 | unsigned! { u8, u16, u32, u64, u128, usize } |
416 | |
417 | enum FloatKind<Uns> { |
418 | Nan, |
419 | Infinite, |
420 | Overflowing(Uns, bool), |
421 | } |
422 | struct Float<Uns> { |
423 | neg: bool, |
424 | kind: FloatKind<Uns>, |
425 | } |
426 | |
427 | macro_rules! from_for_float { |
428 | ($Src:ty, $Uns:ty, $PREC:expr => $($Dst:ty),*) => { $( |
429 | impl From<$Src> for Float<$Dst> { |
430 | fn from(src: $Src) -> Self { |
431 | const SRC_NBITS: i32 = mem::size_of::<$Src>() as i32 * 8; |
432 | const DST_NBITS: i32 = mem::size_of::<$Dst>() as i32 * 8; |
433 | const MANT_NBITS: i32 = $PREC - 1; |
434 | const EXP_NBITS: i32 = SRC_NBITS - MANT_NBITS - 1; |
435 | const EXP_BIAS: i32 = (1 << (EXP_NBITS - 1)) - 1; |
436 | const SIGN_MASK: $Uns = !(!0 >> 1); |
437 | const MANT_MASK: $Uns = !(!0 << MANT_NBITS); |
438 | const EXP_MASK: $Uns = !(SIGN_MASK | MANT_MASK); |
439 | |
440 | let u = src.to_bits(); |
441 | let neg = (u & SIGN_MASK) != 0; |
442 | let biased_exp = u & EXP_MASK; |
443 | if biased_exp == EXP_MASK { |
444 | let kind = if (u & MANT_MASK) == 0 { |
445 | FloatKind::Infinite |
446 | } else { |
447 | FloatKind::Nan |
448 | }; |
449 | return Float { neg, kind }; |
450 | } |
451 | let shift = (biased_exp >> MANT_NBITS) as i32 - (EXP_BIAS + MANT_NBITS); |
452 | |
453 | // Check if the magnitude is smaller than one. Do not return |
454 | // early if shift == -MANT_NBITS, as there is implicit one. |
455 | if shift < -MANT_NBITS { |
456 | let kind = FloatKind::Overflowing(0, false); |
457 | return Float { neg, kind }; |
458 | } |
459 | |
460 | // Check if the least significant bit will be in a $Dst. |
461 | if shift >= DST_NBITS { |
462 | let kind = FloatKind::Overflowing(0, true); |
463 | return Float { neg, kind }; |
464 | } |
465 | |
466 | let mut significand: $Dst = (u & MANT_MASK).into(); |
467 | // Add implicit one. |
468 | significand |= 1 << MANT_NBITS; |
469 | let kind = if shift < 0 { |
470 | FloatKind::Overflowing(significand >> -shift, false) |
471 | } else { |
472 | let wrapped = significand << shift; |
473 | let overflow = (wrapped >> shift) != significand; |
474 | FloatKind::Overflowing(wrapped, overflow) |
475 | }; |
476 | Float { neg, kind } |
477 | } |
478 | } |
479 | |
480 | impl From<Round<$Src>> for Float<$Dst> { |
481 | fn from(src: Round<$Src>) -> Self { |
482 | const SRC_NBITS: i32 = mem::size_of::<$Src>() as i32 * 8; |
483 | const DST_NBITS: i32 = mem::size_of::<$Dst>() as i32 * 8; |
484 | const MANT_NBITS: i32 = $PREC - 1; |
485 | const EXP_NBITS: i32 = SRC_NBITS - MANT_NBITS - 1; |
486 | const EXP_BIAS: i32 = (1 << (EXP_NBITS - 1)) - 1; |
487 | const SIGN_MASK: $Uns = !(!0 >> 1); |
488 | const MANT_MASK: $Uns = !(!0 << MANT_NBITS); |
489 | const EXP_MASK: $Uns = !(SIGN_MASK | MANT_MASK); |
490 | |
491 | let src = src.0; |
492 | let u = src.to_bits(); |
493 | let neg = (u & SIGN_MASK) != 0; |
494 | let biased_exp = u & EXP_MASK; |
495 | if biased_exp == EXP_MASK { |
496 | let kind = if (u & MANT_MASK) == 0 { |
497 | FloatKind::Infinite |
498 | } else { |
499 | FloatKind::Nan |
500 | }; |
501 | return Float { neg, kind }; |
502 | } |
503 | let shift = (biased_exp >> MANT_NBITS) as i32 - (EXP_BIAS + MANT_NBITS); |
504 | |
505 | // If shift = -MANT_BITS, then 1 ≤ x < 2. |
506 | // If shift = -MANT_BITS - 1, then 0.5 ≤ x < 1, which can be rounded up. |
507 | // If shift < -MANT_BITS - 1, then x < 0.5, which is rounded down. |
508 | //// || (shift == -MANT_NBITS - 1 && ((u & MANT_MASK) != 0 || x)) |
509 | if shift < -MANT_NBITS - 1 { |
510 | let kind = FloatKind::Overflowing(0, false); |
511 | return Float { neg, kind }; |
512 | } |
513 | |
514 | // Check if the least significant bit will be in a $Dst. |
515 | if shift >= DST_NBITS { |
516 | let kind = FloatKind::Overflowing(0, true); |
517 | return Float { neg, kind }; |
518 | } |
519 | |
520 | let mut significand: $Dst = (u & MANT_MASK).into(); |
521 | // Add implicit one. |
522 | significand |= 1 << MANT_NBITS; |
523 | let kind = if shift < 0 { |
524 | let right = -shift; |
525 | let round_bit = 1 << (right - 1); |
526 | if (significand & round_bit) != 0 && (significand & (3 * round_bit - 1)) != 0 { |
527 | significand += round_bit; |
528 | } |
529 | FloatKind::Overflowing(significand >> right, false) |
530 | } else { |
531 | let wrapped = significand << shift; |
532 | let overflow = (wrapped >> shift) != significand; |
533 | FloatKind::Overflowing(wrapped, overflow) |
534 | }; |
535 | Float { neg, kind } |
536 | } |
537 | } |
538 | )* }; |
539 | } |
540 | |
541 | from_for_float! { f32, u32, 24 => u32, u64, u128 } |
542 | from_for_float! { f64, u64, 53 => u64, u128 } |
543 | |