1 //! Ergonomic, checked cast functions for primitive types
2 //!
3 //! This crate provides one checked cast function for each numeric primitive.
4 //! Use these functions to perform a cast from any other numeric primitive:
5 //!
6 //! ```
7 //! extern crate cast;
8 //!
9 //! use cast::{u8, u16, Error};
10 //!
11 //! # fn main() {
12 //! // Infallible operations, like integer promotion, are equivalent to a normal
13 //! // cast with `as`
14 //! assert_eq!(u16(0u8), 0u16);
15 //!
16 //! // Everything else will return a `Result` depending on the success of the
17 //! // operation
18 //! assert_eq!(u8(0u16), Ok(0u8));
19 //! assert_eq!(u8(256u16), Err(Error::Overflow));
20 //! assert_eq!(u8(-1i8), Err(Error::Underflow));
21 //! assert_eq!(u8(1. / 0.), Err(Error::Infinite));
22 //! assert_eq!(u8(0. / 0.), Err(Error::NaN));
23 //! # }
24 //! ```
25 //!
26 //! There are no namespace problems between these functions, the "primitive
27 //! modules" in `core`/`std` and the built-in primitive types, so all them can
28 //! be in the same scope:
29 //!
30 //! ```
31 //! extern crate cast;
32 //!
33 //! use std::u8;
34 //! use cast::{u8, u16};
35 //!
36 //! # fn main() {
37 //! // `u8` as a type
38 //! let x: u8 = 0;
39 //! // `u8` as a module
40 //! let y = u16(u8::MAX);
41 //! // `u8` as a function
42 //! let z = u8(y).unwrap();
43 //! # }
44 //! ```
45 //!
46 //! The checked cast functionality is also usable with type aliases via the
47 //! `cast` static method:
48 //!
49 //! ```
50 //! extern crate cast;
51 //!
52 //! use std::os::raw::c_ulonglong;
53 //! // NOTE avoid shadowing `std::convert::From` - cf. rust-lang/rfcs#1311
54 //! use cast::From as _0;
55 //!
56 //! # fn main() {
57 //! assert_eq!(c_ulonglong::cast(0u8), 0u64);
58 //! # }
59 //! ```
60 //!
61 //! This crate also provides a `From` trait that can be used, for example,
62 //! to create a generic function that accepts any type that can be infallibly
63 //! casted to `u32`.
64 //!
65 //! ```
66 //! extern crate cast;
67 //!
68 //! fn to_u32<T>(x: T) -> u32
69 //!     // reads as: "where u32 can be casted from T with output u32"
70 //!     where u32: cast::From<T, Output=u32>,
71 //! {
72 //!     cast::u32(x)
73 //! }
74 //!
75 //! # fn main() {
76 //! assert_eq!(to_u32(0u8), 0u32);
77 //! assert_eq!(to_u32(1u16), 1u32);
78 //! assert_eq!(to_u32(2u32), 2u32);
79 //!
80 //! // to_u32(-1i32);  // Compile error
81 //! # }
82 //! ```
83 //!
84 //! ## Minimal Supported Rust Version
85 //!
86 //! This crate is guaranteed to compile on stable Rust 1.13 and up. It *might* compile on older
87 //! versions but that may change in any new patch release.
88 //!
89 //! ## Building without `std`
90 //!
91 //! This crate can be used without Rust's `std` crate by declaring it as
92 //! follows in your `Cargo.toml`:
93 //!
94 //! ``` toml
95 //! cast = { version = "*", default-features = false }
96 //! ```
97 
98 #![deny(missing_docs)]
99 #![deny(warnings)]
100 #![allow(const_err)]
101 #![cfg_attr(not(feature = "std"), no_std)]
102 #![cfg_attr(all(feature = "x128", not(stable_i128)), feature(i128_type, i128))]
103 
104 
105 
106 #[cfg(test)]
107 #[macro_use]
108 extern crate quickcheck;
109 
110 use core::fmt;
111 #[cfg(feature = "std")]
112 use std::error;
113 
114 #[cfg(test)]
115 mod test;
116 
117 /// Cast errors
118 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
119 pub enum Error {
120     /// Infinite value casted to a type that can only represent finite values
121     Infinite,
122     /// NaN value casted to a type that can't represent a NaN value
123     NaN,
124     /// Source value is greater than the maximum value that the destination type
125     /// can hold
126     Overflow,
127     /// Source value is smaller than the minimum value that the destination type
128     /// can hold
129     Underflow,
130 }
131 
132 impl Error {
133     /// A private helper function that implements `description`, because
134     /// `description` is only available when we have `std` enabled.
description_helper(&self) -> &str135     fn description_helper(&self) -> &str {
136         match *self {
137             Error::Infinite => "Cannot store infinite value in finite type",
138             Error::NaN => "Cannot store NaN in type which does not support it",
139             Error::Overflow => "Overflow during numeric conversion",
140             Error::Underflow => "Underflow during numeric conversion",
141         }
142     }
143 }
144 
145 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result146     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147         write!(f, "{}", self.description_helper())
148     }
149 }
150 
151 #[cfg(feature = "std")]
152 impl error::Error for Error {
description(&self) -> &str153     fn description(&self) -> &str {
154         self.description_helper()
155     }
156 }
157 
158 /// The "cast from" operation
159 pub trait From<Src> {
160     /// The result of the cast operation: either `Self` or `Result<Self, Error>`
161     type Output;
162 
163     /// Checked cast from `Src` to `Self`
cast(_: Src) -> Self::Output164     fn cast(_: Src) -> Self::Output;
165 }
166 
167 macro_rules! fns {
168     ($($ty:ident),+) => {
169         $(
170             /// Checked cast function
171             #[inline]
172             pub fn $ty<T>(x: T) -> <$ty as From<T>>::Output
173                 where $ty: From<T>
174             {
175                 <$ty as From<T>>::cast(x)
176             }
177          )+
178     }
179 }
180 
181 fns!(f32, f64, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
182 
183 #[cfg(feature = "x128")]
184 fns!(i128, u128);
185 
186 /// `$dst` can hold any value of `$src`
187 macro_rules! promotion {
188     ($($src:ty => $($dst: ty),+);+;) => {
189         $(
190             $(
191                 impl From<$src> for $dst {
192                     type Output = $dst;
193 
194                     #[inline]
195                     fn cast(src: $src) -> $dst {
196                         src as $dst
197                     }
198                 }
199             )+
200         )+
201     }
202 }
203 
204 /// `$dst` can hold any positive value of `$src`
205 macro_rules! half_promotion {
206     ($($src:ty => $($dst:ty),+);+;) => {
207         $(
208             $(
209                 impl From<$src> for $dst {
210                     type Output = Result<$dst, Error>;
211 
212                     #[inline]
213                     fn cast(src: $src) -> Self::Output {
214                         if src < 0 {
215                             Err(Error::Underflow)
216                         } else {
217                             Ok(src as $dst)
218                         }
219                     }
220                 }
221             )+
222         )+
223     }
224 }
225 
226 /// From an unsigned `$src` to a smaller `$dst`
227 macro_rules! from_unsigned {
228     ($($src:ident => $($dst:ident),+);+;) => {
229         $(
230             $(
231                 impl From<$src> for $dst {
232                     type Output = Result<$dst, Error>;
233 
234                     #[inline]
235                     fn cast(src: $src) -> Self::Output {
236                         use core::$dst;
237 
238                         if src > $dst::MAX as $src {
239                             Err(Error::Overflow)
240                         } else {
241                             Ok(src as $dst)
242                         }
243                     }
244                 }
245             )+
246         )+
247     }
248 }
249 
250 /// From a signed `$src` to a smaller `$dst`
251 macro_rules! from_signed {
252     ($($src:ident => $($dst:ident),+);+;) => {
253         $(
254             $(
255                 impl From<$src> for $dst {
256                     type Output = Result<$dst, Error>;
257 
258                     #[inline]
259                     fn cast(src: $src) -> Self::Output {
260                         use core::$dst;
261 
262                         Err(if src < $dst::MIN as $src {
263                             Error::Underflow
264                         } else if src > $dst::MAX as $src {
265                             Error::Overflow
266                         } else {
267                             return Ok(src as $dst);
268                         })
269                     }
270                 }
271             )+
272         )+
273     }
274 }
275 
276 /// From a float `$src` to an integer `$dst`
277 macro_rules! from_float {
278     ($($src:ident, $usrc:ident => $($dst:ident),+);+;) => {
279         $(
280             $(
281                 impl From<$src> for $dst {
282                     type Output = Result<$dst, Error>;
283 
284                     #[inline]
285                     fn cast(src: $src) -> Self::Output {
286                         use core::{$dst, $src};
287 
288                         Err(if src != src {
289                             Error::NaN
290                         } else if src == $src::INFINITY ||
291                             src == $src::NEG_INFINITY {
292                             Error::Infinite
293                         } else if {
294                             // we subtract 1 ULP (unit of least precision) here because some
295                             // lossy conversions like `u64::MAX as f64` round *up* and we want
296                             // to avoid this evaluating to false in that case
297                             use core::mem::transmute;
298                             let max = unsafe {
299                                 transmute::<_, $src>(transmute::<_, $usrc>($dst::MAX as $src) - 1)
300                             };
301                             src > max
302                         } {
303                             Error::Overflow
304                         } else if $dst::MIN == 0 {
305                             // when casting to unsigned integer, negative values close to 0 but
306                             // larger than 1.0 should be truncated to 0; this behavior matches
307                             // casting from a float to a signed integer
308                             if src <= -1.0 {
309                                 Error::Underflow
310                             } else {
311                                 return Ok(src as $dst);
312                             }
313                         } else if src < $dst::MIN as $src {
314                             Error::Underflow
315                         } else  {
316                             return Ok(src as $dst);
317                         })
318                     }
319                 }
320             )+
321         )+
322     }
323 }
324 
325 /// From a float `$src` to an integer `$dst`, where $dst is large enough to contain
326 /// all values of `$src`. We can't ever overflow here
327 #[cfg(feature = "x128")]
328 macro_rules! from_float_dst {
329     ($($src:ident => $($dst:ident),+);+;) => {
330         $(
331             $(
332                 impl From<$src> for $dst {
333                      type Output = Result<$dst, Error>;
334 
335                     #[inline]
336                     #[allow(unused_comparisons)]
337                     fn cast(src: $src) -> Self::Output {
338                         use core::{$dst, $src};
339 
340                         Err(if src != src {
341                             Error::NaN
342                         } else if src == $src::INFINITY ||
343                             src == $src::NEG_INFINITY {
344                             Error::Infinite
345                         } else if ($dst::MIN == 0) && src <= -1.0 {
346                             Error::Underflow
347                         } else {
348                             return Ok(src as $dst);
349                         })
350                     }
351                 }
352             )+
353         )+
354     }
355 }
356 
357 // PLAY TETRIS! ;-)
358 
359 #[cfg(target_pointer_width = "32")]
360 mod _32 {
361     use crate::{Error, From};
362 
363     // Signed
364     promotion! {
365         i8    => f32, f64, i8, i16, i32, isize, i64;
366         i16   => f32, f64,     i16, i32, isize, i64;
367         i32   => f32, f64,          i32, isize, i64;
368         isize => f32, f64,          i32, isize, i64;
369         i64   => f32, f64,                      i64;
370     }
371 
372     half_promotion! {
373         i8    =>                                     u8, u16, u32, usize, u64;
374         i16   =>                                         u16, u32, usize, u64;
375         i32   =>                                              u32, usize, u64;
376         isize =>                                              u32, usize, u64;
377         i64   =>                                                          u64;
378     }
379 
380     from_signed! {
381 
382         i16   =>           i8,                       u8;
383         i32   =>           i8, i16,                  u8, u16;
384         isize =>           i8, i16,                  u8, u16;
385         i64   =>           i8, i16, i32, isize,      u8, u16, u32, usize;
386     }
387 
388     // Unsigned
389     promotion! {
390         u8    => f32, f64,     i16, i32, isize, i64, u8, u16, u32, usize, u64;
391         u16   => f32, f64,          i32, isize, i64,     u16, u32, usize, u64;
392         u32   => f32, f64,                      i64,          u32, usize, u64;
393         usize => f32, f64,                      i64,          u32, usize, u64;
394         u64   => f32, f64,                                                u64;
395     }
396 
397     from_unsigned! {
398         u8    =>           i8;
399         u16   =>           i8, i16,                  u8;
400         u32   =>           i8, i16, i32, isize,      u8, u16;
401         usize =>           i8, i16, i32, isize,      u8, u16;
402         u64   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize;
403     }
404 
405     // Float
406     promotion! {
407         f32   => f32, f64;
408         f64   =>      f64;
409     }
410 
411     from_float! {
412         f32, u32 =>        i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
413         f64, u64 =>        i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
414     }
415 }
416 
417 #[cfg(target_pointer_width = "64")]
418 mod _64 {
419     use crate::{Error, From};
420 
421     // Signed
422     promotion! {
423         i8    => f32, f64, i8, i16, i32, i64, isize;
424         i16   => f32, f64,     i16, i32, i64, isize;
425         i32   => f32, f64,          i32, i64, isize;
426         i64   => f32, f64,               i64, isize;
427         isize => f32, f64,               i64, isize;
428     }
429 
430     half_promotion! {
431         i8    =>                                     u8, u16, u32, u64, usize;
432         i16   =>                                         u16, u32, u64, usize;
433         i32   =>                                              u32, u64, usize;
434         i64   =>                                                   u64, usize;
435         isize =>                                                   u64, usize;
436     }
437 
438     from_signed! {
439 
440         i16   =>           i8,                       u8;
441         i32   =>           i8, i16,                  u8, u16;
442         i64   =>           i8, i16, i32,             u8, u16, u32;
443         isize =>           i8, i16, i32,             u8, u16, u32;
444     }
445 
446     // Unsigned
447     promotion! {
448         u8    => f32, f64,     i16, i32, i64, isize, u8, u16, u32, u64, usize;
449         u16   => f32, f64,          i32, i64, isize,     u16, u32, u64, usize;
450         u32   => f32, f64,               i64, isize,          u32, u64, usize;
451         u64   => f32, f64,                                         u64, usize;
452         usize => f32, f64,                                         u64, usize;
453     }
454 
455     from_unsigned! {
456         u8    =>           i8;
457         u16   =>           i8, i16,                  u8;
458         u32   =>           i8, i16, i32,             u8, u16;
459         u64   =>           i8, i16, i32, i64, isize, u8, u16, u32;
460         usize =>           i8, i16, i32, i64, isize, u8, u16, u32;
461     }
462 
463     // Float
464     promotion! {
465         f32  => f32, f64;
466         f64  =>      f64;
467     }
468 
469     from_float! {
470         f32, u32  =>       i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
471         f64, u64  =>       i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
472     }
473 }
474 
475 #[cfg(feature = "x128")]
476 mod _x128 {
477     use crate::{Error, From};
478 
479     // Signed
480     promotion! {
481         i8    =>                              i128;
482         i16   =>                              i128;
483         i32   =>                              i128;
484         i64   =>                              i128;
485         isize =>                              i128;
486         i128  => f32, f64,                    i128;
487     }
488 
489     half_promotion! {
490         i8    =>                                                              u128;
491         i16   =>                                                              u128;
492         i32   =>                                                              u128;
493         i64   =>                                                              u128;
494         isize =>                                                              u128;
495         i128  =>                                                              u128;
496     }
497 
498     from_signed! {
499         i128  =>           i8, i16, i32, i64,       isize, u8, u16, u32, u64,       usize;
500     }
501 
502     // Unsigned
503     promotion! {
504         u8    =>                              i128,                           u128;
505         u16   =>                              i128,                           u128;
506         u32   =>                              i128,                           u128;
507         u64   =>                              i128,                           u128;
508         usize =>                              i128,                           u128;
509         u128  =>      f64,                                                    u128;
510     }
511 
512     from_unsigned! {
513         u128 => f32,       i8, i16, i32, i64, i128, isize, u8, u16, u32, u64,       usize;
514     }
515 
516     // Float
517     from_float! {
518         f32, u32  => i128;
519         f64, u64  => i128, u128;
520     }
521 
522     from_float_dst! {
523         f32       =>       u128;
524     }
525 }
526 
527 // The missing piece
528 impl From<f64> for f32 {
529     type Output = Result<f32, Error>;
530 
531     #[inline]
cast(src: f64) -> Self::Output532     fn cast(src: f64) -> Self::Output {
533         use core::{f32, f64};
534 
535         if src != src || src == f64::INFINITY || src == f64::NEG_INFINITY {
536             Ok(src as f32)
537         } else if src < f32::MIN as f64 {
538             Err(Error::Underflow)
539         } else if src > f32::MAX as f64 {
540             Err(Error::Overflow)
541         } else {
542             Ok(src as f32)
543         }
544     }
545 }
546