瀏覽代碼

Auto merge of #180 - bluss:fix-toprimitive-float, r=cuviper

Fix ToPrimitive for f64 -> f32 conversion.

Fix ToPrimitive for f64 -> f32 conversion.

It should use the destination type and not the source type to check if
the conversion would be to a value that's in range.

NOTE: A finite f64 value that is larger than the f32 value range now produces
None when converted to f32 with ToPrimitive.

Previously, too large f64 values would produce inf f32 values. This `as`
cast has an undefined result and was not specified to always produce for
example `inf`.

The conversion preserves nan/+-inf specifically.
Homu 9 年之前
父節點
當前提交
0861fb4cfb
共有 1 個文件被更改,包括 19 次插入2 次删除
  1. 19 2
      traits/src/cast.rs

+ 19 - 2
traits/src/cast.rs

@@ -222,9 +222,11 @@ macro_rules! impl_to_primitive_float_to_float {
         if size_of::<$SrcT>() <= size_of::<$DstT>() {
             Some($slf as $DstT)
         } else {
+            // Make sure the value is in range for the cast.
+            // NaN and +-inf are cast as they are.
             let n = $slf as f64;
-            let max_value: $SrcT = ::std::$SrcT::MAX;
-            if -max_value as f64 <= n && n <= max_value as f64 {
+            let max_value: $DstT = ::std::$DstT::MAX;
+            if !n.is_finite() || (-max_value as f64 <= n && n <= max_value as f64) {
                 Some($slf as $DstT)
             } else {
                 None
@@ -431,3 +433,18 @@ impl_num_cast!(i64,   to_i64);
 impl_num_cast!(isize, to_isize);
 impl_num_cast!(f32,   to_f32);
 impl_num_cast!(f64,   to_f64);
+
+
+#[test]
+fn to_primitive_float() {
+    use std::f32;
+    use std::f64;
+
+    let f32_toolarge = 1e39f64;
+    assert_eq!(f32_toolarge.to_f32(), None);
+    assert_eq!((f32::MAX as f64).to_f32(), Some(f32::MAX));
+    assert_eq!((-f32::MAX as f64).to_f32(), Some(-f32::MAX));
+    assert_eq!(f64::INFINITY.to_f32(), Some(f32::INFINITY));
+    assert_eq!((f64::NEG_INFINITY).to_f32(), Some(f32::NEG_INFINITY));
+    assert!((f64::NAN).to_f32().map_or(false, |f| f.is_nan()));
+}