|
@@ -6,17 +6,16 @@ use core::{i128, u128};
|
|
|
use core::{i16, i32, i64, i8, isize};
|
|
|
use core::{u16, u32, u64, u8, usize};
|
|
|
|
|
|
-use float::FloatCore;
|
|
|
-
|
|
|
/// A generic trait for converting a value to a number.
|
|
|
///
|
|
|
/// A value can be represented by the target type when it lies within
|
|
|
/// the range of scalars supported by the target type.
|
|
|
/// For example, a negative integer cannot be represented by an unsigned
|
|
|
-/// integer type, and an `f64` with a very high magnitude might not be
|
|
|
-/// convertible to an `f32`.
|
|
|
+/// integer type, and an `i64` with a very high magnitude might not be
|
|
|
+/// convertible to an `i32`.
|
|
|
/// On the other hand, conversions with possible precision loss or truncation
|
|
|
-/// (e.g. an `f32` with a decimal part to an integer type) are admitted.
|
|
|
+/// are admitted, like an `f32` with a decimal part to an integer type, or
|
|
|
+/// even a large `f64` saturating to `f32` infinity.
|
|
|
pub trait ToPrimitive {
|
|
|
/// Converts the value of `self` to an `isize`. If the value cannot be
|
|
|
/// represented by an `isize`, then `None` is returned.
|
|
@@ -102,7 +101,7 @@ pub trait ToPrimitive {
|
|
|
///
|
|
|
/// This method is only available with feature `i128` enabled on Rust >= 1.26.
|
|
|
///
|
|
|
- /// The default implementation converts through `to_u64()`. Types implementing
|
|
|
+ /// The default implementation converts through `to_u64()`. Types implementing
|
|
|
/// this trait should override this method if they can represent a greater range.
|
|
|
#[inline]
|
|
|
#[cfg(has_i128)]
|
|
@@ -110,15 +109,21 @@ pub trait ToPrimitive {
|
|
|
self.to_u64().map(From::from)
|
|
|
}
|
|
|
|
|
|
- /// Converts the value of `self` to an `f32`. If the value cannot be
|
|
|
- /// represented by an `f32`, then `None` is returned.
|
|
|
+ /// Converts the value of `self` to an `f32`. Overflows may map to positive
|
|
|
+ /// or negative inifinity, otherwise `None` is returned if the value cannot
|
|
|
+ /// be represented by an `f32`.
|
|
|
#[inline]
|
|
|
fn to_f32(&self) -> Option<f32> {
|
|
|
self.to_f64().as_ref().and_then(ToPrimitive::to_f32)
|
|
|
}
|
|
|
|
|
|
- /// Converts the value of `self` to an `f64`. If the value cannot be
|
|
|
- /// represented by an `f64`, then `None` is returned.
|
|
|
+ /// Converts the value of `self` to an `f64`. Overflows may map to positive
|
|
|
+ /// or negative inifinity, otherwise `None` is returned if the value cannot
|
|
|
+ /// be represented by an `f64`.
|
|
|
+ ///
|
|
|
+ /// The default implementation tries to convert through `to_i64()`, and
|
|
|
+ /// failing that through `to_u64()`. Types implementing this trait should
|
|
|
+ /// override this method if they can represent a greater range.
|
|
|
#[inline]
|
|
|
fn to_f64(&self) -> Option<f64> {
|
|
|
match self.to_i64() {
|
|
@@ -279,14 +284,8 @@ macro_rules! impl_to_primitive_float_to_float {
|
|
|
($SrcT:ident : $( fn $method:ident -> $DstT:ident ; )*) => {$(
|
|
|
#[inline]
|
|
|
fn $method(&self) -> Option<$DstT> {
|
|
|
- // Only finite values that are reducing size need to worry about overflow.
|
|
|
- if size_of::<$SrcT>() > size_of::<$DstT>() && FloatCore::is_finite(*self) {
|
|
|
- let n = *self as f64;
|
|
|
- if n < $DstT::MIN as f64 || n > $DstT::MAX as f64 {
|
|
|
- return None;
|
|
|
- }
|
|
|
- }
|
|
|
- // We can safely cast NaN, +-inf, and finite values in range.
|
|
|
+ // We can safely cast all values, whether NaN, +-inf, or finite.
|
|
|
+ // Finite values that are reducing size may saturate to +-inf.
|
|
|
Some(*self as $DstT)
|
|
|
}
|
|
|
)*}
|
|
@@ -404,10 +403,11 @@ impl_to_primitive_float!(f64);
|
|
|
/// A value can be represented by the target type when it lies within
|
|
|
/// the range of scalars supported by the target type.
|
|
|
/// For example, a negative integer cannot be represented by an unsigned
|
|
|
-/// integer type, and an `f64` with a very high magnitude might not be
|
|
|
-/// convertible to an `f32`.
|
|
|
+/// integer type, and an `i64` with a very high magnitude might not be
|
|
|
+/// convertible to an `i32`.
|
|
|
/// On the other hand, conversions with possible precision loss or truncation
|
|
|
-/// (e.g. an `f32` with a decimal part to an integer type) are admitted.
|
|
|
+/// are admitted, like an `f32` with a decimal part to an integer type, or
|
|
|
+/// even a large `f64` saturating to `f32` infinity.
|
|
|
pub trait FromPrimitive: Sized {
|
|
|
/// Converts an `isize` to return an optional value of this type. If the
|
|
|
/// value cannot be represented by this type, then `None` is returned.
|
|
@@ -508,6 +508,10 @@ pub trait FromPrimitive: Sized {
|
|
|
|
|
|
/// Converts a `f64` to return an optional value of this type. If the
|
|
|
/// value cannot be represented by this type, then `None` is returned.
|
|
|
+ ///
|
|
|
+ /// The default implementation tries to convert through `from_i64()`, and
|
|
|
+ /// failing that through `from_u64()`. Types implementing this trait should
|
|
|
+ /// override this method if they can represent a greater range.
|
|
|
#[inline]
|
|
|
fn from_f64(n: f64) -> Option<Self> {
|
|
|
match n.to_i64() {
|
|
@@ -692,10 +696,11 @@ pub trait NumCast: Sized + ToPrimitive {
|
|
|
/// A value can be represented by the target type when it lies within
|
|
|
/// the range of scalars supported by the target type.
|
|
|
/// For example, a negative integer cannot be represented by an unsigned
|
|
|
- /// integer type, and an `f64` with a very high magnitude might not be
|
|
|
- /// convertible to an `f32`.
|
|
|
+ /// integer type, and an `i64` with a very high magnitude might not be
|
|
|
+ /// convertible to an `i32`.
|
|
|
/// On the other hand, conversions with possible precision loss or truncation
|
|
|
- /// (e.g. an `f32` with a decimal part to an integer type) are admitted.
|
|
|
+ /// are admitted, like an `f32` with a decimal part to an integer type, or
|
|
|
+ /// even a large `f64` saturating to `f32` infinity.
|
|
|
fn from<T: ToPrimitive>(n: T) -> Option<Self>;
|
|
|
}
|
|
|
|