Skip to content

Commit 7c46c6c

Browse files
committed
Auto merge of #43248 - llogiq:num-try-from, r=nagisa
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. This also means that the implementation will work in targets without 128bit support (unless it's for 128bit types, of course). The downside is that the code looks a bit more complex.
2 parents 598eddf + 72ef15e commit 7c46c6c

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)