]> git.lizzy.rs Git - rust.git/blobdiff - src/libcore/time.rs
Move float ops to unstable inherent methods
[rust.git] / src / libcore / time.rs
index 563eea0066d59abdb10f5fdcd1bbe72c31a62c24..64cb13c7eae75f7477e81a3309284e7bca676fd1 100644 (file)
@@ -21,7 +21,7 @@
 //! assert_eq!(Duration::new(5, 0), Duration::from_secs(5));
 //! ```
 
-use fmt;
+use {fmt, u64};
 use iter::Sum;
 use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign};
 
@@ -30,6 +30,7 @@
 const NANOS_PER_MICRO: u32 = 1_000;
 const MILLIS_PER_SEC: u64 = 1_000;
 const MICROS_PER_SEC: u64 = 1_000_000;
+const MAX_NANOS_F64: f64 = ((u64::MAX as u128)*(NANOS_PER_SEC as u128)) as f64;
 
 /// A `Duration` type to represent a span of time, typically used for system
 /// timeouts.
@@ -208,7 +209,7 @@ pub const fn from_nanos(nanos: u64) -> Duration {
     #[inline]
     pub const fn as_secs(&self) -> u64 { self.secs }
 
-    /// Returns the fractional part of this `Duration`, in milliseconds.
+    /// Returns the fractional part of this `Duration`, in whole milliseconds.
     ///
     /// This method does **not** return the length of the duration when
     /// represented by milliseconds. The returned number always represents a
@@ -228,7 +229,7 @@ pub const fn as_secs(&self) -> u64 { self.secs }
     #[inline]
     pub const fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
 
-    /// Returns the fractional part of this `Duration`, in microseconds.
+    /// Returns the fractional part of this `Duration`, in whole microseconds.
     ///
     /// This method does **not** return the length of the duration when
     /// represented by microseconds. The returned number always represents a
@@ -268,7 +269,7 @@ pub const fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
     #[inline]
     pub const fn subsec_nanos(&self) -> u32 { self.nanos }
 
-    /// Returns the total number of milliseconds contained by this `Duration`.
+    /// Returns the total number of whole milliseconds contained by this `Duration`.
     ///
     /// # Examples
     ///
@@ -285,7 +286,7 @@ pub fn as_millis(&self) -> u128 {
         self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos / NANOS_PER_MILLI) as u128
     }
 
-    /// Returns the total number of microseconds contained by this `Duration`.
+    /// Returns the total number of whole microseconds contained by this `Duration`.
     ///
     /// # Examples
     ///
@@ -458,6 +459,88 @@ pub fn checked_div(self, rhs: u32) -> Option<Duration> {
             None
         }
     }
