Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@
#![feature(unwind_attributes)]

#![cfg_attr(stage0, feature(associated_consts))]
#![cfg_attr(
not(any(target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64")),
feature(compile_error)
)]

#[prelude_import]
#[allow(unused)]
Expand Down
184 changes: 148 additions & 36 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2504,16 +2504,17 @@ impl fmt::Display for TryFromIntError {
}
}

macro_rules! same_sign_try_from_int_impl {
($storage:ty, $target:ty, $($source:ty),*) => {$(
macro_rules! same_sign_try_from_wider_impl {
($target:ty, $($source:ty),*) => {$(
#[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;

#[inline]
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 {
let min = <$target>::min_value() as $source;
let max = <$target>::max_value() as $source;
if u as $source < min || u as $source > max {
Err(TryFromIntError(()))
} else {
Ok(u as $target)
Expand All @@ -2523,42 +2524,120 @@ macro_rules! same_sign_try_from_int_impl {
)*}
}

same_sign_try_from_int_impl!(u128, u8, u8, u16, u32, u64, u128, usize);
same_sign_try_from_int_impl!(i128, i8, i8, i16, i32, i64, i128, isize);
same_sign_try_from_int_impl!(u128, u16, u8, u16, u32, u64, u128, usize);
same_sign_try_from_int_impl!(i128, i16, i8, i16, i32, i64, i128, isize);
same_sign_try_from_int_impl!(u128, u32, u8, u16, u32, u64, u128, usize);
same_sign_try_from_int_impl!(i128, i32, i8, i16, i32, i64, i128, isize);
same_sign_try_from_int_impl!(u128, u64, u8, u16, u32, u64, u128, usize);
same_sign_try_from_int_impl!(i128, i64, i8, i16, i32, i64, i128, isize);
same_sign_try_from_int_impl!(u128, u128, u8, u16, u32, u64, u128, usize);
same_sign_try_from_int_impl!(i128, i128, i8, i16, i32, i64, i128, isize);
same_sign_try_from_int_impl!(u128, usize, u8, u16, u32, u64, u128, usize);
same_sign_try_from_int_impl!(i128, isize, i8, i16, i32, i64, i128, isize);

macro_rules! cross_sign_from_int_impl {
($unsigned:ty, $($signed:ty),*) => {$(
/// TryFrom on types where the conversion will always succeed.
macro_rules! trivial_try_from_impl {
($source:ty, $($target:ty),*) => {$(
#[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<$unsigned> for $signed {
impl TryFrom<$source> for $target {
type Error = TryFromIntError;

fn try_from(u: $unsigned) -> Result<$signed, TryFromIntError> {
let max = <$signed as FromStrRadixHelper>::max_value() as u128;
if u as u128 > max {
Err(TryFromIntError(()))
} else {
Ok(u as $signed)
}
#[inline]
fn try_from(u: $source) -> Result<$target, TryFromIntError> {
Ok(u as $target)
}
}
)*}
}

#[cfg(not(any(
target_pointer_width = "16", target_pointer_width = "32", target_pointer_width = "64")))]
compile_error!("The current implementations of try_from on usize/isize assumes that \
the pointer width is either 16, 32, or 64");
// (source, $(target))
trivial_try_from_impl!(u8, u8, u16, i16, u32, i32, u64, i64, u128, i128, usize);
trivial_try_from_impl!(u16, u16, u32, i32, u64, i64, u128, i128, usize);
trivial_try_from_impl!(u32, u32, u64, i64, u128, i128);
trivial_try_from_impl!(u64, u64, u128, i128);
trivial_try_from_impl!(u128, u128);
trivial_try_from_impl!(usize, usize, u128, i128);
trivial_try_from_impl!(usize, u64);

trivial_try_from_impl!(i8, i8, i16, i32, i64, i128, isize);
trivial_try_from_impl!(i16, i16, i32, i64, i128, isize);
trivial_try_from_impl!(i32, i32, i64, i128);
trivial_try_from_impl!(i64, i64, i128);
trivial_try_from_impl!(i128, i128);
trivial_try_from_impl!(isize, isize, i128);
trivial_try_from_impl!(isize, i64);

// (target, $(source))
same_sign_try_from_wider_impl!(u8, u16, u32, u64, u128, usize);
same_sign_try_from_wider_impl!(i8, i16, i32, i64, i128, isize);
same_sign_try_from_wider_impl!(u16, u32, u64, u128);
same_sign_try_from_wider_impl!(i16, i32, i64, i128);
same_sign_try_from_wider_impl!(u32, u64, u128);
same_sign_try_from_wider_impl!(i32, i64, i128);
same_sign_try_from_wider_impl!(u64, u128);
same_sign_try_from_wider_impl!(i64, i128);
same_sign_try_from_wider_impl!(usize, u128);
same_sign_try_from_wider_impl!(isize, u128);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn’t this be isize, i128?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed


macro_rules! cfg_block {
($(#[$attr:meta]{$($it:item)*})*) => {$($(
#[$attr]
$it
)*)*}
}


cfg_block!(
// Platform specific impls for conversions with the same sign:
// xsize -> x32
// xsize -> x16
// x32 -> xsize
// x64 -> xsize

// 16-bit.
#[cfg(target_pointer_width = "16")] {
// x32 -> xsize
same_sign_try_from_wider_impl!(usize, u32);
same_sign_try_from_wider_impl!(isize, i32);
// xsize -> x16
trivial_try_from_impl!(usize, u16);
trivial_try_from_impl!(isize, i16);
}

// Same for 16 and 32-bit platforms.
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))] {
// xsize -> x32
trivial_try_from_impl!(usize, u32);
trivial_try_from_impl!(isize, i32);
// x64 -> xsize
same_sign_try_from_wider_impl!(usize, u64);
same_sign_try_from_wider_impl!(isize, u64);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A cross-sign conversion again.

I think this code would be easier follow if it was only split into blocks for each target_pointer_width.

Something like:

#[cfg(target_pointer_width = "16")] { 
     trivial_try_from_impl!(usize, u16, u32);
     trivial_try_from_impl!(isize, i16, i32);
     same_sign_try_from_wider_impl!(usize, u32, u64);
     same_sign_try_from_wider_impl!(isize, i32, i64);
}

// and so forth.

Copy link
Member

@nagisa nagisa Jul 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I believe the argument order is swapped for same_sign_try_from_wider_impl here and in the block above? Was looking at the wrong macro.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It make make it more readable yeah.

}

// Same for 32 and 64-bit platforms.
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] {
// xsize -> x16
same_sign_try_from_wider_impl!(u16, usize);
same_sign_try_from_wider_impl!(i16, isize);
// x32 -> xsize
trivial_try_from_impl!(u32, usize);
trivial_try_from_impl!(i32, isize);
}

