Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TryFrom implementation for bool, f32 and f64 #43220

Closed
wants to merge 1 commit into from
Closed
Changes from all 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
113 changes: 113 additions & 0 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2504,6 +2504,53 @@ impl fmt::Display for TryFromIntError {
}
}

/// This error will actually never be returned.
#[unstable(feature = "try_from", issue = "33417")]
#[derive(Debug, Copy, Clone)]
pub struct TryFromBoolError {}

impl TryFromBoolError {
#[unstable(feature = "bool_error_internals",
reason = "available through Error trait and this method should \
not be exposed publicly",
issue = "0")]
#[doc(hidden)]
pub fn __description(&self) -> &str {
"should not be used"
}
}

#[unstable(feature = "try_from", issue = "33417")]
impl fmt::Display for TryFromBoolError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.__description().fmt(fmt)
}
}

#[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<bool> for bool {
type Error = TryFromBoolError;

fn try_from(u: bool) -> Result<bool, TryFromBoolError> {
Copy link
Contributor

Choose a reason for hiding this comment

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

May want to add [inline] here. At least for the integer types, the calls to try_from() didn't inline properly without having [inline], so it might be similar for bool/float.

Ok(u)
}
}

macro_rules! try_from_for_bool {
($($source:ty),*) => {$(
#[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<$source> for bool {
type Error = TryFromBoolError;

fn try_from(u: $source) -> Result<bool, TryFromBoolError> {
Ok(u != 0)
}
}
)*}
}

try_from_for_bool!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);

macro_rules! same_sign_try_from_int_impl {
($storage:ty, $target:ty, $($source:ty),*) => {$(
#[unstable(feature = "try_from", issue = "33417")]
Expand Down Expand Up @@ -2536,6 +2583,19 @@ 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);

same_sign_try_from_int_impl!(f64, usize, f32, f64);
same_sign_try_from_int_impl!(f64, isize, f32, f64);
same_sign_try_from_int_impl!(f64, i128, f32, f64);
same_sign_try_from_int_impl!(f64, u128, f32, f64);
same_sign_try_from_int_impl!(f64, i64, f32, f64);
same_sign_try_from_int_impl!(f64, u64, f32, f64);
same_sign_try_from_int_impl!(f64, i32, f32, f64);
same_sign_try_from_int_impl!(f64, u32, f32, f64);
same_sign_try_from_int_impl!(f64, i16, f32, f64);
same_sign_try_from_int_impl!(f64, u16, f32, f64);
same_sign_try_from_int_impl!(f64, i8, f32, f64);
same_sign_try_from_int_impl!(f64, u8, f32, f64);
Copy link
Member

Choose a reason for hiding this comment

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

For what it's worth the bounds for these conversions are wrong. NaN needs to be taken into account. Also float to int conversions round towards 0 so for example -0.9 as u8 == 0 and 255.9 as u8 == 255 so the bounds need to allow that.


macro_rules! cross_sign_from_int_impl {
($unsigned:ty, $($signed:ty),*) => {$(
#[unstable(feature = "try_from", issue = "33417")]
Expand Down Expand Up @@ -2575,6 +2635,59 @@ 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);

/// The error type returned when a checked floating type conversion fails.
#[unstable(feature = "try_from", issue = "33417")]
#[derive(Debug, Copy, Clone)]
pub struct TryFromFloatError(());

impl TryFromFloatError {
#[unstable(feature = "float_error_internals",
reason = "available through Error trait and this method should \
not be exposed publicly",
issue = "0")]
#[doc(hidden)]
pub fn __description(&self) -> &str {
"out of range floating type conversion attempted"
}
}

#[unstable(feature = "try_from", issue = "33417")]
impl fmt::Display for TryFromFloatError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.__description().fmt(fmt)
}
}

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

fn try_from(u: $source) -> Result<$target, TryFromFloatError> {
use $target;

if u.is_nan() {
Ok($target::NAN)
} else if u.is_infinite() {
Ok($target::INFINITY)
} else {
let min = $target::MIN as $storage;
let max = $target::MAX as $storage;
if u as $storage < min || u as $storage > max {
Copy link
Member

Choose a reason for hiding this comment

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

These bounds are also wrong for f64 to f32 which is the only conversion that actually needs a manual TryFrom conversion. The source value is rounded when casting to f32 so some values larger than f32::MAX as f64 will round down to f32::MAX. How fptrunc performs this rounding is apparently undefined so I'm not completely sure what the bounds will need to be though.

Err(TryFromFloatError(()))
} else {
Ok(u as $target)
}
}
}
}
)*}
}

try_from_float_impl!(f64, f32, f32, f64);
try_from_float_impl!(f64, f64, f32, f64);

#[doc(hidden)]
trait FromStrRadixHelper: PartialOrd + Copy {
fn min_value() -> Self;
Expand Down