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