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 #[cfg(feature = "std")]
105 extern crate core;
106 
107 #[cfg(test)]
108 #[macro_use]
109 extern crate quickcheck;
110 
111 use core::fmt;
112 #[cfg(feature = "std")]
113 use std::error;
114 
115 #[cfg(test)]
116 mod test;
117 
118 /// Cast errors
119 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
120 pub enum Error {
121     /// Infinite value casted to a type that can only represent finite values
122     Infinite,
123     /// NaN value casted to a type that can't represent a NaN value
124     NaN,
125     /// Source value is greater than the maximum value that the destination type
126     /// can hold
127     Overflow,
128     /// Source value is smaller than the minimum value that the destination type
129     /// can hold
130     Underflow,
131 }
132 
133 impl Error {
134     /// A private helper function that implements `description`, because
135     /// `description` is only available when we have `std` enabled.
description_helper(&self) -> &str136     fn description_helper(&self) -> &str {
137         match *self {
138             Error::Infinite => "Cannot store infinite value in finite type",
139             Error::NaN => "Cannot store NaN in type which does not support it",
140             Error::Overflow => "Overflow during numeric conversion",
141             Error::Underflow => "Underflow during numeric conversion",
142         }
143     }
144 }
145 
146 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result147     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148         write!(f, "{}", self.description_helper())
149     }
150 }
151 
152 #[cfg(feature = "std")]
153 impl error::Error for Error {
description(&self) -> &str154     fn description(&self) -> &str {
155         self.description_helper()
156     }
157 }
158 
159 /// The "cast from" operation
160 pub trait From<Src> {
161     /// The result of the cast operation: either `Self` or `Result<Self, Error>`
162     type Output;
163 
164     /// Checked cast from `Src` to `Self`
cast(Src) -> Self::Output165     fn cast(Src) -> Self::Output;
166 }
167 
168 macro_rules! fns {
169     ($($ty:ident),+) => {
170         $(
171             /// Checked cast function
172             #[inline]
173             pub fn $ty<T>(x: T) -> <$ty as From<T>>::Output
174                 where $ty: From<T>
175             {
176                 <$ty as From<T>>::cast(x)
177             }
178          )+
179     }
180 }
181 
182 fns!(f32, f64, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
183 
184 #[cfg(feature = "x128")]
185 fns!(i128, u128);
186 
187 /// `$dst` can hold any value of `$src`
188 macro_rules! promotion {
189     ($($src:ty => $($dst: ty),+);+;) => {
190         $(
191             $(
192                 impl From<$src> for $dst {
193                     type Output = $dst;
194 
195                     #[inline]
196                     fn cast(src: $src) -> $dst {
197                         src as $dst
198                     }
199                 }
200             )+
201         )+
202     }
203 }
204 
205 /// `$dst` can hold any positive value of `$src`
206 macro_rules! half_promotion {
207     ($($src:ty => $($dst:ty),+);+;) => {
208         $(
209             $(
210                 impl From<$src> for $dst {
211                     type Output = Result<$dst, Error>;
212 
213                     #[inline]
214                     fn cast(src: $src) -> Self::Output {
215                         if src < 0 {
216                             Err(Error::Underflow)
217                         } else {
218                             Ok(src as $dst)
219                         }
220                     }
221                 }
222             )+
223         )+
224     }
225 }
226 
227 /// From an unsigned `$src` to a smaller `$dst`
228 macro_rules! from_unsigned {
229     ($($src:ident => $($dst:ident),+);+;) => {
230         $(
231             $(
232                 impl From<$src> for $dst {
233                     type Output = Result<$dst, Error>;
234 
235                     #[inline]
236                     fn cast(src: $src) -> Self::Output {
237                         use core::$dst;
238 
239                         if src > $dst::MAX as $src {
240                             Err(Error::Overflow)
241                         } else {
242                             Ok(src as $dst)
243                         }
244                     }
245                 }
246             )+
247         )+
248     }
249 }
250 
251 /// From a signed `$src` to a smaller `$dst`
252 macro_rules! from_signed {
253     ($($src:ident => $($dst:ident),+);+;) => {
254         $(
255             $(
256                 impl From<$src> for $dst {
257                     type Output = Result<$dst, Error>;
258 
259                     #[inline]
260                     fn cast(src: $src) -> Self::Output {
261                         use core::$dst;
262 
263                         Err(if src < $dst::MIN as $src {
264                             Error::Underflow
265                         } else if src > $dst::MAX as $src {
266                             Error::Overflow
267                         } else {
268                             return Ok(src as $dst);
269                         })
270                     }
271                 }
272             )+
273         )+
274     }
275 }
276 
277 /// From a float `$src` to an integer `$dst`
278 macro_rules! from_float {
279     ($($src:ident, $usrc:ident => $($dst:ident),+);+;) => {
280         $(
281             $(
282                 impl From<$src> for $dst {
283                     type Output = Result<$dst, Error>;
284 
285                     #[inline]
286                     fn cast(src: $src) -> Self::Output {
287                         use core::{$dst, $src};
288 
289                         Err(if src != src {
290                             Error::NaN
291                         } else if src == $src::INFINITY ||
292                             src == $src::NEG_INFINITY {
293                             Error::Infinite
294                         } else if {
295                             // we subtract 1 ULP (unit of least precision) here because some
296                             // lossy conversions like `u64::MAX as f64` round *up* and we want
297                             // to avoid this evaluating to false in that case
298                             use core::mem::transmute;
299                             let max = unsafe {
300                                 transmute::<_, $src>(transmute::<_, $usrc>($dst::MAX as $src) - 1)
301                             };
302                             src > max
303                         } {
304                             Error::Overflow
305                         } else if $dst::MIN == 0 {
306                             // when casting to unsigned integer, negative values close to 0 but
307                             // larger than 1.0 should be truncated to 0; this behavior matches
308                             // casting from a float to a signed integer
309                             if src <= -1.0 {
310                                 Error::Underflow
311                             } else {
312                                 return Ok(src as $dst);
313                             }
314                         } else if src < $dst::MIN as $src {
315                             Error::Underflow
316                         } else  {
317                             return Ok(src as $dst);
318                         })
319                     }
320                 }
321             )+
322         )+
323     }
324 }
325 
326 /// From a float `$src` to an integer `$dst`, where $dst is large enough to contain
327 /// all values of `$src`. We can't ever overflow here
328 #[cfg(feature = "x128")]
329 macro_rules! from_float_dst {
330     ($($src:ident => $($dst:ident),+);+;) => {
331         $(
332             $(
333                 impl From<$src> for $dst {
334                      type Output = Result<$dst, Error>;
335 
336                     #[inline]
337                     #[allow(unused_comparisons)]
338                     fn cast(src: $src) -> Self::Output {
339                         use core::{$dst, $src};
340 
341                         Err(if src != src {
342                             Error::NaN
343                         } else if src == $src::INFINITY ||
344                             src == $src::NEG_INFINITY {
345                             Error::Infinite
346                         } else if ($dst::MIN == 0) && src <= -1.0 {
347                             Error::Underflow
348                         } else {
349                             return Ok(src as $dst);
350                         })
351                     }
352                 }
353             )+
354         )+
355     }
356 }
357 
358 // PLAY TETRIS! ;-)
359 
360 #[cfg(target_pointer_width = "32")]
361 mod _32 {
362     use {Error, From};
363 
364     // Signed
365     promotion! {
366         i8    => f32, f64, i8, i16, i32, isize, i64;
367         i16   => f32, f64,     i16, i32, isize, i64;
368         i32   => f32, f64,          i32, isize, i64;
369         isize => f32, f64,          i32, isize, i64;
370         i64   => f32, f64,                      i64;
371     }
372 
373     half_promotion! {
374         i8    =>                                     u8, u16, u32, usize, u64;
375         i16   =>                                         u16, u32, usize, u64;
376         i32   =>                                              u32, usize, u64;
377         isize =>                                              u32, usize, u64;
378         i64   =>                                                          u64;
379     }
380 
381     from_signed! {
382 
383         i16   =>           i8,                       u8;
384         i32   =>           i8, i16,                  u8, u16;
385         isize =>           i8, i16,                  u8, u16;
386         i64   =>           i8, i16, i32, isize,      u8, u16, u32, usize;
387     }
388 
389     // Unsigned
390     promotion! {
391         u8    => f32, f64,     i16, i32, isize, i64, u8, u16, u32, usize, u64;
392         u16   => f32, f64,          i32, isize, i64,     u16, u32, usize, u64;
393         u32   => f32, f64,                      i64,          u32, usize, u64;
394         usize => f32, f64,                      i64,          u32, usize, u64;
395         u64   => f32, f64,                                                u64;
396     }
397 
398     from_unsigned! {
399         u8    =>           i8;
400         u16   =>           i8, i16,                  u8;
401         u32   =>           i8, i16, i32, isize,      u8, u16;
402         usize =>           i8, i16, i32, isize,      u8, u16;
403         u64   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize;
404     }
405 
406     // Float
407     promotion! {
408         f32   => f32, f64;
409         f64   =>      f64;
410     }
411 
412     from_float! {
413         f32, u32 =>        i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
414         f64, u64 =>        i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
415     }
416 }
417 
418 #[cfg(target_pointer_width = "64")]
419 mod _64 {
420     use {Error, From};
421 
422     // Signed
423     promotion! {
424         i8    => f32, f64, i8, i16, i32, i64, isize;
425         i16   => f32, f64,     i16, i32, i64, isize;
426         i32   => f32, f64,          i32, i64, isize;
427         i64   => f32, f64,               i64, isize;
428         isize => f32, f64,               i64, isize;
429     }
430 
431     half_promotion! {
432         i8    =>                                     u8, u16, u32, u64, usize;
433         i16   =>                                         u16, u32, u64, usize;
434         i32   =>                                              u32, u64, usize;
435         i64   =>                                                   u64, usize;
436         isize =>                                                   u64, usize;
437     }
438 
439     from_signed! {
440 
441         i16   =>           i8,                       u8;
442         i32   =>           i8, i16,                  u8, u16;
443         i64   =>           i8, i16, i32,             u8, u16, u32;
444         isize =>           i8, i16, i32,             u8, u16, u32;
445     }
446 
447     // Unsigned
448     promotion! {
449         u8    => f32, f64,     i16, i32, i64, isize, u8, u16, u32, u64, usize;
450         u16   => f32, f64,          i32, i64, isize,     u16, u32, u64, usize;
451         u32   => f32, f64,               i64, isize,          u32, u64, usize;
452         u64   => f32, f64,                                         u64, usize;
453         usize => f32, f64,                                         u64, usize;
454     }
455 
456     from_unsigned! {
457         u8    =>           i8;
458         u16   =>           i8, i16,                  u8;
459         u32   =>           i8, i16, i32,             u8, u16;
460         u64   =>           i8, i16, i32, i64, isize, u8, u16, u32;
461         usize =>           i8, i16, i32, i64, isize, u8, u16, u32;
462     }
463 
464     // Float
465     promotion! {
466         f32  => f32, f64;
467         f64  =>      f64;
468     }
469 
470     from_float! {
471         f32, u32  =>       i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
472         f64, u64  =>       i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
473     }
474 }
475 
476 #[cfg(feature = "x128")]
477 mod _x128 {
478     use {Error, From};
479 
480     // Signed
481     promotion! {
482         i8    =>                              i128;
483         i16   =>                              i128;
484         i32   =>                              i128;
485         i64   =>                              i128;
486         isize =>                              i128;
487         i128  => f32, f64,                    i128;
488     }
489 
490     half_promotion! {
491         i8    =>                                                              u128;
492         i16   =>                                                              u128;
493         i32   =>                                                              u128;
494         i64   =>                                                              u128;
495         isize =>                                                              u128;
496         i128  =>                                                              u128;
497     }
498 
499     from_signed! {
500         i128  =>           i8, i16, i32, i64,       isize, u8, u16, u32, u64,       usize;
501     }
502 
503     // Unsigned
504     promotion! {
505         u8    =>                              i128,                           u128;
506         u16   =>                              i128,                           u128;
507         u32   =>                              i128,                           u128;
508         u64   =>                              i128,                           u128;
509         usize =>                              i128,                           u128;
510         u128  =>      f64,                                                    u128;
511     }
512 
513     from_unsigned! {
514         u128 => f32,       i8, i16, i32, i64, i128, isize, u8, u16, u32, u64,       usize;
515     }
516 
517     // Float
518     from_float! {
519         f32, u32  => i128;
520         f64, u64  => i128, u128;
521     }
522 
523     from_float_dst! {
524         f32       =>       u128;
525     }
526 }
527 
528 // The missing piece
529 impl From<f64> for f32 {
530     type Output = Result<f32, Error>;
531 
532     #[inline]
cast(src: f64) -> Self::Output533     fn cast(src: f64) -> Self::Output {
534         use core::{f32, f64};
535 
536         if src != src || src == f64::INFINITY || src == f64::NEG_INFINITY {
537             Ok(src as f32)
538         } else if src < f32::MIN as f64 {
539             Err(Error::Underflow)
540         } else if src > f32::MAX as f64 {
541             Err(Error::Overflow)
542         } else {
543             Ok(src as f32)
544         }
545     }
546 }
547