cast/
lib.rs

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