2014-07-14 19:18:07 -07:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
//! Temporal quantification
|
|
|
|
|
|
|
|
#![experimental]
|
|
|
|
|
2014-08-19 14:32:20 +02:00
|
|
|
use {fmt, i64};
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 17:01:33 -08:00
|
|
|
use kinds::Copy;
|
2014-12-07 14:15:25 -05:00
|
|
|
use ops::{Add, Sub, Mul, Div, Neg, FnOnce};
|
2014-11-28 11:57:41 -05:00
|
|
|
use option::Option;
|
|
|
|
use option::Option::{Some, None};
|
2014-11-10 00:11:28 +11:00
|
|
|
use num::Int;
|
2014-11-28 11:57:41 -05:00
|
|
|
use result::Result;
|
|
|
|
use result::Result::{Ok, Err};
|
2014-07-14 19:18:07 -07:00
|
|
|
|
2014-08-19 14:32:20 +02:00
|
|
|
/// The number of nanoseconds in a microsecond.
|
2014-10-06 16:29:47 -07:00
|
|
|
const NANOS_PER_MICRO: i32 = 1000;
|
2014-09-02 01:35:58 -04:00
|
|
|
/// The number of nanoseconds in a millisecond.
|
2014-10-06 16:29:47 -07:00
|
|
|
const NANOS_PER_MILLI: i32 = 1000_000;
|
2014-07-28 15:54:05 -07:00
|
|
|
/// The number of nanoseconds in seconds.
|
2014-10-06 16:29:47 -07:00
|
|
|
const NANOS_PER_SEC: i32 = 1_000_000_000;
|
2014-08-19 14:32:20 +02:00
|
|
|
/// The number of microseconds per second.
|
2014-10-06 16:29:47 -07:00
|
|
|
const MICROS_PER_SEC: i64 = 1000_000;
|
2014-08-19 14:32:20 +02:00
|
|
|
/// The number of milliseconds per second.
|
2014-10-06 16:29:47 -07:00
|
|
|
const MILLIS_PER_SEC: i64 = 1000;
|
2014-08-19 14:32:20 +02:00
|
|
|
/// The number of seconds in a minute.
|
2014-10-06 16:29:47 -07:00
|
|
|
const SECS_PER_MINUTE: i64 = 60;
|
2014-08-19 14:32:20 +02:00
|
|
|
/// The number of seconds in an hour.
|
2014-10-06 16:29:47 -07:00
|
|
|
const SECS_PER_HOUR: i64 = 3600;
|
2014-07-28 15:54:05 -07:00
|
|
|
/// The number of (non-leap) seconds in days.
|
2014-10-06 16:29:47 -07:00
|
|
|
const SECS_PER_DAY: i64 = 86400;
|
2014-08-19 14:32:20 +02:00
|
|
|
/// The number of (non-leap) seconds in a week.
|
2014-10-06 16:29:47 -07:00
|
|
|
const SECS_PER_WEEK: i64 = 604800;
|
2014-07-14 19:18:07 -07:00
|
|
|
|
2014-07-28 15:54:05 -07:00
|
|
|
macro_rules! try_opt(
|
2014-07-14 19:18:07 -07:00
|
|
|
($e:expr) => (match $e { Some(v) => v, None => return None })
|
|
|
|
)
|
|
|
|
|
2014-08-12 16:25:21 -07:00
|
|
|
|
2014-07-28 15:54:05 -07:00
|
|
|
/// ISO 8601 time duration with nanosecond precision.
|
|
|
|
/// This also allows for the negative duration; see individual methods for details.
|
2014-08-15 07:23:51 -07:00
|
|
|
#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
2014-07-14 19:18:07 -07:00
|
|
|
pub struct Duration {
|
2014-08-19 14:32:20 +02:00
|
|
|
secs: i64,
|
|
|
|
nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
2014-08-21 09:37:30 +02:00
|
|
|
/// The minimum possible `Duration`: `i64::MIN` milliseconds.
|
2014-10-06 16:29:47 -07:00
|
|
|
pub const MIN: Duration = Duration {
|
2014-08-21 09:37:30 +02:00
|
|
|
secs: i64::MIN / MILLIS_PER_SEC - 1,
|
|
|
|
nanos: NANOS_PER_SEC + (i64::MIN % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI
|
|
|
|
};
|
|
|
|
|
|
|
|
/// The maximum possible `Duration`: `i64::MAX` milliseconds.
|
2014-10-06 16:29:47 -07:00
|
|
|
pub const MAX: Duration = Duration {
|
2014-08-21 09:37:30 +02:00
|
|
|
secs: i64::MAX / MILLIS_PER_SEC,
|
|
|
|
nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI
|
|
|
|
};
|
2014-07-28 15:54:05 -07:00
|
|
|
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 17:01:33 -08:00
|
|
|
impl Copy for Duration {}
|
|
|
|
|
2014-07-14 19:18:07 -07:00
|
|
|
impl Duration {
|
2014-07-28 15:54:05 -07:00
|
|
|
/// Makes a new `Duration` with given number of weeks.
|
2014-08-19 14:32:20 +02:00
|
|
|
/// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60), with overflow checks.
|
2014-11-08 21:17:51 +05:30
|
|
|
/// Panics when the duration is out of bounds.
|
2014-07-14 19:18:07 -07:00
|
|
|
#[inline]
|
2014-08-19 14:32:20 +02:00
|
|
|
pub fn weeks(weeks: i64) -> Duration {
|
2014-11-10 00:11:28 +11:00
|
|
|
let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds");
|
2014-08-19 14:32:20 +02:00
|
|
|
Duration::seconds(secs)
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
2014-07-28 15:54:05 -07:00
|
|
|
/// Makes a new `Duration` with given number of days.
|
2014-08-19 14:32:20 +02:00
|
|
|
/// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks.
|
2014-11-08 21:17:51 +05:30
|
|
|
/// Panics when the duration is out of bounds.
|
2014-07-14 19:18:07 -07:00
|
|
|
#[inline]
|
2014-08-19 14:32:20 +02:00
|
|
|
pub fn days(days: i64) -> Duration {
|
2014-11-10 00:11:28 +11:00
|
|
|
let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds");
|
2014-08-19 14:32:20 +02:00
|
|
|
Duration::seconds(secs)
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
2014-07-28 15:54:05 -07:00
|
|
|
/// Makes a new `Duration` with given number of hours.
|
2014-08-19 14:32:20 +02:00
|
|
|
/// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks.
|
2014-11-08 21:17:51 +05:30
|
|
|
/// Panics when the duration is out of bounds.
|
2014-07-14 19:18:07 -07:00
|
|
|
#[inline]
|
2014-08-19 14:32:20 +02:00
|
|
|
pub fn hours(hours: i64) -> Duration {
|
2014-11-10 00:11:28 +11:00
|
|
|
let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds");
|
2014-08-19 14:32:20 +02:00
|
|
|
Duration::seconds(secs)
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
2014-07-28 15:54:05 -07:00
|
|
|
/// Makes a new `Duration` with given number of minutes.
|
2014-08-19 14:32:20 +02:00
|
|
|
/// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks.
|
2014-11-08 21:17:51 +05:30
|
|
|
/// Panics when the duration is out of bounds.
|
2014-07-14 19:18:07 -07:00
|
|
|
#[inline]
|
2014-08-19 14:32:20 +02:00
|
|
|
pub fn minutes(minutes: i64) -> Duration {
|
2014-11-10 00:11:28 +11:00
|
|
|
let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds");
|
2014-08-19 14:32:20 +02:00
|
|
|
Duration::seconds(secs)
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
2014-07-28 15:54:05 -07:00
|
|
|
/// Makes a new `Duration` with given number of seconds.
|
2014-11-08 21:17:51 +05:30
|
|
|
/// Panics when the duration is more than `i64::MAX` milliseconds
|
2014-08-21 09:37:30 +02:00
|
|
|
/// or less than `i64::MIN` milliseconds.
|
2014-07-14 19:18:07 -07:00
|
|
|
#[inline]
|
2014-08-19 14:32:20 +02:00
|
|
|
pub fn seconds(seconds: i64) -> Duration {
|
2014-08-21 09:37:30 +02:00
|
|
|
let d = Duration { secs: seconds, nanos: 0 };
|
|
|
|
if d < MIN || d > MAX {
|
2014-10-09 15:17:22 -04:00
|
|
|
panic!("Duration::seconds out of bounds");
|
2014-08-21 09:37:30 +02:00
|
|
|
}
|
|
|
|
d
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
2014-07-28 15:54:05 -07:00
|
|
|
/// Makes a new `Duration` with given number of milliseconds.
|
2014-07-14 19:18:07 -07:00
|
|
|
#[inline]
|
2014-08-19 14:32:20 +02:00
|
|
|
pub fn milliseconds(milliseconds: i64) -> Duration {
|
|
|
|
let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC);
|
|
|
|
let nanos = millis as i32 * NANOS_PER_MILLI;
|
|
|
|
Duration { secs: secs, nanos: nanos }
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
2014-07-28 15:54:05 -07:00
|
|
|
/// Makes a new `Duration` with given number of microseconds.
|
2014-07-14 19:18:07 -07:00
|
|
|
#[inline]
|
2014-08-19 14:32:20 +02:00
|
|
|
pub fn microseconds(microseconds: i64) -> Duration {
|
|
|
|
let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
|
|
|
|
let nanos = micros as i32 * NANOS_PER_MICRO;
|
|
|
|
Duration { secs: secs, nanos: nanos }
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
2014-07-28 15:54:05 -07:00
|
|
|
/// Makes a new `Duration` with given number of nanoseconds.
|
2014-07-14 19:18:07 -07:00
|
|
|
#[inline]
|
2014-08-19 14:32:20 +02:00
|
|
|
pub fn nanoseconds(nanos: i64) -> Duration {
|
|
|
|
let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64);
|
|
|
|
Duration { secs: secs, nanos: nanos as i32 }
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
2014-11-10 12:27:56 -08:00
|
|
|
/// Runs a closure, returning the duration of time it took to run the
|
|
|
|
/// closure.
|
2014-12-07 14:15:25 -05:00
|
|
|
pub fn span<F>(f: F) -> Duration where F: FnOnce() {
|
2014-11-10 12:27:56 -08:00
|
|
|
let before = super::precise_time_ns();
|
|
|
|
f();
|
2014-11-13 08:48:38 -08:00
|
|
|
Duration::nanoseconds((super::precise_time_ns() - before) as i64)
|
2014-11-10 12:27:56 -08:00
|
|
|
}
|
|
|
|
|
2014-07-28 15:54:05 -07:00
|
|
|
/// Returns the total number of whole weeks in the duration.
|
2014-07-14 19:18:07 -07:00
|
|
|
#[inline]
|
2014-08-19 14:32:20 +02:00
|
|
|
pub fn num_weeks(&self) -> i64 {
|
2014-07-28 15:54:05 -07:00
|
|
|
self.num_days() / 7
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the total number of whole days in the duration.
|
2014-08-19 14:32:20 +02:00
|
|
|
pub fn num_days(&self) -> i64 {
|
|
|
|
self.num_seconds() / SECS_PER_DAY
|
2014-07-28 15:54:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the total number of whole hours in the duration.
|
|
|
|
#[inline]
|
|
|
|
pub fn num_hours(&self) -> i64 {
|
2014-08-19 14:32:20 +02:00
|
|
|
self.num_seconds() / SECS_PER_HOUR
|
2014-07-28 15:54:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the total number of whole minutes in the duration.
|
|
|
|
#[inline]
|
|
|
|
pub fn num_minutes(&self) -> i64 {
|
2014-08-19 14:32:20 +02:00
|
|
|
self.num_seconds() / SECS_PER_MINUTE
|
2014-07-28 15:54:05 -07:00
|
|
|
}
|
|
|
|
|
2014-08-07 18:22:31 -07:00
|
|
|
/// Returns the total number of whole seconds in the duration.
|
2014-07-28 15:54:05 -07:00
|
|
|
pub fn num_seconds(&self) -> i64 {
|
2014-08-19 14:32:20 +02:00
|
|
|
// If secs is negative, nanos should be subtracted from the duration.
|
|
|
|
if self.secs < 0 && self.nanos > 0 {
|
|
|
|
self.secs + 1
|
|
|
|
} else {
|
|
|
|
self.secs
|
2014-07-28 15:54:05 -07:00
|
|
|
}
|
2014-08-19 14:32:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the number of nanoseconds such that
|
|
|
|
/// `nanos_mod_sec() + num_seconds() * NANOS_PER_SEC` is the total number of
|
|
|
|
/// nanoseconds in the duration.
|
|
|
|
fn nanos_mod_sec(&self) -> i32 {
|
|
|
|
if self.secs < 0 && self.nanos > 0 {
|
|
|
|
self.nanos - NANOS_PER_SEC
|
|
|
|
} else {
|
|
|
|
self.nanos
|
2014-07-28 15:54:05 -07:00
|
|
|
}
|
2014-08-19 14:32:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the total number of whole milliseconds in the duration,
|
2014-08-21 09:37:30 +02:00
|
|
|
pub fn num_milliseconds(&self) -> i64 {
|
|
|
|
// A proper Duration will not overflow, because MIN and MAX are defined
|
|
|
|
// such that the range is exactly i64 milliseconds.
|
|
|
|
let secs_part = self.num_seconds() * MILLIS_PER_SEC;
|
2014-08-19 14:32:20 +02:00
|
|
|
let nanos_part = self.nanos_mod_sec() / NANOS_PER_MILLI;
|
2014-08-21 09:37:30 +02:00
|
|
|
secs_part + nanos_part as i64
|
2014-07-28 15:54:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the total number of whole microseconds in the duration,
|
2014-08-19 14:32:20 +02:00
|
|
|
/// or `None` on overflow (exceeding 2^63 microseconds in either direction).
|
2014-07-28 15:54:05 -07:00
|
|
|
pub fn num_microseconds(&self) -> Option<i64> {
|
2014-11-10 00:11:28 +11:00
|
|
|
let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC));
|
2014-08-19 14:32:20 +02:00
|
|
|
let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO;
|
2014-11-10 00:11:28 +11:00
|
|
|
secs_part.checked_add(nanos_part as i64)
|
2014-07-28 15:54:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the total number of whole nanoseconds in the duration,
|
2014-08-19 14:32:20 +02:00
|
|
|
/// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
|
2014-07-28 15:54:05 -07:00
|
|
|
pub fn num_nanoseconds(&self) -> Option<i64> {
|
2014-11-10 00:11:28 +11:00
|
|
|
let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64));
|
2014-08-19 14:32:20 +02:00
|
|
|
let nanos_part = self.nanos_mod_sec();
|
2014-11-10 00:11:28 +11:00
|
|
|
secs_part.checked_add(nanos_part as i64)
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
2014-11-10 00:11:28 +11:00
|
|
|
/// Add two durations, returning `None` if overflow occured.
|
|
|
|
pub fn checked_add(&self, rhs: &Duration) -> Option<Duration> {
|
|
|
|
let mut secs = try_opt!(self.secs.checked_add(rhs.secs));
|
|
|
|
let mut nanos = self.nanos + rhs.nanos;
|
|
|
|
if nanos >= NANOS_PER_SEC {
|
|
|
|
nanos -= NANOS_PER_SEC;
|
|
|
|
secs = try_opt!(secs.checked_add(1));
|
|
|
|
}
|
|
|
|
let d = Duration { secs: secs, nanos: nanos };
|
|
|
|
// Even if d is within the bounds of i64 seconds,
|
|
|
|
// it might still overflow i64 milliseconds.
|
|
|
|
if d < MIN || d > MAX { None } else { Some(d) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Subtract two durations, returning `None` if overflow occured.
|
|
|
|
pub fn checked_sub(&self, rhs: &Duration) -> Option<Duration> {
|
|
|
|
let mut secs = try_opt!(self.secs.checked_sub(rhs.secs));
|
|
|
|
let mut nanos = self.nanos - rhs.nanos;
|
|
|
|
if nanos < 0 {
|
|
|
|
nanos += NANOS_PER_SEC;
|
|
|
|
secs = try_opt!(secs.checked_sub(1));
|
|
|
|
}
|
|
|
|
let d = Duration { secs: secs, nanos: nanos };
|
|
|
|
// Even if d is within the bounds of i64 seconds,
|
|
|
|
// it might still overflow i64 milliseconds.
|
|
|
|
if d < MIN || d > MAX { None } else { Some(d) }
|
|
|
|
}
|
2014-07-28 15:54:05 -07:00
|
|
|
|
2014-11-10 00:11:28 +11:00
|
|
|
/// The minimum possible `Duration`: `i64::MIN` milliseconds.
|
2014-07-14 19:18:07 -07:00
|
|
|
#[inline]
|
2014-11-10 00:11:28 +11:00
|
|
|
pub fn min_value() -> Duration { MIN }
|
|
|
|
|
|
|
|
/// The maximum possible `Duration`: `i64::MAX` milliseconds.
|
|
|
|
#[inline]
|
|
|
|
pub fn max_value() -> Duration { MAX }
|
|
|
|
|
|
|
|
/// A duration where the stored seconds and nanoseconds are equal to zero.
|
|
|
|
#[inline]
|
|
|
|
pub fn zero() -> Duration {
|
2014-08-19 14:32:20 +02:00
|
|
|
Duration { secs: 0, nanos: 0 }
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
2014-11-10 00:11:28 +11:00
|
|
|
/// Returns `true` if the duration equals `Duration::zero()`.
|
2014-07-14 19:18:07 -07:00
|
|
|
#[inline]
|
2014-11-10 00:11:28 +11:00
|
|
|
pub fn is_zero(&self) -> bool {
|
2014-08-19 14:32:20 +02:00
|
|
|
self.secs == 0 && self.nanos == 0
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Neg<Duration> for Duration {
|
2014-07-28 15:54:05 -07:00
|
|
|
#[inline]
|
2014-07-14 19:18:07 -07:00
|
|
|
fn neg(&self) -> Duration {
|
2014-08-21 09:37:30 +02:00
|
|
|
if self.nanos == 0 {
|
2014-08-19 14:32:20 +02:00
|
|
|
Duration { secs: -self.secs, nanos: 0 }
|
|
|
|
} else {
|
|
|
|
Duration { secs: -self.secs - 1, nanos: NANOS_PER_SEC - self.nanos }
|
|
|
|
}
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Add<Duration,Duration> for Duration {
|
|
|
|
fn add(&self, rhs: &Duration) -> Duration {
|
|
|
|
let mut secs = self.secs + rhs.secs;
|
|
|
|
let mut nanos = self.nanos + rhs.nanos;
|
2014-08-19 14:32:20 +02:00
|
|
|
if nanos >= NANOS_PER_SEC {
|
|
|
|
nanos -= NANOS_PER_SEC;
|
2014-07-14 19:18:07 -07:00
|
|
|
secs += 1;
|
|
|
|
}
|
2014-08-19 14:32:20 +02:00
|
|
|
Duration { secs: secs, nanos: nanos }
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Sub<Duration,Duration> for Duration {
|
|
|
|
fn sub(&self, rhs: &Duration) -> Duration {
|
2014-08-19 14:32:20 +02:00
|
|
|
let mut secs = self.secs - rhs.secs;
|
|
|
|
let mut nanos = self.nanos - rhs.nanos;
|
2014-07-14 19:18:07 -07:00
|
|
|
if nanos < 0 {
|
|
|
|
nanos += NANOS_PER_SEC;
|
|
|
|
secs -= 1;
|
|
|
|
}
|
2014-08-19 14:32:20 +02:00
|
|
|
Duration { secs: secs, nanos: nanos }
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Mul<i32,Duration> for Duration {
|
|
|
|
fn mul(&self, rhs: &i32) -> Duration {
|
2014-08-19 14:32:20 +02:00
|
|
|
// Multiply nanoseconds as i64, because it cannot overflow that way.
|
|
|
|
let total_nanos = self.nanos as i64 * *rhs as i64;
|
|
|
|
let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64);
|
|
|
|
let secs = self.secs * *rhs as i64 + extra_secs;
|
|
|
|
Duration { secs: secs, nanos: nanos as i32 }
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Div<i32,Duration> for Duration {
|
|
|
|
fn div(&self, rhs: &i32) -> Duration {
|
2014-08-19 14:32:20 +02:00
|
|
|
let mut secs = self.secs / *rhs as i64;
|
|
|
|
let carry = self.secs - secs * *rhs as i64;
|
|
|
|
let extra_nanos = carry * NANOS_PER_SEC as i64 / *rhs as i64;
|
|
|
|
let mut nanos = self.nanos / *rhs + extra_nanos as i32;
|
|
|
|
if nanos >= NANOS_PER_SEC {
|
|
|
|
nanos -= NANOS_PER_SEC;
|
|
|
|
secs += 1;
|
|
|
|
}
|
|
|
|
if nanos < 0 {
|
|
|
|
nanos += NANOS_PER_SEC;
|
|
|
|
secs -= 1;
|
|
|
|
}
|
|
|
|
Duration { secs: secs, nanos: nanos }
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Show for Duration {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2014-10-27 09:28:24 +07:00
|
|
|
// technically speaking, negative duration is not valid ISO 8601,
|
|
|
|
// but we need to print it anyway.
|
2014-10-31 05:40:15 -04:00
|
|
|
let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") };
|
2014-10-27 09:28:24 +07:00
|
|
|
|
|
|
|
let days = abs.secs / SECS_PER_DAY;
|
|
|
|
let secs = abs.secs - days * SECS_PER_DAY;
|
2014-08-19 14:32:20 +02:00
|
|
|
let hasdate = days != 0;
|
2014-10-27 09:28:24 +07:00
|
|
|
let hastime = (secs != 0 || abs.nanos != 0) || !hasdate;
|
|
|
|
|
|
|
|
try!(write!(f, "{}P", sign));
|
2014-07-14 19:18:07 -07:00
|
|
|
|
|
|
|
if hasdate {
|
2014-08-19 14:32:20 +02:00
|
|
|
try!(write!(f, "{}D", days));
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
if hastime {
|
2014-10-27 09:28:24 +07:00
|
|
|
if abs.nanos == 0 {
|
2014-08-19 14:32:20 +02:00
|
|
|
try!(write!(f, "T{}S", secs));
|
2014-10-27 09:28:24 +07:00
|
|
|
} else if abs.nanos % NANOS_PER_MILLI == 0 {
|
|
|
|
try!(write!(f, "T{}.{:03}S", secs, abs.nanos / NANOS_PER_MILLI));
|
|
|
|
} else if abs.nanos % NANOS_PER_MICRO == 0 {
|
|
|
|
try!(write!(f, "T{}.{:06}S", secs, abs.nanos / NANOS_PER_MICRO));
|
2014-07-14 19:18:07 -07:00
|
|
|
} else {
|
2014-10-27 09:28:24 +07:00
|
|
|
try!(write!(f, "T{}.{:09}S", secs, abs.nanos));
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copied from libnum
|
|
|
|
#[inline]
|
|
|
|
fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
|
|
|
|
(div_floor_64(this, other), mod_floor_64(this, other))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn div_floor_64(this: i64, other: i64) -> i64 {
|
|
|
|
match div_rem_64(this, other) {
|
|
|
|
(d, r) if (r > 0 && other < 0)
|
|
|
|
|| (r < 0 && other > 0) => d - 1,
|
|
|
|
(d, _) => d,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn mod_floor_64(this: i64, other: i64) -> i64 {
|
|
|
|
match this % other {
|
|
|
|
r if (r > 0 && other < 0)
|
|
|
|
|| (r < 0 && other > 0) => r + other,
|
|
|
|
r => r,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
|
|
|
|
(this / other, this % other)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2014-08-19 14:32:20 +02:00
|
|
|
use super::{Duration, MIN, MAX};
|
2014-07-30 20:07:41 -07:00
|
|
|
use {i32, i64};
|
2014-11-28 11:57:41 -05:00
|
|
|
use option::Option::{Some, None};
|
2014-11-16 12:38:03 +11:00
|
|
|
use string::ToString;
|
2014-07-14 19:18:07 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_duration() {
|
2014-11-10 00:11:28 +11:00
|
|
|
assert!(Duration::seconds(1) != Duration::zero());
|
2014-07-14 19:18:07 -07:00
|
|
|
assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3));
|
|
|
|
assert_eq!(Duration::seconds(86399) + Duration::seconds(4),
|
|
|
|
Duration::days(1) + Duration::seconds(3));
|
|
|
|
assert_eq!(Duration::days(10) - Duration::seconds(1000), Duration::seconds(863000));
|
|
|
|
assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000));
|
2014-08-28 21:56:27 +02:00
|
|
|
assert_eq!(Duration::days(2) + Duration::seconds(86399) +
|
|
|
|
Duration::nanoseconds(1234567890),
|
2014-07-14 19:18:07 -07:00
|
|
|
Duration::days(3) + Duration::nanoseconds(234567890));
|
|
|
|
assert_eq!(-Duration::days(3), Duration::days(-3));
|
|
|
|
assert_eq!(-(Duration::days(3) + Duration::seconds(70)),
|
|
|
|
Duration::days(-4) + Duration::seconds(86400-70));
|
|
|
|
}
|
|
|
|
|
2014-07-28 15:54:05 -07:00
|
|
|
#[test]
|
|
|
|
fn test_duration_num_days() {
|
2014-11-10 00:11:28 +11:00
|
|
|
assert_eq!(Duration::zero().num_days(), 0);
|
2014-07-28 15:54:05 -07:00
|
|
|
assert_eq!(Duration::days(1).num_days(), 1);
|
|
|
|
assert_eq!(Duration::days(-1).num_days(), -1);
|
|
|
|
assert_eq!(Duration::seconds(86399).num_days(), 0);
|
|
|
|
assert_eq!(Duration::seconds(86401).num_days(), 1);
|
|
|
|
assert_eq!(Duration::seconds(-86399).num_days(), 0);
|
|
|
|
assert_eq!(Duration::seconds(-86401).num_days(), -1);
|
2014-08-19 14:32:20 +02:00
|
|
|
assert_eq!(Duration::days(i32::MAX as i64).num_days(), i32::MAX as i64);
|
|
|
|
assert_eq!(Duration::days(i32::MIN as i64).num_days(), i32::MIN as i64);
|
2014-07-28 15:54:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_duration_num_seconds() {
|
2014-11-10 00:11:28 +11:00
|
|
|
assert_eq!(Duration::zero().num_seconds(), 0);
|
2014-07-28 15:54:05 -07:00
|
|
|
assert_eq!(Duration::seconds(1).num_seconds(), 1);
|
|
|
|
assert_eq!(Duration::seconds(-1).num_seconds(), -1);
|
|
|
|
assert_eq!(Duration::milliseconds(999).num_seconds(), 0);
|
|
|
|
assert_eq!(Duration::milliseconds(1001).num_seconds(), 1);
|
|
|
|
assert_eq!(Duration::milliseconds(-999).num_seconds(), 0);
|
|
|
|
assert_eq!(Duration::milliseconds(-1001).num_seconds(), -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_duration_num_milliseconds() {
|
2014-11-10 00:11:28 +11:00
|
|
|
assert_eq!(Duration::zero().num_milliseconds(), 0);
|
2014-08-21 09:37:30 +02:00
|
|
|
assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1);
|
|
|
|
assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1);
|
|
|
|
assert_eq!(Duration::microseconds(999).num_milliseconds(), 0);
|
|
|
|
assert_eq!(Duration::microseconds(1001).num_milliseconds(), 1);
|
|
|
|
assert_eq!(Duration::microseconds(-999).num_milliseconds(), 0);
|
|
|
|
assert_eq!(Duration::microseconds(-1001).num_milliseconds(), -1);
|
|
|
|
assert_eq!(Duration::milliseconds(i64::MAX).num_milliseconds(), i64::MAX);
|
|
|
|
assert_eq!(Duration::milliseconds(i64::MIN).num_milliseconds(), i64::MIN);
|
|
|
|
assert_eq!(MAX.num_milliseconds(), i64::MAX);
|
|
|
|
assert_eq!(MIN.num_milliseconds(), i64::MIN);
|
2014-07-28 15:54:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_duration_num_microseconds() {
|
2014-11-10 00:11:28 +11:00
|
|
|
assert_eq!(Duration::zero().num_microseconds(), Some(0));
|
2014-07-28 15:54:05 -07:00
|
|
|
assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1));
|
|
|
|
assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1));
|
|
|
|
assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0));
|
|
|
|
assert_eq!(Duration::nanoseconds(1001).num_microseconds(), Some(1));
|
|
|
|
assert_eq!(Duration::nanoseconds(-999).num_microseconds(), Some(0));
|
|
|
|
assert_eq!(Duration::nanoseconds(-1001).num_microseconds(), Some(-1));
|
2014-08-19 14:32:20 +02:00
|
|
|
assert_eq!(Duration::microseconds(i64::MAX).num_microseconds(), Some(i64::MAX));
|
|
|
|
assert_eq!(Duration::microseconds(i64::MIN).num_microseconds(), Some(i64::MIN));
|
2014-07-31 17:24:54 -07:00
|
|
|
assert_eq!(MAX.num_microseconds(), None);
|
|
|
|
assert_eq!(MIN.num_microseconds(), None);
|
2014-07-28 15:54:05 -07:00
|
|
|
|
|
|
|
// overflow checks
|
2014-10-06 16:29:47 -07:00
|
|
|
const MICROS_PER_DAY: i64 = 86400_000_000;
|
2014-08-19 14:32:20 +02:00
|
|
|
assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY).num_microseconds(),
|
2014-07-28 15:54:05 -07:00
|
|
|
Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY));
|
2014-08-19 14:32:20 +02:00
|
|
|
assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY).num_microseconds(),
|
2014-07-28 15:54:05 -07:00
|
|
|
Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY));
|
2014-08-19 14:32:20 +02:00
|
|
|
assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None);
|
|
|
|
assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY - 1).num_microseconds(), None);
|
2014-07-28 15:54:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_duration_num_nanoseconds() {
|
2014-11-10 00:11:28 +11:00
|
|
|
assert_eq!(Duration::zero().num_nanoseconds(), Some(0));
|
2014-07-28 15:54:05 -07:00
|
|
|
assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1));
|
|
|
|
assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1));
|
2014-08-19 14:32:20 +02:00
|
|
|
assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX));
|
|
|
|
assert_eq!(Duration::nanoseconds(i64::MIN).num_nanoseconds(), Some(i64::MIN));
|
2014-07-31 17:24:54 -07:00
|
|
|
assert_eq!(MAX.num_nanoseconds(), None);
|
|
|
|
assert_eq!(MIN.num_nanoseconds(), None);
|
2014-07-28 15:54:05 -07:00
|
|
|
|
|
|
|
// overflow checks
|
2014-10-06 16:29:47 -07:00
|
|
|
const NANOS_PER_DAY: i64 = 86400_000_000_000;
|
2014-08-19 14:32:20 +02:00
|
|
|
assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(),
|
2014-07-28 15:54:05 -07:00
|
|
|
Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY));
|
2014-08-19 14:32:20 +02:00
|
|
|
assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY).num_nanoseconds(),
|
2014-07-28 15:54:05 -07:00
|
|
|
Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY));
|
2014-08-19 14:32:20 +02:00
|
|
|
assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None);
|
|
|
|
assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY - 1).num_nanoseconds(), None);
|
2014-07-28 15:54:05 -07:00
|
|
|
}
|
|
|
|
|
2014-07-14 19:18:07 -07:00
|
|
|
#[test]
|
|
|
|
fn test_duration_checked_ops() {
|
2014-08-21 09:37:30 +02:00
|
|
|
assert_eq!(Duration::milliseconds(i64::MAX - 1).checked_add(&Duration::microseconds(999)),
|
|
|
|
Some(Duration::milliseconds(i64::MAX - 2) + Duration::microseconds(1999)));
|
2014-08-28 21:56:27 +02:00
|
|
|
assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::microseconds(1000))
|
|
|
|
.is_none());
|
2014-07-14 19:18:07 -07:00
|
|
|
|
2014-08-21 09:37:30 +02:00
|
|
|
assert_eq!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(0)),
|
|
|
|
Some(Duration::milliseconds(i64::MIN)));
|
2014-08-28 21:56:27 +02:00
|
|
|
assert!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(1))
|
|
|
|
.is_none());
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_duration_mul() {
|
2014-11-10 00:11:28 +11:00
|
|
|
assert_eq!(Duration::zero() * i32::MAX, Duration::zero());
|
|
|
|
assert_eq!(Duration::zero() * i32::MIN, Duration::zero());
|
|
|
|
assert_eq!(Duration::nanoseconds(1) * 0, Duration::zero());
|
2014-07-14 19:18:07 -07:00
|
|
|
assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1));
|
|
|
|
assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1));
|
|
|
|
assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1));
|
|
|
|
assert_eq!(-Duration::nanoseconds(1) * 1_000_000_000, -Duration::seconds(1));
|
|
|
|
assert_eq!(Duration::nanoseconds(30) * 333_333_333,
|
|
|
|
Duration::seconds(10) - Duration::nanoseconds(10));
|
|
|
|
assert_eq!((Duration::nanoseconds(1) + Duration::seconds(1) + Duration::days(1)) * 3,
|
|
|
|
Duration::nanoseconds(3) + Duration::seconds(3) + Duration::days(3));
|
2014-08-19 14:32:20 +02:00
|
|
|
assert_eq!(Duration::milliseconds(1500) * -2, Duration::seconds(-3));
|
|
|
|
assert_eq!(Duration::milliseconds(-1500) * 2, Duration::seconds(-3));
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_duration_div() {
|
2014-11-10 00:11:28 +11:00
|
|
|
assert_eq!(Duration::zero() / i32::MAX, Duration::zero());
|
|
|
|
assert_eq!(Duration::zero() / i32::MIN, Duration::zero());
|
2014-07-14 19:18:07 -07:00
|
|
|
assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789));
|
|
|
|
assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789));
|
|
|
|
assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789));
|
|
|
|
assert_eq!(-Duration::nanoseconds(123_456_789) / 1, -Duration::nanoseconds(123_456_789));
|
2014-08-19 14:32:20 +02:00
|
|
|
assert_eq!(Duration::seconds(1) / 3, Duration::nanoseconds(333_333_333));
|
|
|
|
assert_eq!(Duration::seconds(4) / 3, Duration::nanoseconds(1_333_333_333));
|
|
|
|
assert_eq!(Duration::seconds(-1) / 2, Duration::milliseconds(-500));
|
|
|
|
assert_eq!(Duration::seconds(1) / -2, Duration::milliseconds(-500));
|
|
|
|
assert_eq!(Duration::seconds(-1) / -2, Duration::milliseconds(500));
|
|
|
|
assert_eq!(Duration::seconds(-4) / 3, Duration::nanoseconds(-1_333_333_333));
|
|
|
|
assert_eq!(Duration::seconds(-4) / -3, Duration::nanoseconds(1_333_333_333));
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_duration_fmt() {
|
2014-11-27 19:45:47 -05:00
|
|
|
assert_eq!(Duration::zero().to_string(), "PT0S");
|
|
|
|
assert_eq!(Duration::days(42).to_string(), "P42D");
|
|
|
|
assert_eq!(Duration::days(-42).to_string(), "-P42D");
|
|
|
|
assert_eq!(Duration::seconds(42).to_string(), "PT42S");
|
|
|
|
assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S");
|
|
|
|
assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S");
|
|
|
|
assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S");
|
2014-07-14 19:18:07 -07:00
|
|
|
assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(),
|
2014-11-27 19:45:47 -05:00
|
|
|
"P7DT6.543S");
|
|
|
|
assert_eq!(Duration::seconds(-86401).to_string(), "-P1DT1S");
|
|
|
|
assert_eq!(Duration::nanoseconds(-1).to_string(), "-PT0.000000001S");
|
2014-07-28 15:54:05 -07:00
|
|
|
|
|
|
|
// the format specifier should have no effect on `Duration`
|
|
|
|
assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)),
|
2014-11-27 19:45:47 -05:00
|
|
|
"P1DT2.345S");
|
2014-07-14 19:18:07 -07:00
|
|
|
}
|
|
|
|
}
|