Skip to content

Commit cc98f4c

Browse files
committed
Rollup merge of rust-lang#33426 - sfackler:try-from, r=aturon
Implement RFC 1542 cc rust-lang#33417 r? @aturon
2 parents 5d87805 + a9779df commit cc98f4c

File tree

7 files changed

+450
-158
lines changed

7 files changed

+450
-158
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};
@@ -2352,9 +2352,101 @@ macro_rules! from_str_radix_int_impl {
23522352
}
23532353
from_str_radix_int_impl! { isize i8 i16 i32 i64 usize u8 u16 u32 u64 }
23542354

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

src/libcoretest/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#![feature(unboxed_closures)]
3434
#![feature(unicode)]
3535
#![feature(unique)]
36+
#![feature(try_from)]
3637

3738
extern crate core;
3839
extern crate test;

0 commit comments

Comments
 (0)