Skip to content

Commit a9779df

Browse files
committed
Implement RFC 1542
cc rust-lang#33417
1 parent 936b32a commit a9779df

File tree

7 files changed

+451
-159
lines changed

7 files changed

+451
-159
lines changed

src/libcore/convert.rs

+47-10
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,19 @@
2020
//! - Impl the `As*` traits for reference-to-reference conversions
2121
//! - Impl the `Into` trait when you want to consume the value in the conversion
2222
//! - The `From` trait is the most flexible, useful for value _and_ reference conversions
23+
//! - The `TryFrom` and `TryInto` traits behave like `From` and `Into`, but allow for the
24+
//! conversion to fail
2325
//!
24-
//! As a library author, you should prefer implementing `From<T>` rather than
25-
//! `Into<U>`, as `From` provides greater flexibility and offers an equivalent `Into`
26-
//! implementation for free, thanks to a blanket implementation in the standard library.
27-
//!
28-
//! **Note: these traits must not fail**. If the conversion can fail, you must use a dedicated
29-
//! method which returns an `Option<T>` or a `Result<T, E>`.
26+
//! As a library author, you should prefer implementing `From<T>` or `TryFrom<T>` rather than
27+
//! `Into<U>` or `TryInto<U>`, as `From` and `TryFrom` provide greater flexibility and offer
28+
//! equivalent `Into` or `TryInto` implementations for free, thanks to a blanket implementation
29+
//! in the standard library.
3030
//!
3131
//! # Generic impl
3232
//!
3333
//! - `AsRef` and `AsMut` auto-dereference if the inner type is a reference
3434
//! - `From<U> for T` implies `Into<T> for U`
35+
//! - `TryFrom<U> for T` implies `TryInto<T> for U`
3536
//! - `From` and `Into` are reflexive, which means that all types can `into()`
3637
//! themselves and `from()` themselves
3738
//!
@@ -40,6 +41,7 @@
4041
#![stable(feature = "rust1", since = "1.0.0")]
4142

4243
use marker::Sized;
44+
use result::Result;
4345

