Skip to content

Commit 72ef15e

Browse files
committed
improve the TryFrom implementations
This removes the need for a 128 bit storage by making use of the fact that there can be either no over/underflow, either one or both, and each time the target type suffices to hold the limit for comparison. The downside is that the code looks a bit more complex. This test code included in this commit is from @oyvindln 's PR. They also greatly helped fixing a number of errors I made along the way. Thanks a lot!
1 parent b4502f7 commit 72ef15e

File tree

2 files changed

+391
-38
lines changed

2 files changed

+391
-38
lines changed

src/libcore/num/mod.rs

+177-38
Original file line numberDiff line numberDiff line change
@@ -2504,76 +2504,209 @@ impl fmt::Display for TryFromIntError {
25042504
}
25052505
}
25062506

2507-
macro_rules! same_sign_try_from_int_impl {
2508-
($storage:ty, $target:ty, $($source:ty),*) => {$(
2507+
// no possible bounds violation
2508+
macro_rules! try_from_unbounded {
2509+
($source:ty, $($target:ty),*) => {$(
25092510
#[unstable(feature = "try_from", issue = "33417")]
25102511
impl TryFrom<$source> for $target {
25112512
type Error = TryFromIntError;
25122513

2514+
#[inline]
25132515
fn try_from(u: $source) -> Result<$target, TryFromIntError> {
2514-
let min = <$target as FromStrRadixHelper>::min_value() as $storage;
2515-
let max = <$target as FromStrRadixHelper>::max_value() as $storage;
2516-
if u as $storage < min || u as $storage > max {
2517-
Err(TryFromIntError(()))
2518-
} else {
2516+
Ok(u as $target)
2517+
}
2518+
}
2519+
)*}
2520+
}
2521+
2522+
// only negative bounds
2523+
macro_rules! try_from_lower_bounded {
2524+
($source:ty, $($target:ty),*) => {$(
2525+
#[unstable(feature = "try_from", issue = "33417")]
2526+
impl TryFrom<$source> for $target {
2527+
type Error = TryFromIntError;
2528+
2529+
#[inline]
2530+
fn try_from(u: $source) -> Result<$target, TryFromIntError> {
2531+
if u >= 0 {
25192532
Ok(u as $target)
2533+
} else {
2534+
Err(TryFromIntError(()))
25202535
}
25212536
}
25222537
}
25232538
)*}
25242539
}
25252540

2526-
same_sign_try_from_int_impl!(u128, u8, u8, u16, u32, u64, u128, usize);
2527-
same_sign_try_from_int_impl!(i128, i8, i8, i16, i32, i64, i128, isize);
2528-
same_sign_try_from_int_impl!(u128, u16, u8, u16, u32, u64, u128, usize);
2529-
same_sign_try_from_int_impl!(i128, i16, i8, i16, i32, i64, i128, isize);
2530-
same_sign_try_from_int_impl!(u128, u32, u8, u16, u32, u64, u128, usize);
2531-
same_sign_try_from_int_impl!(i128, i32, i8, i16, i32, i64, i128, isize);
2532-
same_sign_try_from_int_impl!(u128, u64, u8, u16, u32, u64, u128, usize);
2533-
same_sign_try_from_int_impl!(i128, i64, i8, i16, i32, i64, i128, isize);
2534-
same_sign_try_from_int_impl!(u128, u128, u8, u16, u32, u64, u128, usize);
2535-
same_sign_try_from_int_impl!(i128, i128, i8, i16, i32, i64, i128, isize);
2536-
same_sign_try_from_int_impl!(u128, usize, u8, u16, u32, u64, u128, usize);
2537-
same_sign_try_from_int_impl!(i128, isize, i8, i16, i32, i64, i128, isize);
2538-
2539-
macro_rules! cross_sign_from_int_impl {
2540-
($unsigned:ty, $($signed:ty),*) => {$(
2541+
// unsigned to signed (only positive bound)
2542+
macro_rules! try_from_upper_bounded {
2543+
($source:ty, $($target:ty),*) => {$(
25412544
#[unstable(feature = "try_from", issue = "33417")]
2542-
impl TryFrom<$unsigned> for $signed {
2545+
impl TryFrom<$source> for $target {
25432546
type Error = TryFromIntError;
25442547

2545-
fn try_from(u: $unsigned) -> Result<$signed, TryFromIntError> {
2546-
let max = <$signed as FromStrRadixHelper>::max_value() as u128;
2547-
if u as u128 > max {
2548+
#[inline]
2549+
fn try_from(u: $source) -> Result<$target, TryFromIntError> {
2550+
if u > (<$target>::max_value() as $source) {
25482551
Err(TryFromIntError(()))
25492552
} else {
2550-
Ok(u as $signed)
2553+
Ok(u as $target)
25512554
}
25522555
}
25532556
}
2557+
)*}
2558+
}
25542559

2560+
// all other cases
2561+
macro_rules! try_from_both_bounded {
2562+
($source:ty, $($target:ty),*) => {$(
25552563
#[unstable(feature = "try_from", issue = "33417")]
2556-
impl TryFrom<$signed> for $unsigned {
2564+
impl TryFrom<$source> for $target {
25572565
type Error = TryFromIntError;
25582566

2559-
fn try_from(u: $signed) -> Result<$unsigned, TryFromIntError> {
2560-
let max = <$unsigned as FromStrRadixHelper>::max_value() as u128;
2561-
if u < 0 || u as u128 > max {
2567+
#[inline]
2568+
fn try_from(u: $source) -> Result<$target, TryFromIntError> {
2569+
let min = <$target>::min_value() as $source;
2570+
let max = <$target>::max_value() as $source;
2571+
if u < min || u > max {
25622572
Err(TryFromIntError(()))
25632573
} else {
2564-
Ok(u as $unsigned)
2574+
Ok(u as $target)
25652575
}
25662576
}
25672577
}
25682578
)*}
25692579
}
25702580

2571-
cross_sign_from_int_impl!(u8, i8, i16, i32, i64, i128, isize);
2572-
cross_sign_from_int_impl!(u16, i8, i16, i32, i64, i128, isize);
2573-
cross_sign_from_int_impl!(u32, i8, i16, i32, i64, i128, isize);
2574-
cross_sign_from_int_impl!(u64, i8, i16, i32, i64, i128, isize);
2575-
cross_sign_from_int_impl!(u128, i8, i16, i32, i64, i128, isize);
2576-
cross_sign_from_int_impl!(usize, i8, i16, i32, i64, i128, isize);
2581+
macro_rules! rev {
2582+
($mac:ident, $source:ty, $($target:ty),*) => {$(
2583+
$mac!($target, $source);
2584+
)*}
2585+
}
2586+
2587+
/// intra-sign conversions
2588+
try_from_unbounded!(u8, u8, u16, u32, u64, u128);
2589+
try_from_unbounded!(u16, u16, u32, u64, u128);
2590+
try_from_unbounded!(u32, u32, u64, u128);
2591+
try_from_unbounded!(u64, u64, u128);
2592+
try_from_unbounded!(u128, u128);
2593+
try_from_upper_bounded!(u16, u8);
2594+
try_from_upper_bounded!(u32, u16, u8);
2595+
try_from_upper_bounded!(u64, u32, u16, u8);
2596+
try_from_upper_bounded!(u128, u64, u32, u16, u8);
2597+
2598+
try_from_unbounded!(i8, i8, i16, i32, i64, i128);
2599+
try_from_unbounded!(i16, i16, i32, i64, i128);
2600+
try_from_unbounded!(i32, i32, i64, i128);
2601+
try_from_unbounded!(i64, i64, i128);
2602+
try_from_unbounded!(i128, i128);
2603+
try_from_both_bounded!(i16, i8);
2604+
try_from_both_bounded!(i32, i16, i8);
2605+
try_from_both_bounded!(i64, i32, i16, i8);
2606+
try_from_both_bounded!(i128, i64, i32, i16, i8);
2607+
2608+
// unsigned-to-signed
2609+
try_from_unbounded!(u8, i16, i32, i64, i128);
2610+
try_from_unbounded!(u16, i32, i64, i128);
2611+
try_from_unbounded!(u32, i64, i128);
2612+
try_from_unbounded!(u64, i128);
2613+
try_from_upper_bounded!(u8, i8);
2614+
try_from_upper_bounded!(u16, i8, i16);
2615+
try_from_upper_bounded!(u32, i8, i16, i32);
2616+
try_from_upper_bounded!(u64, i8, i16, i32, i64);
2617+
try_from_upper_bounded!(u128, i8, i16, i32, i64, i128);
2618+
2619+
// signed-to-unsigned
2620+
try_from_lower_bounded!(i8, u8, u16, u32, u64, u128);
2621+
try_from_lower_bounded!(i16, u16, u32, u64, u128);
2622+
try_from_lower_bounded!(i32, u32, u64, u128);
2623+
try_from_lower_bounded!(i64, u64, u128);
2624+
try_from_lower_bounded!(i128, u128);
2625+
try_from_both_bounded!(i16, u8);
2626+
try_from_both_bounded!(i32, u16, u8);
2627+
try_from_both_bounded!(i64, u32, u16, u8);
2628+
try_from_both_bounded!(i128, u64, u32, u16, u8);
2629+
2630+
#[unstable(feature = "try_from", issue = "33417")]
2631+
pub use self::ptr_try_from_impls::*;
2632+
2633+
#[cfg(target_pointer_width = "16")]
2634+
mod ptr_try_from_impls {
2635+
use super::TryFromIntError;
2636+
use convert::TryFrom;
2637+
2638+
try_from_upper_bounded!(usize, u8);
2639+
try_from_unbounded!(usize, usize, u16, u32, u64, u128);
2640+
try_from_upper_bounded!(usize, i8, i16, isize);
2641+
try_from_unbounded!(usize, i32, i64, i128);
2642+
2643+
try_from_both_bounded!(isize, u8);
2644+
try_from_lower_bounded!(isize, usize, u16, u32, u64, u128);
2645+
try_from_both_bounded!(isize, i8);
2646+
try_from_unbounded!(isize, i16, i32, i64, i128);
2647+
2648+
rev!(try_from_unbounded, usize, u8, u16);
2649+
rev!(try_from_upper_bounded, usize, u32, u64, u128);
2650+
rev!(try_from_lower_bounded, usize, i8, i16);
2651+
rev!(try_from_both_bounded, usize, i32, i64, i128);
2652+
2653+
rev!(try_from_unbounded, isize, u8);
2654+
rev!(try_from_upper_bounded, isize, u16, u32, u64, u128);
2655+
rev!(try_from_unbounded, isize, i8, i16);
2656+
rev!(try_from_both_bounded, isize, i32, i64, i128);
2657+
}
2658+
2659+
#[cfg(target_pointer_width = "32")]
2660+
mod ptr_try_from_impls {
2661+
use super::TryFromIntError;
2662+
use convert::TryFrom;
2663+
2664+
try_from_upper_bounded!(usize, u8, u16);
2665+
try_from_unbounded!(usize, usize, u32, u64, u128);
2666+
try_from_upper_bounded!(usize, i8, i16, i32, isize);
2667+
try_from_unbounded!(usize, i64, i128);
2668+
2669+
try_from_both_bounded!(isize, u8, u16);
2670+
try_from_lower_bounded!(isize, usize, u32, u64, u128);
2671+
try_from_both_bounded!(isize, i8, i16);
2672+
try_from_unbounded!(isize, i32, i64, i128);
2673+
2674+
rev!(try_from_unbounded, usize, u8, u16, u32);
2675+
rev!(try_from_upper_bounded, usize, u64, u128);
2676+
rev!(try_from_lower_bounded, usize, i8, i16, i32);
2677+
rev!(try_from_both_bounded, usize, i64, i128);
2678+
2679+
rev!(try_from_unbounded, isize, u8, u16);
2680+
rev!(try_from_upper_bounded, isize, u32, u64, u128);
2681+
rev!(try_from_unbounded, isize, i8, i16, i32);
2682+
rev!(try_from_both_bounded, isize, i64, i128);
2683+
}
2684+
2685+
#[cfg(target_pointer_width = "64")]
2686+
mod ptr_try_from_impls {
2687+
use super::TryFromIntError;
2688+
use convert::TryFrom;
2689+
2690+
try_from_upper_bounded!(usize, u8, u16, u32);
2691+
try_from_unbounded!(usize, usize, u64, u128);
2692+
try_from_upper_bounded!(usize, i8, i16, i32, i64, isize);
2693+
try_from_unbounded!(usize, i128);
2694+
2695+
try_from_both_bounded!(isize, u8, u16, u32);
2696+
try_from_lower_bounded!(isize, usize, u64, u128);
2697+
try_from_both_bounded!(isize, i8, i16, i32);
2698+
try_from_unbounded!(isize, i64, i128);
2699+
2700+
rev!(try_from_unbounded, usize, u8, u16, u32, u64);
2701+
rev!(try_from_upper_bounded, usize, u128);
2702+
rev!(try_from_lower_bounded, usize, i8, i16, i32, i64);
2703+
rev!(try_from_both_bounded, usize, i128);
2704+
2705+
rev!(try_from_unbounded, isize, u8, u16, u32);
2706+
rev!(try_from_upper_bounded, isize, u64, u128);
2707+
rev!(try_from_unbounded, isize, i8, i16, i32, i64);
2708+
rev!(try_from_both_bounded, isize, i128);
2709+
}
25772710

25782711
#[doc(hidden)]
25792712
trait FromStrRadixHelper: PartialOrd + Copy {
@@ -2587,15 +2720,21 @@ trait FromStrRadixHelper: PartialOrd + Copy {
25872720

25882721
macro_rules! doit {
25892722
($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
2723+
#[inline]
25902724
fn min_value() -> Self { Self::min_value() }
2725+
#[inline]
25912726
fn max_value() -> Self { Self::max_value() }
2727+
#[inline]
25922728
fn from_u32(u: u32) -> Self { u as Self }
2729+
#[inline]
25932730
fn checked_mul(&self, other: u32) -> Option<Self> {
25942731
Self::checked_mul(*self, other as Self)
25952732
}
2733+
#[inline]
25962734
fn checked_sub(&self, other: u32) -> Option<Self> {
25972735
Self::checked_sub(*self, other as Self)
25982736
}
2737+
#[inline]
25992738
fn checked_add(&self, other: u32) -> Option<Self> {
26002739
Self::checked_add(*self, other as Self)
26012740
}

0 commit comments

Comments
 (0)