+
+    /// Multiply `Duration` by `f64`.
+    ///
+    /// # Examples
+    /// ```
+    /// let dur = Duration::new(2, 700_000_000);
+    /// assert_eq!(dur.mul_f64(3.14), Duration::new(8, 478_000_000));
+    /// assert_eq!(dur.mul_f64(3.14e5), Duration::new(847_800, 0));
+    /// ```
+    #[unstable(feature = "duration_float_ops",
+               reason = "duration/floats operations are unstabe",
+               issue = "0")]
+    #[inline]
+    pub fn mul_f64(self, rhs: f64) -> Duration {
+        const NPS: f64 = NANOS_PER_SEC as f64;
+        let nanos_f64 = rhs * (NPS * (self.secs as f64) + (self.nanos as f64));
+        if !nanos_f64.is_finite() {
+            panic!("got non-finite value when multiplying duration by float");
+        }
+        if nanos_f64 > MAX_NANOS_F64 {
+            panic!("overflow when multiplying duration by float");
+        }
+        if nanos_f64 < 0.0 {
+            panic!("underflow when multiplying duration by float");
+        }
+        let nanos_u128 = nanos_f64 as u128;
+        Duration {
+            secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64,
+            nanos: (nanos_u128 % (NANOS_PER_SEC as u128)) as u32,
+        }
+    }
+
+    /// Divide `Duration` by `f64`.
+    ///
+    /// # Examples
+    /// ```
+    /// let dur = Duration::new(2, 700_000_000);
+    /// assert_eq!(dur.div_f64(3.14), Duration::new(0, 859_872_611));
+    /// // note that truncation is used, not rounding
+    /// assert_eq!(dur.div_f64(3.14e5), Duration::new(0, 8_598));
+    /// ```
+    #[unstable(feature = "duration_float_ops",
+               reason = "duration/floats operations are unstabe",
+               issue = "0")]
+    #[inline]
+    pub fn div_f64(self, rhs: f64) -> Duration {
+        const NPS: f64 = NANOS_PER_SEC as f64;
+        let nanos_f64 = (NPS * (self.secs as f64) + (self.nanos as f64)) / rhs;
+        if !nanos_f64.is_finite() {
+            panic!("got non-finite value when dividing duration by float");
+        }
+        if nanos_f64 > MAX_NANOS_F64 {
+            panic!("overflow when dividing duration by float");
+        }
+        if nanos_f64 < 0.0 {
+            panic!("underflow when multiplying duration by float");
+        }
+        let nanos_u128 = nanos_f64 as u128;
+        Duration {
+            secs: (nanos_u128 / (NANOS_PER_SEC as u128)) as u64,
+            nanos: (nanos_u128 % (NANOS_PER_SEC as u128)) as u32,
+        }
+    }
+
+    /// Divide `Duration` by `Duration` and return `f64`.
+    ///
+    /// # Examples
+    /// ```
+    /// let dur1 = Duration::new(2, 700_000_000);
+    /// let dur2 = Duration::new(5, 400_000_000);
+    /// assert_eq!(dur1.div_duration(dur2), 0.5);
+    /// ```
+    #[unstable(feature = "duration_float_ops",
+               reason = "duration/floats operations are unstabe",
+               issue = "0")]
+    #[inline]
+    pub fn div_duration(self, rhs: Duration) -> f64 {
+        const NPS: f64 = NANOS_PER_SEC as f64;
+        let nanos1 = NPS * (self.secs as f64) + (self.nanos as f64);
+        let nanos2 = NPS * (rhs.secs as f64) + (rhs.nanos as f64);
+        nanos1/nanos2
+    }
 }
 
 #[stable(feature = "duration", since = "1.3.0")]
@@ -501,6 +584,15 @@ fn mul(self, rhs: u32) -> Duration {
     }
 }
 
+#[stable(feature = "symmetric_u32_duration_mul", since = "1.30.0")]
+impl Mul<Duration> for u32 {
+    type Output = Duration;
+
+    fn mul(self, rhs: Duration) -> Duration {
+        rhs * self
+    }
+}
+
 #[stable(feature = "time_augmented_assignment", since = "1.9.0")]
 impl MulAssign<u32> for Duration {
     fn mul_assign(&mut self, rhs: u32) {
@@ -524,17 +616,48 @@ fn div_assign(&mut self, rhs: u32) {
     }
 }
 
+
+macro_rules! sum_durations {
+    ($iter:expr) => {{
+        let mut total_secs: u64 = 0;
+        let mut total_nanos: u64 = 0;
+
+        for entry in $iter {
+            total_secs = total_secs
+                .checked_add(entry.secs)
+                .expect("overflow in iter::sum over durations");
+            total_nanos = match total_nanos.checked_add(entry.nanos as u64) {
+                Some(n) => n,
+                None => {
+                    total_secs = total_secs
+                        .checked_add(total_nanos / NANOS_PER_SEC as u64)
+                        .expect("overflow in iter::sum over durations");
+                    (total_nanos % NANOS_PER_SEC as u64) + entry.nanos as u64
+                }
+            };
+        }
+        total_secs = total_secs
+            .checked_add(total_nanos / NANOS_PER_SEC as u64)
+            .expect("overflow in iter::sum over durations");
+        total_nanos = total_nanos % NANOS_PER_SEC as u64;
+        Duration {
+            secs: total_secs,
+            nanos: total_nanos as u32,
+        }
+    }};
+}
+
 #[stable(feature = "duration_sum", since = "1.16.0")]
 impl Sum for Duration {
     fn sum<I: Iterator<Item=Duration>>(iter: I) -> Duration {
-        iter.fold(Duration::new(0, 0), |a, b| a + b)
+        sum_durations!(iter)
     }
 }
 
 #[stable(feature = "duration_sum", since = "1.16.0")]
 impl<'a> Sum<&'a Duration> for Duration {
     fn sum<I: Iterator<Item=&'a Duration>>(iter: I) -> Duration {
-        iter.fold(Duration::new(0, 0), |a, b| a + *b)
+        sum_durations!(iter)
     }
 }