diff options
| author | Steven Fackler <sfackler@gmail.com> | 2016-05-04 22:42:14 -0700 |
|---|---|---|
| committer | Steven Fackler <sfackler@gmail.com> | 2016-05-07 08:52:41 -0700 |
| commit | a9779df1886e18923f40cf0bb67ab72d4e4942df (patch) | |
| tree | 8b2cb30118bca393968a3bd28ab0d47384ee76ec /src/libcore | |
| parent | 936b32a514b73c1d3dfcbd9d17818f9f18bf4883 (diff) | |
| download | rust-a9779df1886e18923f40cf0bb67ab72d4e4942df.tar.gz rust-a9779df1886e18923f40cf0bb67ab72d4e4942df.zip | |
Implement RFC 1542
cc #33417
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/convert.rs | 57 | ||||
| -rw-r--r-- | src/libcore/num/mod.rs | 95 |
2 files changed, 141 insertions, 11 deletions
diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 2d999868f71..48421abc7bb 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -20,18 +20,19 @@ //! - Impl the `As*` traits for reference-to-reference conversions //! - Impl the `Into` trait when you want to consume the value in the conversion //! - The `From` trait is the most flexible, useful for value _and_ reference conversions +//! - The `TryFrom` and `TryInto` traits behave like `From` and `Into`, but allow for the +//! conversion to fail //! -//! As a library author, you should prefer implementing `From<T>` rather than -//! `Into<U>`, as `From` provides greater flexibility and offers an equivalent `Into` -//! implementation for free, thanks to a blanket implementation in the standard library. -//! -//! **Note: these traits must not fail**. If the conversion can fail, you must use a dedicated -//! method which returns an `Option<T>` or a `Result<T, E>`. +//! As a library author, you should prefer implementing `From<T>` or `TryFrom<T>` rather than +//! `Into<U>` or `TryInto<U>`, as `From` and `TryFrom` provide greater flexibility and offer +//! equivalent `Into` or `TryInto` implementations for free, thanks to a blanket implementation +//! in the standard library. //! //! # Generic impl //! //! - `AsRef` and `AsMut` auto-dereference if the inner type is a reference //! - `From<U> for T` implies `Into<T> for U` +//! - `TryFrom<U> for T` implies `TryInto<T> for U` //! - `From` and `Into` are reflexive, which means that all types can `into()` //! themselves and `from()` themselves //! @@ -40,6 +41,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use marker::Sized; +use result::Result; /// A cheap, reference-to-reference conversion. /// @@ -98,8 +100,8 @@ pub trait AsMut<T: ?Sized> { /// A conversion that consumes `self`, which may or may not be expensive. /// -/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which -/// returns an `Option<T>` or a `Result<T, E>`. +/// **Note: this trait must not fail**. If the conversion can fail, use `TryInto` or a dedicated +/// method which returns an `Option<T>` or a `Result<T, E>`. /// /// Library authors should not directly implement this trait, but should prefer implementing /// the `From` trait, which offers greater flexibility and provides an equivalent `Into` @@ -133,8 +135,8 @@ pub trait Into<T>: Sized { /// Construct `Self` via a conversion. /// -/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which -/// returns an `Option<T>` or a `Result<T, E>`. +/// **Note: this trait must not fail**. If the conversion can fail, use `TryFrom` or a dedicated +/// method which returns an `Option<T>` or a `Result<T, E>`. /// /// # Examples /// @@ -158,6 +160,30 @@ pub trait From<T>: Sized { fn from(T) -> Self; } +/// An attempted conversion that consumes `self`, which may or may not be expensive. +/// +/// Library authors should not directly implement this trait, but should prefer implementing +/// the `TryFrom` trait, which offers greater flexibility and provides an equivalent `TryInto` +/// implementation for free, thanks to a blanket implementation in the standard library. +#[unstable(feature = "try_from", issue = "33417")] +pub trait TryInto<T>: Sized { + /// The type returned in the event of a conversion error. + type Err; + + /// Performs the conversion. + fn try_into(self) -> Result<T, Self::Err>; +} + +/// Attempt to construct `Self` via a conversion. +#[unstable(feature = "try_from", issue = "33417")] +pub trait TryFrom<T>: Sized { + /// The type returned in the event of a conversion error. + type Err; + + /// Performs the conversion. + fn try_from(T) -> Result<Self, Self::Err>; +} + //////////////////////////////////////////////////////////////////////////////// // GENERIC IMPLS //////////////////////////////////////////////////////////////////////////////// @@ -216,6 +242,17 @@ impl<T> From<T> for T { fn from(t: T) -> T { t } } + +// TryFrom implies TryInto +#[unstable(feature = "try_from", issue = "33417")] +impl<T, U> TryInto<U> for T where U: TryFrom<T> { + type Err = U::Err; + + fn try_into(self) -> Result<U, U::Err> { + U::try_from(self) + } +} + //////////////////////////////////////////////////////////////////////////////// // CONCRETE IMPLS //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 589ac90b308..e048c963d15 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -15,7 +15,7 @@ use char::CharExt; use cmp::PartialOrd; -use convert::From; +use convert::{From, TryFrom}; use fmt; use intrinsics; use marker::{Copy, Sized}; @@ -2341,9 +2341,101 @@ macro_rules! from_str_radix_int_impl { } from_str_radix_int_impl! { isize i8 i16 i32 i64 usize u8 u16 u32 u64 } +/// The error type returned when a checked integral type conversion fails. +#[unstable(feature = "try_from", issue = "33417")] +#[derive(Debug, Copy, Clone)] +pub struct TryFromIntError(()); + +impl TryFromIntError { + #[unstable(feature = "int_error_internals", + reason = "available through Error trait and this method should \ + not be exposed publicly", + issue = "0")] + #[doc(hidden)] + pub fn __description(&self) -> &str { + "out of range integral type conversion attempted" + } +} + +#[unstable(feature = "try_from", issue = "33417")] +impl fmt::Display for TryFromIntError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + self.__description().fmt(fmt) + } +} + +macro_rules! same_sign_from_int_impl { + ($storage:ty, $target:ty, $($source:ty),*) => {$( + #[stable(feature = "rust1", since = "1.0.0")] + impl TryFrom<$source> for $target { + type Err = TryFromIntError; + + fn try_from(u: $source) -> Result<$target, TryFromIntError> { + let min = <$target as FromStrRadixHelper>::min_value() as $storage; + let max = <$target as FromStrRadixHelper>::max_value() as $storage; + if u as $storage < min || u as $storage > max { + Err(TryFromIntError(())) + } else { + Ok(u as $target) + } + } + } + )*} +} + +same_sign_from_int_impl!(u64, u8, u8, u16, u32, u64, usize); +same_sign_from_int_impl!(i64, i8, i8, i16, i32, i64, isize); +same_sign_from_int_impl!(u64, u16, u8, u16, u32, u64, usize); +same_sign_from_int_impl!(i64, i16, i8, i16, i32, i64, isize); +same_sign_from_int_impl!(u64, u32, u8, u16, u32, u64, usize); +same_sign_from_int_impl!(i64, i32, i8, i16, i32, i64, isize); +same_sign_from_int_impl!(u64, u64, u8, u16, u32, u64, usize); +same_sign_from_int_impl!(i64, i64, i8, i16, i32, i64, isize); +same_sign_from_int_impl!(u64, usize, u8, u16, u32, u64, usize); +same_sign_from_int_impl!(i64, isize, i8, i16, i32, i64, isize); + +macro_rules! cross_sign_from_int_impl { + ($unsigned:ty, $($signed:ty),*) => {$( + #[stable(feature = "rust1", since = "1.0.0")] + impl TryFrom<$unsigned> for $signed { + type Err = TryFromIntError; + + fn try_from(u: $unsigned) -> Result<$signed, TryFromIntError> { + let max = <$signed as FromStrRadixHelper>::max_value() as u64; + if u as u64 > max { + Err(TryFromIntError(())) + } else { + Ok(u as $signed) + } + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl TryFrom<$signed> for $unsigned { + type Err = TryFromIntError; + + fn try_from(u: $signed) -> Result<$unsigned, TryFromIntError> { + let max = <$unsigned as FromStrRadixHelper>::max_value() as u64; + if u < 0 || u as u64 > max { + Err(TryFromIntError(())) + } else { + Ok(u as $unsigned) + } + } + } + )*} +} + +cross_sign_from_int_impl!(u8, i8, i16, i32, i64, isize); +cross_sign_from_int_impl!(u16, i8, i16, i32, i64, isize); +cross_sign_from_int_impl!(u32, i8, i16, i32, i64, isize); +cross_sign_from_int_impl!(u64, i8, i16, i32, i64, isize); +cross_sign_from_int_impl!(usize, i8, i16, i32, i64, isize); + #[doc(hidden)] trait FromStrRadixHelper: PartialOrd + Copy { fn min_value() -> Self; + fn max_value() -> Self; fn from_u32(u: u32) -> Self; fn checked_mul(&self, other: u32) -> Option<Self>; fn checked_sub(&self, other: u32) -> Option<Self>; @@ -2353,6 +2445,7 @@ trait FromStrRadixHelper: PartialOrd + Copy { macro_rules! doit { ($($t:ty)*) => ($(impl FromStrRadixHelper for $t { fn min_value() -> Self { Self::min_value() } + fn max_value() -> Self { Self::max_value() } fn from_u32(u: u32) -> Self { u as Self } fn checked_mul(&self, other: u32) -> Option<Self> { Self::checked_mul(*self, other as Self) |