// 64-bit.
#[cfg(target_pointer_width = "64")] {
// xsize -> x32
same_sign_try_from_wider_impl!(u32, usize);
same_sign_try_from_wider_impl!(i32, isize);
// x64 -> xsize
trivial_try_from_impl!(u64, usize);
trivial_try_from_impl!(i64, isize);
}
);

macro_rules! unsigned_from_signed_impl {
($unsigned:ty, $($signed:ty, $storage:ty),*) => {$(
#[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<$signed> for $unsigned {
type Error = TryFromIntError;

#[inline]
fn try_from(u: $signed) -> Result<$unsigned, TryFromIntError> {
let max = <$unsigned as FromStrRadixHelper>::max_value() as u128;
if u < 0 || u as u128 > max {
let max: $storage = <$unsigned>::max_value().into();
if u < 0 || u as $storage > max {
Err(TryFromIntError(()))
} else {
Ok(u as $unsigned)
Expand All @@ -2568,12 +2647,39 @@ macro_rules! cross_sign_from_int_impl {
)*}
}

cross_sign_from_int_impl!(u8, i8, i16, i32, i64, i128, isize);
cross_sign_from_int_impl!(u16, i8, i16, i32, i64, i128, isize);
cross_sign_from_int_impl!(u32, i8, i16, i32, i64, i128, isize);
cross_sign_from_int_impl!(u64, i8, i16, i32, i64, i128, isize);
cross_sign_from_int_impl!(u128, i8, i16, i32, i64, i128, isize);
cross_sign_from_int_impl!(usize, i8, i16, i32, i64, i128, isize);
macro_rules! signed_from_unsigned_impl {
($signed:ty, $($unsigned:ty, $storage:ty),*) => {$(
#[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<$unsigned> for $signed {
type Error = TryFromIntError;

#[inline]
fn try_from(u: $unsigned) -> Result<$signed, TryFromIntError> {
let max = <$signed>::max_value() as $storage;
if u as $storage > max {
Err(TryFromIntError(()))
} else {
Ok(u as $signed)
}
}
}
)*}
}

// (unsigned type, $(signed type, storage))
unsigned_from_signed_impl!(u8, i8, u8, i16, i16, i32, i32, i64, i64, i128, i128, isize, u64);
unsigned_from_signed_impl!(u16, i8, u16, i16, u16, i32, u32, i64, u64, i128, i128, isize, u64);
unsigned_from_signed_impl!(u32, i8, u32, i16, u32, i32, u32, i64, u64, i128, i128, isize, u64);
unsigned_from_signed_impl!(u64, i8, u64, i16, u64, i32, u64, i64, u64, i128, i128, isize, u64);
unsigned_from_signed_impl!(u128, i8, u128, i16, u128, i32, u128, i64, u128, i128, u128, isize,
u128);

// (signed type, $(unsigned type, storage))
signed_from_unsigned_impl!(i8, u8, u8, u16, u16, u32, u32, u64, u64, u128, u128, usize, usize);
signed_from_unsigned_impl!(i16, u16, u16, u32, u32, u64, u64, u128, u128, usize, usize);
signed_from_unsigned_impl!(i32, u32, u32, u64, u64, u128, u128, usize, usize);
signed_from_unsigned_impl!(i64, u64, u64, u128, u128, usize, usize);
signed_from_unsigned_impl!(i128, u128, u128);

#[doc(hidden)]
trait FromStrRadixHelper: PartialOrd + Copy {
Expand All @@ -2587,15 +2693,21 @@ trait FromStrRadixHelper: PartialOrd + Copy {

macro_rules! doit {
($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
#[inline]
fn min_value() -> Self { Self::min_value() }
#[inline]
fn max_value() -> Self { Self::max_value() }
#[inline]
fn from_u32(u: u32) -> Self { u as Self }
#[inline]
fn checked_mul(&self, other: u32) -> Option<Self> {
Self::checked_mul(*self, other as Self)
}
#[inline]
fn checked_sub(&self, other: u32) -> Option<Self> {
Self::checked_sub(*self, other as Self)
}
#[inline]
fn checked_add(&self, other: u32) -> Option<Self> {
Self::checked_add(*self, other as Self)
}
Expand Down