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