4446
/// A cheap, reference-to-reference conversion.
4547
///
@@ -98,8 +100,8 @@ pub trait AsMut<T: ?Sized> {
98100

99101
/// A conversion that consumes `self`, which may or may not be expensive.
100102
///
101-
/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which
102-
/// returns an `Option<T>` or a `Result<T, E>`.
103+
/// **Note: this trait must not fail**. If the conversion can fail, use `TryInto` or a dedicated
104+
/// method which returns an `Option<T>` or a `Result<T, E>`.
103105
///
104106
/// Library authors should not directly implement this trait, but should prefer implementing
105107
/// the `From` trait, which offers greater flexibility and provides an equivalent `Into`
@@ -133,8 +135,8 @@ pub trait Into<T>: Sized {
133135

134136
/// Construct `Self` via a conversion.
135137
///
136-
/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which
137-
/// returns an `Option<T>` or a `Result<T, E>`.
138+
/// **Note: this trait must not fail**. If the conversion can fail, use `TryFrom` or a dedicated
139+
/// method which returns an `Option<T>` or a `Result<T, E>`.
138140
///
139141
/// # Examples
140142
///
@@ -158,6 +160,30 @@ pub trait From<T>: Sized {
158160
fn from(T) -> Self;
159161
}
160162

163+
/// An attempted conversion that consumes `self`, which may or may not be expensive.
164+
///
165+
/// Library authors should not directly implement this trait, but should prefer implementing
166+
/// the `TryFrom` trait, which offers greater flexibility and provides an equivalent `TryInto`
167+
/// implementation for free, thanks to a blanket implementation in the standard library.
168+
#[unstable(feature = "try_from", issue = "33417")]
169+
pub trait TryInto<T>: Sized {
170+
/// The type returned in the event of a conversion error.
171+
type Err;
172+
173+
/// Performs the conversion.
174+
fn try_into(self) -> Result<T, Self::Err>;
175+
}
176+
177+
/// Attempt to construct `Self` via a conversion.
178+
#[unstable(feature = "try_from", issue = "33417")]
179+
pub trait TryFrom<T>: Sized {
180+
/// The type returned in the event of a conversion error.
181+
type Err;
182+
183+
/// Performs the conversion.
184+
fn try_from(T) -> Result<Self, Self::Err>;
185+
}
186+
161187
////////////////////////////////////////////////////////////////////////////////
162188
// GENERIC IMPLS
163189
////////////////////////////////////////////////////////////////////////////////
@@ -216,6 +242,17 @@ impl<T> From<T> for T {
216242
fn from(t: T) -> T { t }
217243
}
218244

245+
246+
// TryFrom implies TryInto
247+
#[unstable(feature = "try_from", issue = "33417")]
248+
impl<T, U> TryInto<U> for T where U: TryFrom<T> {
249+
type Err = U::Err;
250+
251+
fn try_into(self) -> Result<U, U::Err> {
252+
U::try_from(self)
253+
}
254+
}
255+
219256
////////////////////////////////////////////////////////////////////////////////
220257
// CONCRETE IMPLS
221258
////////////////////////////////////////////////////////////////////////////////

src/libcore/num/mod.rs

+94-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
use char::CharExt;
1717
use cmp::PartialOrd;
18-
use convert::From;
18+
use convert::{From, TryFrom};
1919
use fmt;
2020
use intrinsics;
2121
use marker::{Copy, Sized};
@@ -2341,9 +2341,101 @@ macro_rules! from_str_radix_int_impl {
23412341
}
23422342
from_str_radix_int_impl! { isize i8 i16 i32 i64 usize u8 u16 u32 u64 }
23432343

2344+
/// The error type returned when a checked integral type conversion fails.
2345+
#[unstable(feature = "try_from", issue = "33417")]
2346+
#[derive(Debug, Copy, Clone)]
2347+
pub struct TryFromIntError(());
2348+
2349+
impl TryFromIntError {
2350+
#[unstable(feature = "int_error_internals",
2351+
reason = "available through Error trait and this method should \
2352+
not be exposed publicly",
2353+
issue = "0")]
2354+
#[doc(hidden)]
2355+
pub fn __description(&self) -> &str {
2356+
"out of range integral type conversion attempted"
2357+
}
2358+
}
2359+
2360+
#[unstable(feature = "try_from", issue = "33417")]
2361+
impl fmt::Display for TryFromIntError {
2362+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2363+
self.__description().fmt(fmt)
2364+
}
2365+
}
2366+
2367+
macro_rules! same_sign_from_int_impl {
2368+
($storage:ty, $target:ty, $($source:ty),*) => {$(
2369+
#[stable(feature = "rust1", since = "1.0.0")]
2370+
impl TryFrom<$source> for $target {
2371+
type Err = TryFromIntError;
2372+
2373+
fn try_from(u: $source) -> Result<$target, TryFromIntError> {
2374+
let min = <$target as FromStrRadixHelper>::min_value() as $storage;
2375+
let max = <$target as FromStrRadixHelper>::max_value() as $storage;
2376+
if u as $storage < min || u as $storage > max {
2377+
Err(TryFromIntError(()))
2378+
} else {
2379+
Ok(u as $target)
2380+
}
2381+
}
2382+
}
2383+
)*}
2384+
}
2385+
2386+
same_sign_from_int_impl!(u64, u8, u8, u16, u32, u64, usize);
2387+
same_sign_from_int_impl!(i64, i8, i8, i16, i32, i64, isize);
2388+
same_sign_from_int_impl!(u64, u16, u8, u16, u32, u64, usize);
2389+
same_sign_from_int_impl!(i64, i16, i8, i16, i32, i64, isize);
2390+
same_sign_from_int_impl!(u64, u32, u8, u16, u32, u64, usize);
2391+
same_sign_from_int_impl!(i64, i32, i8, i16, i32, i64, isize);
2392+
same_sign_from_int_impl!(u64, u64, u8, u16, u32, u64, usize);
2393+
same_sign_from_int_impl!(i64, i64, i8, i16, i32, i64, isize);
2394+
same_sign_from_int_impl!(u64, usize, u8, u16, u32, u64, usize);
2395+
same_sign_from_int_impl!(i64, isize, i8, i16, i32, i64, isize);
2396+
2397+
macro_rules! cross_sign_from_int_impl {
2398+
($unsigned:ty, $($signed:ty),*) => {$(
2399+
#[stable(feature = "rust1", since = "1.0.0")]
2400+
impl TryFrom<$unsigned> for $signed {
2401+
type Err = TryFromIntError;
2402+
2403+
fn try_from(u: $unsigned) -> Result<$signed, TryFromIntError> {
2404+
let max = <$signed as FromStrRadixHelper>::max_value() as u64;
2405+
if u as u64 > max {
2406+
Err(TryFromIntError(()))
2407+
} else {
2408+
Ok(u as $signed)
2409+
}
2410+
}
2411+
}
2412+
2413+
#[stable(feature = "rust1", since = "1.0.0")]
2414+
impl TryFrom<$signed> for $unsigned {
2415+
type Err = TryFromIntError;
2416+
2417+
fn try_from(u: $signed) -> Result<$unsigned, TryFromIntError> {
2418+
let max = <$unsigned as FromStrRadixHelper>::max_value() as u64;
2419+
if u < 0 || u as u64 > max {
2420+
Err(TryFromIntError(()))
2421+
} else {
2422+
Ok(u as $unsigned)
2423+
}
2424+
}
2425+
}
2426+
)*}
2427+
}
2428+
2429+
cross_sign_from_int_impl!(u8, i8, i16, i32, i64, isize);
2430+
cross_sign_from_int_impl!(u16, i8, i16, i32, i64, isize);
2431+
cross_sign_from_int_impl!(u32, i8, i16, i32, i64, isize);
2432+
cross_sign_from_int_impl!(u64, i8, i16, i32, i64, isize);
2433+
cross_sign_from_int_impl!(usize, i8, i16, i32, i64, isize);
2434+
23442435
#[doc(hidden)]
23452436
trait FromStrRadixHelper: PartialOrd + Copy {
23462437
fn min_value() -> Self;
2438+
fn max_value() -> Self;
23472439
fn from_u32(u: u32) -> Self;
23482440
fn checked_mul(&self, other: u32) -> Option<Self>;
23492441
fn checked_sub(&self, other: u32) -> Option<Self>;
@@ -2353,6 +2445,7 @@ trait FromStrRadixHelper: PartialOrd + Copy {
23532445
macro_rules! doit {
23542446
($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
23552447
fn min_value() -> Self { Self::min_value() }
2448+
fn max_value() -> Self { Self::max_value() }
23562449
fn from_u32(u: u32) -> Self { u as Self }
23572450
fn checked_mul(&self, other: u32) -> Option<Self> {
23582451
Self::checked_mul(*self, other as Self)

src/libcoretest/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#![feature(unboxed_closures)]
3535
#![feature(unicode)]
3636
#![feature(unique)]
37+
#![feature(try_from)]
3738

3839
extern crate core;
3940
extern crate test;

0 commit comments

Comments
 (0)