From a6b0068c365bd88cf78a3405baeb0827599f53e3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 5 Jun 2017 14:36:41 -0700 Subject: [PATCH] Add `cast` function to primitive integers This commit is a result of the libs team's discussion of #33417 and how it affects integral types. The conclusion was that the motivation for converting integral types, working in a cross-platform code that uses platform-specific integer types, was different enough from the intent of `TryFrom` that it doesn't make sense to unify the paths. As a result this is a proposal for the alternative version of the API which purely works with integral types. An unstable `Cast` trait is added as the implementation detail of this API, and otherwise with this you should be able to call `i32::cast(0u8)` at will. The intention is then to call this in platform-specific contexts like: // Convert from C to Rust let a: c_int = ...; let b: u32 = u32::cast(a)?; // Convert from Rust to C let a: u32 = ...; let b: c_int = ::cast(a)?; Everything here is unstable for now, but the intention is that this will stabilize sooner than `TryFrom`. --- .../src/library-features/num_cast.md | 8 + .../library-features/num_cast_internals.md | 8 + src/libcore/num/cast.rs | 99 ++++++++++ src/libcore/num/mod.rs | 32 ++++ src/libcore/tests/lib.rs | 1 + src/libcore/tests/num/mod.rs | 179 +++++++++--------- src/libstd/error.rs | 6 + src/libstd/lib.rs | 2 + src/libstd/num.rs | 2 + 9 files changed, 247 insertions(+), 90 deletions(-) create mode 100644 src/doc/unstable-book/src/library-features/num_cast.md create mode 100644 src/doc/unstable-book/src/library-features/num_cast_internals.md create mode 100644 src/libcore/num/cast.rs diff --git a/src/doc/unstable-book/src/library-features/num_cast.md b/src/doc/unstable-book/src/library-features/num_cast.md new file mode 100644 index 0000000000000..dad986af8c79d --- /dev/null +++ b/src/doc/unstable-book/src/library-features/num_cast.md @@ -0,0 +1,8 @@ +# `num_cast` + +The tracking issue for this feature is: [#FIXME] + +[#FIXME]: https://github.com/rust-lang/rust/issues/FIXME + +------------------------ + diff --git a/src/doc/unstable-book/src/library-features/num_cast_internals.md b/src/doc/unstable-book/src/library-features/num_cast_internals.md new file mode 100644 index 0000000000000..da0d48affa018 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/num_cast_internals.md @@ -0,0 +1,8 @@ +# `num_cast_internals` + +The tracking issue for this feature is: [#FIXME] + +[#FIXME]: https://github.com/rust-lang/rust/issues/FIXME + +------------------------ + diff --git a/src/libcore/num/cast.rs b/src/libcore/num/cast.rs new file mode 100644 index 0000000000000..c1e17897449d7 --- /dev/null +++ b/src/libcore/num/cast.rs @@ -0,0 +1,99 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use fmt; + +/// Internal trait for APIs like `i32::cast`. +#[unstable(feature = "num_cast_internals", issue = "0")] +pub trait Cast: Sized { + /// Internal implementation detail of this trait. + fn cast(t: T) -> Result; +} + +/// Error type returned from APIs like `i32::cast`, indicates that a cast could +/// not be performed losslessly. +#[unstable(feature = "num_cast", issue = "0")] +#[derive(Debug)] +pub struct CastError(()); + +#[unstable(feature = "num_cast", issue = "0")] +impl fmt::Display for CastError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "failed to losslessly cast integral types".fmt(f) + } +} + +macro_rules! same_sign_cast_int_impl { + ($storage:ty, $target:ty, $($source:ty),*) => {$( + #[unstable(feature = "num_cast", issue = "0")] + impl Cast<$source> for $target { + #[inline] + fn cast(u: $source) -> Result<$target, CastError> { + let min = <$target>::min_value() as $storage; + let max = <$target>::max_value() as $storage; + if u as $storage < min || u as $storage > max { + Err(CastError(())) + } else { + Ok(u as $target) + } + } + } + )*} +} + +same_sign_cast_int_impl!(u128, u8, u8, u16, u32, u64, u128, usize); +same_sign_cast_int_impl!(i128, i8, i8, i16, i32, i64, i128, isize); +same_sign_cast_int_impl!(u128, u16, u8, u16, u32, u64, u128, usize); +same_sign_cast_int_impl!(i128, i16, i8, i16, i32, i64, i128, isize); +same_sign_cast_int_impl!(u128, u32, u8, u16, u32, u64, u128, usize); +same_sign_cast_int_impl!(i128, i32, i8, i16, i32, i64, i128, isize); +same_sign_cast_int_impl!(u128, u64, u8, u16, u32, u64, u128, usize); +same_sign_cast_int_impl!(i128, i64, i8, i16, i32, i64, i128, isize); +same_sign_cast_int_impl!(u128, u128, u8, u16, u32, u64, u128, usize); +same_sign_cast_int_impl!(i128, i128, i8, i16, i32, i64, i128, isize); +same_sign_cast_int_impl!(u128, usize, u8, u16, u32, u64, u128, usize); +same_sign_cast_int_impl!(i128, isize, i8, i16, i32, i64, i128, isize); + +macro_rules! cross_sign_cast_int_impl { + ($unsigned:ty, $($signed:ty),*) => {$( + #[unstable(feature = "num_cast", issue = "0")] + impl Cast<$unsigned> for $signed { + #[inline] + fn cast(u: $unsigned) -> Result<$signed, CastError> { + let max = <$signed>::max_value() as u128; + if u as u128 > max { + Err(CastError(())) + } else { + Ok(u as $signed) + } + } + } + + #[unstable(feature = "num_cast", issue = "0")] + impl Cast<$signed> for $unsigned { + #[inline] + fn cast(u: $signed) -> Result<$unsigned, CastError> { + let max = <$unsigned>::max_value() as u128; + if u < 0 || u as u128 > max { + Err(CastError(())) + } else { + Ok(u as $unsigned) + } + } + } + )*} +} + +cross_sign_cast_int_impl!(u8, i8, i16, i32, i64, i128, isize); +cross_sign_cast_int_impl!(u16, i8, i16, i32, i64, i128, isize); +cross_sign_cast_int_impl!(u32, i8, i16, i32, i64, i128, isize); +cross_sign_cast_int_impl!(u64, i8, i16, i32, i64, i128, isize); +cross_sign_cast_int_impl!(u128, i8, i16, i32, i64, i128, isize); +cross_sign_cast_int_impl!(usize, i8, i16, i32, i64, i128, isize); diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index cbd59ed371377..64c70642645e2 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -88,6 +88,10 @@ impl fmt::UpperHex for Wrapping { } mod wrapping; +mod cast; + +#[unstable(feature = "num_cast", issue = "0")] +pub use self::cast::*; // All these modules are technically private and only exposed for coretests: pub mod flt2dec; @@ -127,6 +131,20 @@ macro_rules! int_impl { !Self::min_value() } + /// Attempt to cast the provided integral type into this type. + /// + /// # Errors + /// + /// This function will return an error if the provided integral type + /// cannot losslessly be represented as this type. + #[unstable(feature = "num_cast", issue = "0")] + #[inline] + pub fn cast(t: T) -> Result + where Self: Cast + { + Cast::cast(t) + } + /// Converts a string slice in a given base to an integer. /// /// Leading and trailing whitespace represent an error. @@ -1290,6 +1308,20 @@ macro_rules! uint_impl { #[inline] pub const fn max_value() -> Self { !0 } + /// Attempt to cast the provided integral type into this type. + /// + /// # Errors + /// + /// This function will return an error if the provided integral type + /// cannot losslessly be represented as this type. + #[unstable(feature = "num_cast", issue = "0")] + #[inline] + pub fn cast(t: T) -> Result + where Self: Cast + { + Cast::cast(t) + } + /// Converts a string slice in a given base to an integer. /// /// Leading and trailing whitespace represent an error. diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 337f8aa31dc46..1922e8eacbbe0 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -28,6 +28,7 @@ #![feature(libc)] #![feature(nonzero)] #![feature(ord_max_min)] +#![feature(num_cast)] #![feature(rand)] #![feature(raw)] #![feature(sip_hash_13)] diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index f233b649a8f3c..e7b325c48508d 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::convert::TryFrom; use core::cmp::PartialEq; use core::fmt::Debug; use core::marker::Copy; @@ -212,58 +211,58 @@ fn test_f32f64() { assert!(nan.is_nan()); } -macro_rules! test_impl_try_from_always_ok { +macro_rules! test_impl_cast_always_ok { ($fn_name:ident, $source:ty, $target: ty) => { #[test] fn $fn_name() { let max = <$source>::max_value(); let min = <$source>::min_value(); let zero: $source = 0; - assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), + assert_eq!(<$target>::cast(max).unwrap(), max as $target); - assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), + assert_eq!(<$target>::cast(min).unwrap(), min as $target); - assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), + assert_eq!(<$target>::cast(zero).unwrap(), zero as $target); } } } -test_impl_try_from_always_ok! { test_try_u8u8, u8, u8 } -test_impl_try_from_always_ok! { test_try_u8u16, u8, u16 } -test_impl_try_from_always_ok! { test_try_u8u32, u8, u32 } -test_impl_try_from_always_ok! { test_try_u8u64, u8, u64 } -test_impl_try_from_always_ok! { test_try_u8i16, u8, i16 } -test_impl_try_from_always_ok! { test_try_u8i32, u8, i32 } -test_impl_try_from_always_ok! { test_try_u8i64, u8, i64 } +test_impl_cast_always_ok! { test_try_u8u8, u8, u8 } +test_impl_cast_always_ok! { test_try_u8u16, u8, u16 } +test_impl_cast_always_ok! { test_try_u8u32, u8, u32 } +test_impl_cast_always_ok! { test_try_u8u64, u8, u64 } +test_impl_cast_always_ok! { test_try_u8i16, u8, i16 } +test_impl_cast_always_ok! { test_try_u8i32, u8, i32 } +test_impl_cast_always_ok! { test_try_u8i64, u8, i64 } -test_impl_try_from_always_ok! { test_try_u16u16, u16, u16 } -test_impl_try_from_always_ok! { test_try_u16u32, u16, u32 } -test_impl_try_from_always_ok! { test_try_u16u64, u16, u64 } -test_impl_try_from_always_ok! { test_try_u16i32, u16, i32 } -test_impl_try_from_always_ok! { test_try_u16i64, u16, i64 } +test_impl_cast_always_ok! { test_try_u16u16, u16, u16 } +test_impl_cast_always_ok! { test_try_u16u32, u16, u32 } +test_impl_cast_always_ok! { test_try_u16u64, u16, u64 } +test_impl_cast_always_ok! { test_try_u16i32, u16, i32 } +test_impl_cast_always_ok! { test_try_u16i64, u16, i64 } -test_impl_try_from_always_ok! { test_try_u32u32, u32, u32 } -test_impl_try_from_always_ok! { test_try_u32u64, u32, u64 } -test_impl_try_from_always_ok! { test_try_u32i64, u32, i64 } +test_impl_cast_always_ok! { test_try_u32u32, u32, u32 } +test_impl_cast_always_ok! { test_try_u32u64, u32, u64 } +test_impl_cast_always_ok! { test_try_u32i64, u32, i64 } -test_impl_try_from_always_ok! { test_try_u64u64, u64, u64 } +test_impl_cast_always_ok! { test_try_u64u64, u64, u64 } -test_impl_try_from_always_ok! { test_try_i8i8, i8, i8 } -test_impl_try_from_always_ok! { test_try_i8i16, i8, i16 } -test_impl_try_from_always_ok! { test_try_i8i32, i8, i32 } -test_impl_try_from_always_ok! { test_try_i8i64, i8, i64 } +test_impl_cast_always_ok! { test_try_i8i8, i8, i8 } +test_impl_cast_always_ok! { test_try_i8i16, i8, i16 } +test_impl_cast_always_ok! { test_try_i8i32, i8, i32 } +test_impl_cast_always_ok! { test_try_i8i64, i8, i64 } -test_impl_try_from_always_ok! { test_try_i16i16, i16, i16 } -test_impl_try_from_always_ok! { test_try_i16i32, i16, i32 } -test_impl_try_from_always_ok! { test_try_i16i64, i16, i64 } +test_impl_cast_always_ok! { test_try_i16i16, i16, i16 } +test_impl_cast_always_ok! { test_try_i16i32, i16, i32 } +test_impl_cast_always_ok! { test_try_i16i64, i16, i64 } -test_impl_try_from_always_ok! { test_try_i32i32, i32, i32 } -test_impl_try_from_always_ok! { test_try_i32i64, i32, i64 } +test_impl_cast_always_ok! { test_try_i32i32, i32, i32 } +test_impl_cast_always_ok! { test_try_i32i64, i32, i64 } -test_impl_try_from_always_ok! { test_try_i64i64, i64, i64 } +test_impl_cast_always_ok! { test_try_i64i64, i64, i64 } -macro_rules! test_impl_try_from_signed_to_unsigned_upper_ok { +macro_rules! test_impl_cast_signed_to_unsigned_upper_ok { ($fn_name:ident, $source:ty, $target:ty) => { #[test] fn $fn_name() { @@ -271,61 +270,61 @@ macro_rules! test_impl_try_from_signed_to_unsigned_upper_ok { let min = <$source>::min_value(); let zero: $source = 0; let neg_one: $source = -1; - assert_eq!(<$target as TryFrom<$source>>::try_from(max).unwrap(), + assert_eq!(<$target>::cast(max).unwrap(), max as $target); - assert!(<$target as TryFrom<$source>>::try_from(min).is_err()); - assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), + assert!(<$target>::cast(min).is_err()); + assert_eq!(<$target>::cast(zero).unwrap(), zero as $target); - assert!(<$target as TryFrom<$source>>::try_from(neg_one).is_err()); + assert!(<$target>::cast(neg_one).is_err()); } } } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u8, i8, u8 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u16, i8, u16 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u32, i8, u32 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i8u64, i8, u64 } +test_impl_cast_signed_to_unsigned_upper_ok! { test_try_i8u8, i8, u8 } +test_impl_cast_signed_to_unsigned_upper_ok! { test_try_i8u16, i8, u16 } +test_impl_cast_signed_to_unsigned_upper_ok! { test_try_i8u32, i8, u32 } +test_impl_cast_signed_to_unsigned_upper_ok! { test_try_i8u64, i8, u64 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u16, i16, u16 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u32, i16, u32 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i16u64, i16, u64 } +test_impl_cast_signed_to_unsigned_upper_ok! { test_try_i16u16, i16, u16 } +test_impl_cast_signed_to_unsigned_upper_ok! { test_try_i16u32, i16, u32 } +test_impl_cast_signed_to_unsigned_upper_ok! { test_try_i16u64, i16, u64 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u32, i32, u32 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32u64, i32, u64 } +test_impl_cast_signed_to_unsigned_upper_ok! { test_try_i32u32, i32, u32 } +test_impl_cast_signed_to_unsigned_upper_ok! { test_try_i32u64, i32, u64 } -test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64u64, i64, u64 } +test_impl_cast_signed_to_unsigned_upper_ok! { test_try_i64u64, i64, u64 } -macro_rules! test_impl_try_from_unsigned_to_signed_upper_err { +macro_rules! test_impl_cast_unsigned_to_signed_upper_err { ($fn_name:ident, $source:ty, $target:ty) => { #[test] fn $fn_name() { let max = <$source>::max_value(); let min = <$source>::min_value(); let zero: $source = 0; - assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); - assert_eq!(<$target as TryFrom<$source>>::try_from(min).unwrap(), + assert!(<$target>::cast(max).is_err()); + assert_eq!(<$target>::cast(min).unwrap(), min as $target); - assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), + assert_eq!(<$target>::cast(zero).unwrap(), zero as $target); } } } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u8i8, u8, i8 } +test_impl_cast_unsigned_to_signed_upper_err! { test_try_u8i8, u8, i8 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16i8, u16, i8 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16i16, u16, i16 } +test_impl_cast_unsigned_to_signed_upper_err! { test_try_u16i8, u16, i8 } +test_impl_cast_unsigned_to_signed_upper_err! { test_try_u16i16, u16, i16 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i8, u32, i8 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i16, u32, i16 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32i32, u32, i32 } +test_impl_cast_unsigned_to_signed_upper_err! { test_try_u32i8, u32, i8 } +test_impl_cast_unsigned_to_signed_upper_err! { test_try_u32i16, u32, i16 } +test_impl_cast_unsigned_to_signed_upper_err! { test_try_u32i32, u32, i32 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i8, u64, i8 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i16, u64, i16 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i32, u64, i32 } -test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64i64, u64, i64 } +test_impl_cast_unsigned_to_signed_upper_err! { test_try_u64i8, u64, i8 } +test_impl_cast_unsigned_to_signed_upper_err! { test_try_u64i16, u64, i16 } +test_impl_cast_unsigned_to_signed_upper_err! { test_try_u64i32, u64, i32 } +test_impl_cast_unsigned_to_signed_upper_err! { test_try_u64i64, u64, i64 } -macro_rules! test_impl_try_from_same_sign_err { +macro_rules! test_impl_cast_same_sign_err { ($fn_name:ident, $source:ty, $target:ty) => { #[test] fn $fn_name() { @@ -334,41 +333,41 @@ macro_rules! test_impl_try_from_same_sign_err { let zero: $source = 0; let t_max = <$target>::max_value(); let t_min = <$target>::min_value(); - assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); + assert!(<$target>::cast(max).is_err()); if min != 0 { - assert!(<$target as TryFrom<$source>>::try_from(min).is_err()); + assert!(<$target>::cast(min).is_err()); } - assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), + assert_eq!(<$target>::cast(zero).unwrap(), zero as $target); - assert_eq!(<$target as TryFrom<$source>>::try_from(t_max as $source) + assert_eq!(<$target>::cast(t_max as $source) .unwrap(), t_max as $target); - assert_eq!(<$target as TryFrom<$source>>::try_from(t_min as $source) + assert_eq!(<$target>::cast(t_min as $source) .unwrap(), t_min as $target); } } } -test_impl_try_from_same_sign_err! { test_try_u16u8, u16, u8 } +test_impl_cast_same_sign_err! { test_try_u16u8, u16, u8 } -test_impl_try_from_same_sign_err! { test_try_u32u8, u32, u8 } -test_impl_try_from_same_sign_err! { test_try_u32u16, u32, u16 } +test_impl_cast_same_sign_err! { test_try_u32u8, u32, u8 } +test_impl_cast_same_sign_err! { test_try_u32u16, u32, u16 } -test_impl_try_from_same_sign_err! { test_try_u64u8, u64, u8 } -test_impl_try_from_same_sign_err! { test_try_u64u16, u64, u16 } -test_impl_try_from_same_sign_err! { test_try_u64u32, u64, u32 } +test_impl_cast_same_sign_err! { test_try_u64u8, u64, u8 } +test_impl_cast_same_sign_err! { test_try_u64u16, u64, u16 } +test_impl_cast_same_sign_err! { test_try_u64u32, u64, u32 } -test_impl_try_from_same_sign_err! { test_try_i16i8, i16, i8 } +test_impl_cast_same_sign_err! { test_try_i16i8, i16, i8 } -test_impl_try_from_same_sign_err! { test_try_i32i8, i32, i8 } -test_impl_try_from_same_sign_err! { test_try_i32i16, i32, i16 } +test_impl_cast_same_sign_err! { test_try_i32i8, i32, i8 } +test_impl_cast_same_sign_err! { test_try_i32i16, i32, i16 } -test_impl_try_from_same_sign_err! { test_try_i64i8, i64, i8 } -test_impl_try_from_same_sign_err! { test_try_i64i16, i64, i16 } -test_impl_try_from_same_sign_err! { test_try_i64i32, i64, i32 } +test_impl_cast_same_sign_err! { test_try_i64i8, i64, i8 } +test_impl_cast_same_sign_err! { test_try_i64i16, i64, i16 } +test_impl_cast_same_sign_err! { test_try_i64i32, i64, i32 } -macro_rules! test_impl_try_from_signed_to_unsigned_err { +macro_rules! test_impl_cast_signed_to_unsigned_err { ($fn_name:ident, $source:ty, $target:ty) => { #[test] fn $fn_name() { @@ -377,28 +376,28 @@ macro_rules! test_impl_try_from_signed_to_unsigned_err { let zero: $source = 0; let t_max = <$target>::max_value(); let t_min = <$target>::min_value(); - assert!(<$target as TryFrom<$source>>::try_from(max).is_err()); - assert!(<$target as TryFrom<$source>>::try_from(min).is_err()); - assert_eq!(<$target as TryFrom<$source>>::try_from(zero).unwrap(), + assert!(<$target>::cast(max).is_err()); + assert!(<$target>::cast(min).is_err()); + assert_eq!(<$target>::cast(zero).unwrap(), zero as $target); - assert_eq!(<$target as TryFrom<$source>>::try_from(t_max as $source) + assert_eq!(<$target>::cast(t_max as $source) .unwrap(), t_max as $target); - assert_eq!(<$target as TryFrom<$source>>::try_from(t_min as $source) + assert_eq!(<$target>::cast(t_min as $source) .unwrap(), t_min as $target); } } } -test_impl_try_from_signed_to_unsigned_err! { test_try_i16u8, i16, u8 } +test_impl_cast_signed_to_unsigned_err! { test_try_i16u8, i16, u8 } -test_impl_try_from_signed_to_unsigned_err! { test_try_i32u8, i32, u8 } -test_impl_try_from_signed_to_unsigned_err! { test_try_i32u16, i32, u16 } +test_impl_cast_signed_to_unsigned_err! { test_try_i32u8, i32, u8 } +test_impl_cast_signed_to_unsigned_err! { test_try_i32u16, i32, u16 } -test_impl_try_from_signed_to_unsigned_err! { test_try_i64u8, i64, u8 } -test_impl_try_from_signed_to_unsigned_err! { test_try_i64u16, i64, u16 } -test_impl_try_from_signed_to_unsigned_err! { test_try_i64u32, i64, u32 } +test_impl_cast_signed_to_unsigned_err! { test_try_i64u8, i64, u8 } +test_impl_cast_signed_to_unsigned_err! { test_try_i64u16, i64, u16 } +test_impl_cast_signed_to_unsigned_err! { test_try_i64u32, i64, u32 } macro_rules! test_float { ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => { mod $modname { diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 4b340f70fbc74..fa29587484c17 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -347,6 +347,12 @@ impl Error for char::ParseCharError { } } +#[unstable(feature = "num_cast", issue = "0")] +impl Error for num::CastError { + fn description(&self) -> &str { + "failed to losslessly cast integral types" + } +} // copied from any.rs impl Error + 'static { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index bafe23e80a030..c7d654448ca85 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -284,6 +284,8 @@ #![feature(needs_panic_runtime)] #![feature(needs_drop)] #![feature(never_type)] +#![feature(num_cast)] +#![feature(num_cast_internals)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] #![feature(on_unimplemented)] diff --git a/src/libstd/num.rs b/src/libstd/num.rs index a2c133954a327..bc82be52eea8f 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -20,6 +20,8 @@ pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; +#[unstable(feature = "num_cast", issue = "0")] +pub use core::num::{Cast, CastError}; #[cfg(test)] use fmt; #[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem};