std: Redesign Duration, implementing RFC 1040

This commit is an implementation of [RFC 1040][rfc] which is a redesign of the
currently-unstable `Duration` type. The API of the type has been scaled back to
be more conservative and it also no longer supports negative durations.

[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1040-duration-reform.md

The inner `duration` module of the `time` module has now been hidden (as
`Duration` is reexported) and the feature name for this type has changed from
`std_misc` to `duration`. All APIs accepting durations have also been audited to
take a more flavorful feature name instead of `std_misc`.

Closes #24874
This commit is contained in:
Alex Crichton 2015-04-28 11:40:04 -07:00
parent 05d5fcaa5b
commit 556e76bb78
26 changed files with 380 additions and 637 deletions

View File

@ -30,6 +30,8 @@
#![feature(box_syntax)]
#![feature(collections)]
#![feature(core)]
#![feature(duration)]
#![feature(duration_span)]
#![feature(fs_canonicalize)]
#![feature(hash)]
#![feature(into_cow)]

View File

@ -720,8 +720,7 @@ fn get_metadata_section(is_osx: bool, filename: &Path) -> Result<MetadataBlob, S
let dur = Duration::span(|| {
ret = Some(get_metadata_section_imp(is_osx, filename));
});
info!("reading {:?} => {}ms", filename.file_name().unwrap(),
dur.num_milliseconds());
info!("reading {:?} => {}", filename.file_name().unwrap(), dur);
return ret.unwrap();;
}

View File

@ -55,8 +55,8 @@ pub fn time<T, U, F>(do_it: bool, what: &str, u: U, f: F) -> T where
};
let rv = rv.unwrap();
println!("{}time: {}.{:03} \t{}", repeat(" ").take(old).collect::<String>(),
dur.num_seconds(), dur.num_milliseconds() % 1000, what);
println!("{}time: {} \t{}", repeat(" ").take(old).collect::<String>(),
dur, what);
DEPTH.with(|slot| slot.set(old));
rv

View File

@ -69,12 +69,12 @@ pub struct Condvar { inner: Box<StaticCondvar> }
/// # Examples
///
/// ```
/// # #![feature(std_misc)]
/// # #![feature(static_condvar)]
/// use std::sync::{StaticCondvar, CONDVAR_INIT};
///
/// static CVAR: StaticCondvar = CONDVAR_INIT;
/// ```
#[unstable(feature = "std_misc",
#[unstable(feature = "static_condvar",
reason = "may be merged with Condvar in the future")]
pub struct StaticCondvar {
inner: sys::Condvar,
@ -82,7 +82,7 @@ pub struct StaticCondvar {
}
/// Constant initializer for a statically allocated condition variable.
#[unstable(feature = "std_misc",
#[unstable(feature = "static_condvar",
reason = "may be merged with Condvar in the future")]
pub const CONDVAR_INIT: StaticCondvar = StaticCondvar {
inner: sys::CONDVAR_INIT,
@ -161,6 +161,30 @@ impl Condvar {
}
}
/// Waits on this condition variable for a notification, timing out after a
/// specified duration.
///
/// The semantics of this function are equivalent to `wait()` except that
/// the thread will be blocked for roughly no longer than `dur`. This
/// method should not be used for precise timing due to anomalies such as
/// preemption or platform differences that may not cause the maximum
/// amount of time waited to be precisely `dur`.
///
/// The returned boolean is `false` only if the timeout is known
/// to have elapsed.
///
/// Like `wait`, the lock specified will be re-acquired when this function
/// returns, regardless of whether the timeout elapsed or not.
#[unstable(feature = "wait_timeout", reason = "waiting for Duration")]
pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
dur: Duration)
-> LockResult<(MutexGuard<'a, T>, bool)> {
unsafe {
let me: &'static Condvar = &*(self as *const _);
me.inner.wait_timeout(guard, dur)
}
}
/// Waits on this condition variable for a notification, timing out after a
/// specified duration.
///
@ -214,7 +238,7 @@ impl StaticCondvar {
/// notification.
///
/// See `Condvar::wait`.
#[unstable(feature = "std_misc",
#[unstable(feature = "static_condvar",
reason = "may be merged with Condvar in the future")]
pub fn wait<'a, T>(&'static self, guard: MutexGuard<'a, T>)
-> LockResult<MutexGuard<'a, T>> {
@ -235,14 +259,27 @@ impl StaticCondvar {
/// specified duration.
///
/// See `Condvar::wait_timeout`.
#[unstable(feature = "std_misc",
#[unstable(feature = "static_condvar",
reason = "may be merged with Condvar in the future")]
pub fn wait_timeout_ms<'a, T>(&'static self, guard: MutexGuard<'a, T>, ms: u32)
-> LockResult<(MutexGuard<'a, T>, bool)> {
self.wait_timeout(guard, Duration::from_millis(ms as u64))
}
/// Waits on this condition variable for a notification, timing out after a
/// specified duration.
///
/// See `Condvar::wait_timeout`.
#[unstable(feature = "static_condvar",
reason = "may be merged with Condvar in the future")]
pub fn wait_timeout<'a, T>(&'static self,
guard: MutexGuard<'a, T>,
timeout: Duration)
-> LockResult<(MutexGuard<'a, T>, bool)> {
let (poisoned, success) = unsafe {
let lock = mutex::guard_lock(&guard);
self.verify(lock);
let success = self.inner.wait_timeout(lock, Duration::milliseconds(ms as i64));
let success = self.inner.wait_timeout(lock, timeout);
(mutex::guard_poison(&guard).get(), success)
};
if poisoned {
@ -259,7 +296,7 @@ impl StaticCondvar {
/// passed and the function returns `false`.
///
/// See `Condvar::wait_timeout_with`.
#[unstable(feature = "std_misc",
#[unstable(feature = "static_condvar",
reason = "may be merged with Condvar in the future")]
pub fn wait_timeout_with<'a, T, F>(&'static self,
guard: MutexGuard<'a, T>,
@ -267,7 +304,8 @@ impl StaticCondvar {
mut f: F)
-> LockResult<(MutexGuard<'a, T>, bool)>
where F: FnMut(LockResult<&mut T>) -> bool {
// This could be made more efficient by pushing the implementation into sys::condvar
// This could be made more efficient by pushing the implementation into
// sys::condvar
let start = SteadyTime::now();
let mut guard_result: LockResult<MutexGuard<'a, T>> = Ok(guard);
while !f(guard_result
@ -277,12 +315,15 @@ impl StaticCondvar {
let now = SteadyTime::now();
let consumed = &now - &start;
let guard = guard_result.unwrap_or_else(|e| e.into_inner());
let res = self.wait_timeout_ms(guard, (dur - consumed).num_milliseconds() as u32);
let (new_guard_result, no_timeout) = match res {
Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout),
Err(err) => {
let (new_guard, no_timeout) = err.into_inner();
(Err(PoisonError::new(new_guard)), no_timeout)
let (new_guard_result, no_timeout) = if consumed > dur {
(Ok(guard), false)
} else {
match self.wait_timeout(guard, dur - consumed) {
Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout),
Err(err) => {
let (new_guard, no_timeout) = err.into_inner();
(Err(PoisonError::new(new_guard)), no_timeout)
}
}
};
guard_result = new_guard_result;
@ -301,14 +342,14 @@ impl StaticCondvar {
/// Wakes up one blocked thread on this condvar.
///
/// See `Condvar::notify_one`.
#[unstable(feature = "std_misc",
#[unstable(feature = "static_condvar",
reason = "may be merged with Condvar in the future")]
pub fn notify_one(&'static self) { unsafe { self.inner.notify_one() } }
/// Wakes up all blocked threads on this condvar.
///
/// See `Condvar::notify_all`.
#[unstable(feature = "std_misc",
#[unstable(feature = "static_condvar",
reason = "may be merged with Condvar in the future")]
pub fn notify_all(&'static self) { unsafe { self.inner.notify_all() } }
@ -318,7 +359,7 @@ impl StaticCondvar {
/// active users of the condvar, and this also doesn't prevent any future
/// users of the condvar. This method is required to be called to not leak
/// memory on all platforms.
#[unstable(feature = "std_misc",
#[unstable(feature = "static_condvar",
reason = "may be merged with Condvar in the future")]
pub unsafe fn destroy(&'static self) {
self.inner.destroy()
@ -447,7 +488,9 @@ mod tests {
static S: AtomicUsize = ATOMIC_USIZE_INIT;
let g = M.lock().unwrap();
let (g, success) = C.wait_timeout_with(g, Duration::nanoseconds(1000), |_| false).unwrap();
let (g, success) = C.wait_timeout_with(g, Duration::new(0, 1000), |_| {
false
}).unwrap();
assert!(!success);
let (tx, rx) = channel();
@ -471,7 +514,8 @@ mod tests {
});
let mut state = 0;
let (_g, success) = C.wait_timeout_with(g, Duration::days(1), |_| {
let day = 24 * 60 * 60;
let (_g, success) = C.wait_timeout_with(g, Duration::new(day, 0), |_| {
assert_eq!(state, S.load(Ordering::SeqCst));
tx.send(()).unwrap();
state += 1;

View File

@ -57,25 +57,20 @@ impl Condvar {
// https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46
// https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
if dur <= Duration::zero() {
return false;
}
// First, figure out what time it currently is, in both system and stable time.
// pthread_cond_timedwait uses system time, but we want to report timeout based on stable
// time.
// First, figure out what time it currently is, in both system and
// stable time. pthread_cond_timedwait uses system time, but we want to
// report timeout based on stable time.
let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 };
let stable_now = time::SteadyTime::now();
let r = ffi::gettimeofday(&mut sys_now, ptr::null_mut());
debug_assert_eq!(r, 0);
let seconds = dur.num_seconds() as libc::time_t;
let seconds = dur.secs() as libc::time_t;
let timeout = match sys_now.tv_sec.checked_add(seconds) {
Some(sec) => {
libc::timespec {
tv_sec: sec,
tv_nsec: (dur - Duration::seconds(dur.num_seconds()))
.num_nanoseconds().unwrap() as libc::c_long,
tv_nsec: dur.extra_nanos() as libc::c_long,
}
}
None => {
@ -87,11 +82,12 @@ impl Condvar {
};
// And wait!
let r = ffi::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), &timeout);
let r = ffi::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex),
&timeout);
debug_assert!(r == libc::ETIMEDOUT || r == 0);
// ETIMEDOUT is not a totally reliable method of determining timeout due to clock shifts,
// so do the check ourselves
// ETIMEDOUT is not a totally reliable method of determining timeout due
// to clock shifts, so do the check ourselves
&time::SteadyTime::now() - &stable_now < dur
}

View File

@ -129,14 +129,9 @@ impl Thread {
}
pub fn sleep(dur: Duration) {
if dur < Duration::zero() {
return Thread::yield_now()
}
let seconds = dur.num_seconds();
let ns = dur - Duration::seconds(seconds);
let mut ts = libc::timespec {
tv_sec: seconds as libc::time_t,
tv_nsec: ns.num_nanoseconds().unwrap() as libc::c_long,
tv_sec: dur.secs() as libc::time_t,
tv_nsec: dur.extra_nanos() as libc::c_long,
};
// If we're awoken with a signal then the return value will be -1 and

View File

@ -10,12 +10,15 @@
pub use self::inner::SteadyTime;
const NSEC_PER_SEC: u64 = 1_000_000_000;
#[cfg(any(target_os = "macos", target_os = "ios"))]
mod inner {
use libc;
use time::Duration;
use ops::Sub;
use sync::{Once, ONCE_INIT};
use super::NSEC_PER_SEC;
pub struct SteadyTime {
t: u64
@ -32,11 +35,6 @@ mod inner {
t: unsafe { mach_absolute_time() },
}
}
pub fn ns(&self) -> u64 {
let info = info();
self.t * info.numer as u64 / info.denom as u64
}
}
fn info() -> &'static libc::mach_timebase_info {
@ -59,8 +57,9 @@ mod inner {
fn sub(self, other: &SteadyTime) -> Duration {
let info = info();
let diff = self.t as i64 - other.t as i64;
Duration::nanoseconds(diff * info.numer as i64 / info.denom as i64)
let diff = self.t as u64 - other.t as u64;
let nanos = diff * info.numer as u64 / info.denom as u64;
Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32)
}
}
}
@ -70,8 +69,7 @@ mod inner {
use libc;
use time::Duration;
use ops::Sub;
const NSEC_PER_SEC: i64 = 1_000_000_000;
use super::NSEC_PER_SEC;
pub struct SteadyTime {
t: libc::timespec,
@ -104,10 +102,6 @@ mod inner {
}
t
}
pub fn ns(&self) -> u64 {
self.t.tv_sec as u64 * NSEC_PER_SEC as u64 + self.t.tv_nsec as u64
}
}
impl<'a> Sub for &'a SteadyTime {
@ -115,12 +109,12 @@ mod inner {
fn sub(self, other: &SteadyTime) -> Duration {
if self.t.tv_nsec >= other.t.tv_nsec {
Duration::seconds(self.t.tv_sec as i64 - other.t.tv_sec as i64) +
Duration::nanoseconds(self.t.tv_nsec as i64 - other.t.tv_nsec as i64)
Duration::new(self.t.tv_sec as u64 - other.t.tv_sec as u64,
self.t.tv_nsec as u32 - other.t.tv_nsec as u32)
} else {
Duration::seconds(self.t.tv_sec as i64 - 1 - other.t.tv_sec as i64) +
Duration::nanoseconds(self.t.tv_nsec as i64 + NSEC_PER_SEC -
other.t.tv_nsec as i64)
Duration::new(self.t.tv_sec as u64 - 1 - other.t.tv_sec as u64,
self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
other.t.tv_nsec as u32)
}
}
}

View File

@ -42,7 +42,7 @@ impl Condvar {
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
let r = ffi::SleepConditionVariableSRW(self.inner.get(),
mutex::raw(mutex),
dur.num_milliseconds() as DWORD,
super::dur2timeout(dur),
0);
if r == 0 {
const ERROR_TIMEOUT: DWORD = 0x5B4;

View File

@ -20,6 +20,7 @@ use libc;
use num::Zero;
use os::windows::ffi::{OsStrExt, OsStringExt};
use path::PathBuf;
use time::Duration;
pub mod backtrace;
pub mod c;
@ -151,6 +152,27 @@ fn cvt<I: PartialEq + Zero>(i: I) -> io::Result<I> {
}
}
fn dur2timeout(dur: Duration) -> libc::DWORD {
// Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
// timeouts in windows APIs are typically u32 milliseconds. To translate, we
// have two pieces to take care of:
//
// * Nanosecond precision is rounded up
// * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE
// (never time out).
dur.secs().checked_mul(1000).and_then(|ms| {
ms.checked_add((dur.extra_nanos() as u64) / 1_000_000)
}).and_then(|ms| {
ms.checked_add(if dur.extra_nanos() % 1_000_000 > 0 {1} else {0})
}).map(|ms| {
if ms > <libc::DWORD>::max_value() as u64 {
libc::INFINITE
} else {
ms as libc::DWORD
}
}).unwrap_or(libc::INFINITE)
}
fn ms_to_filetime(ms: u64) -> libc::FILETIME {
// A FILETIME is a count of 100 nanosecond intervals, so we multiply by
// 10000 b/c there are 10000 intervals in 1 ms

View File

@ -80,15 +80,7 @@ impl Thread {
pub fn sleep(dur: Duration) {
unsafe {
if dur < Duration::zero() {
return Thread::yield_now()
}
let ms = dur.num_milliseconds();
// if we have a fractional number of milliseconds then add an extra
// millisecond to sleep for
let extra = dur - Duration::milliseconds(ms);
let ms = ms + if extra.is_zero() {0} else {1};
c::Sleep(ms as DWORD);
c::Sleep(super::dur2timeout(dur))
}
}
}

View File

@ -12,7 +12,7 @@ use ops::Sub;
use time::Duration;
use sync::{Once, ONCE_INIT};
const NANOS_PER_SEC: i64 = 1_000_000_000;
const NANOS_PER_SEC: u64 = 1_000_000_000;
pub struct SteadyTime {
t: libc::LARGE_INTEGER,
@ -24,10 +24,6 @@ impl SteadyTime {
unsafe { libc::QueryPerformanceCounter(&mut t.t); }
t
}
pub fn ns(&self) -> u64 {
mul_div_i64(self.t as i64, NANOS_PER_SEC, frequency() as i64) as u64
}
}
fn frequency() -> libc::LARGE_INTEGER {
@ -46,15 +42,16 @@ impl<'a> Sub for &'a SteadyTime {
type Output = Duration;
fn sub(self, other: &SteadyTime) -> Duration {
let diff = self.t as i64 - other.t as i64;
Duration::nanoseconds(mul_div_i64(diff, NANOS_PER_SEC, frequency() as i64))
let diff = self.t as u64 - other.t as u64;
let nanos = mul_div_u64(diff, NANOS_PER_SEC, frequency() as u64);
Duration::new(nanos / NANOS_PER_SEC, (nanos % NANOS_PER_SEC) as u32)
}
}
// Computes (value*numer)/denom without overflow, as long as both
// (numer*denom) and the overall result fit into i64 (which is the case
// for our time conversions).
fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 {
fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 {
let q = value / denom;
let r = value % denom;
// Decompose value as (value/denom*denom + value%denom),
@ -65,9 +62,6 @@ fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 {
#[test]
fn test_muldiv() {
assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000);
assert_eq!(mul_div_i64(-1_000_000_000_001, 1_000_000_000, 1_000_000), -1_000_000_000_001_000);
assert_eq!(mul_div_i64(-1_000_000_000_001,-1_000_000_000, 1_000_000), 1_000_000_000_001_000);
assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000,-1_000_000), -1_000_000_000_001_000);
assert_eq!(mul_div_i64( 1_000_000_000_001,-1_000_000_000,-1_000_000), 1_000_000_000_001_000);
assert_eq!(mul_div_u64( 1_000_000_000_001, 1_000_000_000, 1_000_000),
1_000_000_000_001_000);
}

View File

@ -482,7 +482,23 @@ pub fn catch_panic<F, R>(f: F) -> Result<R>
/// spurious wakeup.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn sleep_ms(ms: u32) {
imp::Thread::sleep(Duration::milliseconds(ms as i64))
sleep(Duration::from_millis(ms as u64))
}
/// Puts the current thread to sleep for the specified amount of time.
///
/// The thread may sleep longer than the duration specified due to scheduling
/// specifics or platform-dependent functionality.
///
/// # Platform behavior
///
/// On Unix platforms this function will not return early due to a
/// signal being received or a spurious wakeup. Platforms which do not support
/// nanosecond precision for sleeping will have `dur` rounded up to the nearest
/// granularity of time they can sleep for.
#[unstable(feature = "thread_sleep", reason = "waiting on Duration")]
pub fn sleep(dur: Duration) {
imp::Thread::sleep(dur)
}
/// Blocks unless or until the current thread's token is made available (may wake spuriously).
@ -508,18 +524,38 @@ pub fn park() {
/// the specified duration has been reached (may wake spuriously).
///
/// The semantics of this function are equivalent to `park()` except that the
/// thread will be blocked for roughly no longer than *duration*. This method
/// thread will be blocked for roughly no longer than *ms*. This method
/// should not be used for precise timing due to anomalies such as
/// preemption or platform differences that may not cause the maximum
/// amount of time waited to be precisely *duration* long.
/// amount of time waited to be precisely *ms* long.
///
/// See the module doc for more detail.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn park_timeout_ms(ms: u32) {
park_timeout(Duration::from_millis(ms as u64))
}
/// Blocks unless or until the current thread's token is made available or
/// the specified duration has been reached (may wake spuriously).
///
/// The semantics of this function are equivalent to `park()` except that the
/// thread will be blocked for roughly no longer than *dur*. This method
/// should not be used for precise timing due to anomalies such as
/// preemption or platform differences that may not cause the maximum
/// amount of time waited to be precisely *dur* long.
///
/// See the module doc for more detail.
///
/// # Platform behavior
///
/// Platforms which do not support nanosecond precision for sleeping will have
/// `dur` rounded up to the nearest granularity of time they can sleep for.
#[unstable(feature = "park_timeout", reason = "waiting on Duration")]
pub fn park_timeout(dur: Duration) {
let thread = current();
let mut guard = thread.inner.lock.lock().unwrap();
if !*guard {
let (g, _) = thread.inner.cvar.wait_timeout_ms(guard, ms).unwrap();
let (g, _) = thread.inner.cvar.wait_timeout(guard, dur).unwrap();
guard = g;
}
*guard = false;

View File

@ -10,589 +10,265 @@
//! Temporal quantification
#![unstable(feature = "std_misc")]
#![unstable(feature = "duration", reason = "recently added API per RFC 1040")]
use prelude::v1::*;
use {fmt, i64};
use ops::{Add, Sub, Mul, Div, Neg};
use fmt;
use ops::{Add, Sub, Mul, Div};
use sys::time::SteadyTime;
/// The number of nanoseconds in a microsecond.
const NANOS_PER_MICRO: i32 = 1000;
/// The number of nanoseconds in a millisecond.
const NANOS_PER_MILLI: i32 = 1000_000;
/// The number of nanoseconds in seconds.
const NANOS_PER_SEC: i32 = 1_000_000_000;
/// The number of microseconds per second.
const MICROS_PER_SEC: i64 = 1000_000;
/// The number of milliseconds per second.
const MILLIS_PER_SEC: i64 = 1000;
/// The number of seconds in a minute.
const SECS_PER_MINUTE: i64 = 60;
/// The number of seconds in an hour.
const SECS_PER_HOUR: i64 = 3600;
/// The number of (non-leap) seconds in days.
const SECS_PER_DAY: i64 = 86400;
/// The number of (non-leap) seconds in a week.
const SECS_PER_WEEK: i64 = 604800;
const NANOS_PER_SEC: u32 = 1_000_000_000;
const NANOS_PER_MILLI: u32 = 1_000_000;
const MILLIS_PER_SEC: u64 = 1_000;
macro_rules! try_opt {
($e:expr) => (match $e { Some(v) => v, None => return None })
}
/// ISO 8601 time duration with nanosecond precision.
/// This also allows for the negative duration; see individual methods for details.
#[unstable(feature = "std_misc")]
/// A duration type to represent a span of time, typically used for system
/// timeouts.
///
/// Each duration is composed of a number of seconds and nanosecond precision.
/// APIs binding a system timeout will typically round up the nanosecond
/// precision if the underlying system does not support that level of precision.
///
/// Durations implement many common traits, including `Add`, `Sub`, and other
/// ops traits. Currently a duration may only be inspected for its number of
/// seconds and its nanosecond precision.
///
/// # Examples
///
/// ```
/// #![feature(duration)]
/// use std::time::Duration;
///
/// let five_seconds = Duration::new(5, 0);
/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5);
///
/// assert_eq!(five_seconds_and_five_nanos.secs(), 5);
/// assert_eq!(five_seconds_and_five_nanos.extra_nanos(), 5);
///
/// let ten_millis = Duration::from_millis(10);
/// ```
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Duration {
secs: i64,
nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
secs: u64,
nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
}
/// The minimum possible `Duration`: `i64::MIN` milliseconds.
#[unstable(feature = "std_misc")]
pub const MIN: Duration = Duration {
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.
#[unstable(feature = "std_misc")]
pub const MAX: Duration = Duration {
secs: i64::MAX / MILLIS_PER_SEC,
nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI
};
impl Duration {
/// Makes a new `Duration` with given number of weeks.
/// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60)` with overflow checks.
/// Panics when the duration is out of bounds.
#[inline]
#[unstable(feature = "std_misc")]
pub fn weeks(weeks: i64) -> Duration {
let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds");
Duration::seconds(secs)
}
/// Makes a new `Duration` with given number of days.
/// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks.
/// Panics when the duration is out of bounds.
#[inline]
#[unstable(feature = "std_misc")]
pub fn days(days: i64) -> Duration {
let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds");
Duration::seconds(secs)
}
/// Makes a new `Duration` with given number of hours.
/// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks.
/// Panics when the duration is out of bounds.
#[inline]
#[unstable(feature = "std_misc")]
pub fn hours(hours: i64) -> Duration {
let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds");
Duration::seconds(secs)
}
/// Makes a new `Duration` with given number of minutes.
/// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks.
/// Panics when the duration is out of bounds.
#[inline]
#[unstable(feature = "std_misc")]
pub fn minutes(minutes: i64) -> Duration {
let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds");
Duration::seconds(secs)
}
/// Makes a new `Duration` with given number of seconds.
/// Panics when the duration is more than `i64::MAX` milliseconds
/// or less than `i64::MIN` milliseconds.
#[inline]
#[unstable(feature = "std_misc")]
pub fn seconds(seconds: i64) -> Duration {
let d = Duration { secs: seconds, nanos: 0 };
if d < MIN || d > MAX {
panic!("Duration::seconds out of bounds");
}
d
}
/// Makes a new `Duration` with given number of milliseconds.
#[inline]
#[unstable(feature = "std_misc")]
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;
/// Crates a new `Duration` from the specified number of seconds and
/// additional nanosecond precision.
///
/// If the nanoseconds is greater than 1 billion (the number of nanoseconds
/// in a second), then it will carry over into the seconds provided.
pub fn new(secs: u64, nanos: u32) -> Duration {
let secs = secs + (nanos / NANOS_PER_SEC) as u64;
let nanos = nanos % NANOS_PER_SEC;
Duration { secs: secs, nanos: nanos }
}
/// Makes a new `Duration` with given number of microseconds.
#[inline]
#[unstable(feature = "std_misc")]
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 }
}
/// Makes a new `Duration` with given number of nanoseconds.
#[inline]
#[unstable(feature = "std_misc")]
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 }
}
/// Runs a closure, returning the duration of time it took to run the
/// closure.
#[unstable(feature = "std_misc")]
#[unstable(feature = "duration_span",
reason = "unsure if this is the right API or whether it should \
wait for a more general \"moment in time\" \
abstraction")]
pub fn span<F>(f: F) -> Duration where F: FnOnce() {
let before = super::precise_time_ns();
let start = SteadyTime::now();
f();
Duration::nanoseconds((super::precise_time_ns() - before) as i64)
&SteadyTime::now() - &start
}
/// Returns the total number of whole weeks in the duration.
#[inline]
#[unstable(feature = "std_misc")]
pub fn num_weeks(&self) -> i64 {
self.num_days() / 7
/// Creates a new `Duration` from the specified number of seconds.
pub fn from_secs(secs: u64) -> Duration {
Duration { secs: secs, nanos: 0 }
}
/// Returns the total number of whole days in the duration.
#[unstable(feature = "std_misc")]
pub fn num_days(&self) -> i64 {
self.num_seconds() / SECS_PER_DAY
/// Creates a new `Duration` from the specified number of milliseconds.
pub fn from_millis(millis: u64) -> Duration {
let secs = millis / MILLIS_PER_SEC;
let nanos = ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI;
Duration { secs: secs, nanos: nanos }
}
/// Returns the total number of whole hours in the duration.
#[inline]
#[unstable(feature = "std_misc")]
pub fn num_hours(&self) -> i64 {
self.num_seconds() / SECS_PER_HOUR
}
/// Returns the number of whole seconds represented by this duration.
///
/// The extra precision represented by this duration is ignored (e.g. extra
/// nanoseconds are not represented in the returned value).
pub fn secs(&self) -> u64 { self.secs }
/// Returns the total number of whole minutes in the duration.
#[inline]
#[unstable(feature = "std_misc")]
pub fn num_minutes(&self) -> i64 {
self.num_seconds() / SECS_PER_MINUTE
}
/// Returns the total number of whole seconds in the duration.
#[unstable(feature = "std_misc")]
pub fn num_seconds(&self) -> i64 {
// If secs is negative, nanos should be subtracted from the duration.
if self.secs < 0 && self.nanos > 0 {
self.secs + 1
} else {
self.secs
}
}
/// 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
}
}
/// Returns the total number of whole milliseconds in the duration,
#[unstable(feature = "std_misc")]
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;
let nanos_part = self.nanos_mod_sec() / NANOS_PER_MILLI;
secs_part + nanos_part as i64
}
/// Returns the total number of whole microseconds in the duration,
/// or `None` on overflow (exceeding 2^63 microseconds in either direction).
#[unstable(feature = "std_misc")]
pub fn num_microseconds(&self) -> Option<i64> {
let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC));
let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO;
secs_part.checked_add(nanos_part as i64)
}
/// Returns the total number of whole nanoseconds in the duration,
/// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
#[unstable(feature = "std_misc")]
pub fn num_nanoseconds(&self) -> Option<i64> {
let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64));
let nanos_part = self.nanos_mod_sec();
secs_part.checked_add(nanos_part as i64)
}
/// Add two durations, returning `None` if overflow occurred.
#[unstable(feature = "std_misc")]
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 occurred.
#[unstable(feature = "std_misc")]
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) }
}
/// The minimum possible `Duration`: `i64::MIN` milliseconds.
#[inline]
#[unstable(feature = "std_misc")]
pub fn min_value() -> Duration { MIN }
/// The maximum possible `Duration`: `i64::MAX` milliseconds.
#[inline]
#[unstable(feature = "std_misc")]
pub fn max_value() -> Duration { MAX }
/// A duration where the stored seconds and nanoseconds are equal to zero.
#[inline]
#[unstable(feature = "std_misc")]
pub fn zero() -> Duration {
Duration { secs: 0, nanos: 0 }
}
/// Returns `true` if the duration equals `Duration::zero()`.
#[inline]
#[unstable(feature = "std_misc")]
pub fn is_zero(&self) -> bool {
self.secs == 0 && self.nanos == 0
}
/// Returns the nanosecond precision represented by this duration.
///
/// This method does **not** return the length of the duration when
/// represented by nanoseconds. The returned number always represents a
/// fractional portion of a second (e.g. it is less than one billion).
pub fn extra_nanos(&self) -> u32 { self.nanos }
}
#[unstable(feature = "std_misc")]
impl Neg for Duration {
type Output = Duration;
#[inline]
fn neg(self) -> Duration {
if self.nanos == 0 {
Duration { secs: -self.secs, nanos: 0 }
} else {
Duration { secs: -self.secs - 1, nanos: NANOS_PER_SEC - self.nanos }
}
}
}
#[unstable(feature = "std_misc")]
impl Add for Duration {
type Output = Duration;
fn add(self, rhs: Duration) -> Duration {
let mut secs = self.secs + rhs.secs;
let mut secs = self.secs.checked_add(rhs.secs)
.expect("overflow when adding durations");
let mut nanos = self.nanos + rhs.nanos;
if nanos >= NANOS_PER_SEC {
nanos -= NANOS_PER_SEC;
secs += 1;
secs = secs.checked_add(1).expect("overflow when adding durations");
}
debug_assert!(nanos < NANOS_PER_SEC);
Duration { secs: secs, nanos: nanos }
}
}
#[unstable(feature = "std_misc")]
impl Sub for Duration {
type Output = Duration;
fn sub(self, rhs: Duration) -> Duration {
let mut secs = self.secs - rhs.secs;
let mut nanos = self.nanos - rhs.nanos;
if nanos < 0 {
nanos += NANOS_PER_SEC;
secs -= 1;
}
let mut secs = self.secs.checked_sub(rhs.secs)
.expect("overflow when subtracting durations");
let nanos = if self.nanos >= rhs.nanos {
self.nanos - rhs.nanos
} else {
secs = secs.checked_sub(1)
.expect("overflow when subtracting durations");
self.nanos + NANOS_PER_SEC - rhs.nanos
};
debug_assert!(nanos < NANOS_PER_SEC);
Duration { secs: secs, nanos: nanos }
}
}
#[unstable(feature = "std_misc")]
impl Mul<i32> for Duration {
impl Mul<u32> for Duration {
type Output = Duration;
fn mul(self, rhs: i32) -> Duration {
// 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 }
}
}
#[unstable(feature = "std_misc")]
impl Div<i32> for Duration {
type Output = Duration;
fn div(self, rhs: i32) -> Duration {
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;
}
fn mul(self, rhs: u32) -> Duration {
// Multiply nanoseconds as u64, because it cannot overflow that way.
let total_nanos = self.nanos as u64 * rhs as u64;
let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
let secs = self.secs.checked_mul(rhs as u64)
.and_then(|s| s.checked_add(extra_secs))
.expect("overflow when multiplying duration");
debug_assert!(nanos < NANOS_PER_SEC);
Duration { secs: secs, nanos: nanos }
}
}
impl Div<u32> for Duration {
type Output = Duration;
fn div(self, rhs: u32) -> Duration {
let secs = self.secs / (rhs as u64);
let carry = self.secs - secs * (rhs as u64);
let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64);
let nanos = self.nanos / rhs + (extra_nanos as u32);
debug_assert!(nanos < NANOS_PER_SEC);
Duration { secs: secs, nanos: nanos }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for Duration {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// technically speaking, negative duration is not valid ISO 8601,
// but we need to print it anyway.
let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") };
let days = abs.secs / SECS_PER_DAY;
let secs = abs.secs - days * SECS_PER_DAY;
let hasdate = days != 0;
let hastime = (secs != 0 || abs.nanos != 0) || !hasdate;
try!(write!(f, "{}P", sign));
if hasdate {
try!(write!(f, "{}D", days));
match (self.secs, self.nanos) {
(s, 0) => write!(f, "{}s", s),
(0, n) if n % NANOS_PER_MILLI == 0 => write!(f, "{}ms",
n / NANOS_PER_MILLI),
(0, n) if n % 1_000 == 0 => write!(f, "{}µs", n / 1_000),
(0, n) => write!(f, "{}ns", n),
(s, n) => write!(f, "{}.{}s", s,
format!("{:09}", n).trim_right_matches('0'))
}
if hastime {
if abs.nanos == 0 {
try!(write!(f, "T{}S", secs));
} 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));
} else {
try!(write!(f, "T{}.{:09}S", secs, abs.nanos));
}
}
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 {
use super::{Duration, MIN, MAX};
use {i32, i64};
use option::Option::{Some, None};
use string::ToString;
use prelude::v1::*;
use super::Duration;
#[test]
fn test_duration() {
assert!(Duration::seconds(1) != Duration::zero());
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));
assert_eq!(Duration::days(2) + Duration::seconds(86399) +
Duration::nanoseconds(1234567890),
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));
fn creation() {
assert!(Duration::from_secs(1) != Duration::from_secs(0));
assert_eq!(Duration::from_secs(1) + Duration::from_secs(2),
Duration::from_secs(3));
assert_eq!(Duration::from_millis(10) + Duration::from_secs(4),
Duration::new(4, 10 * 1_000_000));
assert_eq!(Duration::from_millis(4000), Duration::new(4, 0));
}
#[test]
fn test_duration_num_days() {
assert_eq!(Duration::zero().num_days(), 0);
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);
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);
fn secs() {
assert_eq!(Duration::new(0, 0).secs(), 0);
assert_eq!(Duration::from_secs(1).secs(), 1);
assert_eq!(Duration::from_millis(999).secs(), 0);
assert_eq!(Duration::from_millis(1001).secs(), 1);
}
#[test]
fn test_duration_num_seconds() {
assert_eq!(Duration::zero().num_seconds(), 0);
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);
fn nanos() {
assert_eq!(Duration::new(0, 0).extra_nanos(), 0);
assert_eq!(Duration::new(0, 5).extra_nanos(), 5);
assert_eq!(Duration::new(0, 1_000_000_001).extra_nanos(), 1);
assert_eq!(Duration::from_secs(1).extra_nanos(), 0);
assert_eq!(Duration::from_millis(999).extra_nanos(), 999 * 1_000_000);
assert_eq!(Duration::from_millis(1001).extra_nanos(), 1 * 1_000_000);
}
#[test]
fn test_duration_num_milliseconds() {
assert_eq!(Duration::zero().num_milliseconds(), 0);
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);
fn add() {
assert_eq!(Duration::new(0, 0) + Duration::new(0, 1),
Duration::new(0, 1));
assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001),
Duration::new(1, 1));
}
#[test]
fn test_duration_num_microseconds() {
assert_eq!(Duration::zero().num_microseconds(), Some(0));
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));
assert_eq!(Duration::microseconds(i64::MAX).num_microseconds(), Some(i64::MAX));
assert_eq!(Duration::microseconds(i64::MIN).num_microseconds(), Some(i64::MIN));
assert_eq!(MAX.num_microseconds(), None);
assert_eq!(MIN.num_microseconds(), None);
fn sub() {
assert_eq!(Duration::new(0, 1) - Duration::new(0, 0),
Duration::new(0, 1));
assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000),
Duration::new(0, 1));
assert_eq!(Duration::new(1, 0) - Duration::new(0, 1),
Duration::new(0, 999_999_999));
}
// overflow checks
const MICROS_PER_DAY: i64 = 86400_000_000;
assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY).num_microseconds(),
Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY));
assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY).num_microseconds(),
Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY));
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);
#[test] #[should_panic]
fn sub_bad1() {
Duration::new(0, 0) - Duration::new(0, 1);
}
#[test] #[should_panic]
fn sub_bad2() {
Duration::new(0, 0) - Duration::new(1, 0);
}
#[test]
fn test_duration_num_nanoseconds() {
assert_eq!(Duration::zero().num_nanoseconds(), Some(0));
assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1));
assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1));
assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX));
assert_eq!(Duration::nanoseconds(i64::MIN).num_nanoseconds(), Some(i64::MIN));
assert_eq!(MAX.num_nanoseconds(), None);
assert_eq!(MIN.num_nanoseconds(), None);
// overflow checks
const NANOS_PER_DAY: i64 = 86400_000_000_000;
assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(),
Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY));
assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY).num_nanoseconds(),
Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY));
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);
fn mul() {
assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2));
assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3));
assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4));
assert_eq!(Duration::new(0, 500_000_001) * 4000,
Duration::new(2000, 4000));
}
#[test]
fn test_duration_checked_ops() {
assert_eq!(Duration::milliseconds(i64::MAX - 1).checked_add(&Duration::microseconds(999)),
Some(Duration::milliseconds(i64::MAX - 2) + Duration::microseconds(1999)));
assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::microseconds(1000))
.is_none());
assert_eq!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(0)),
Some(Duration::milliseconds(i64::MIN)));
assert!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(1))
.is_none());
fn div() {
assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333));
assert_eq!(Duration::new(99, 999_999_000) / 100,
Duration::new(0, 999_999_990));
}
#[test]
fn test_duration_mul() {
assert_eq!(Duration::zero() * i32::MAX, Duration::zero());
assert_eq!(Duration::zero() * i32::MIN, Duration::zero());
assert_eq!(Duration::nanoseconds(1) * 0, Duration::zero());
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));
assert_eq!(Duration::milliseconds(1500) * -2, Duration::seconds(-3));
assert_eq!(Duration::milliseconds(-1500) * 2, Duration::seconds(-3));
}
#[test]
fn test_duration_div() {
assert_eq!(Duration::zero() / i32::MAX, Duration::zero());
assert_eq!(Duration::zero() / i32::MIN, Duration::zero());
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));
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));
}
#[test]
fn test_duration_fmt() {
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");
assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(),
"P7DT6.543S");
assert_eq!(Duration::seconds(-86401).to_string(), "-P1DT1S");
assert_eq!(Duration::nanoseconds(-1).to_string(), "-PT0.000000001S");
// the format specifier should have no effect on `Duration`
assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)),
"P1DT2.345S");
fn display() {
assert_eq!(Duration::new(0, 2).to_string(), "2ns");
assert_eq!(Duration::new(0, 2_000_000).to_string(), "2ms");
assert_eq!(Duration::new(2, 0).to_string(), "2s");
assert_eq!(Duration::new(2, 2).to_string(), "2.000000002s");
assert_eq!(Duration::new(2, 2_000_000).to_string(),
"2.002s");
assert_eq!(Duration::new(0, 2_000_002).to_string(),
"2000002ns");
assert_eq!(Duration::new(2, 2_000_002).to_string(),
"2.002000002s");
}
}

View File

@ -10,17 +10,8 @@
//! Temporal quantification.
#![unstable(feature = "std_misc")]
use sys::time::SteadyTime;
#![unstable(feature = "time")]
pub use self::duration::Duration;
pub mod duration;
/// Returns the current value of a high-resolution performance counter
/// in nanoseconds since an unspecified epoch.
// NB: this is intentionally not public, this is not ready to stabilize its api.
fn precise_time_ns() -> u64 {
SteadyTime::now().ns()
}
mod duration;

View File

@ -43,6 +43,8 @@
#![feature(std_misc)]
#![feature(libc)]
#![feature(set_stdio)]
#![feature(duration)]
#![feature(duration_span)]
extern crate getopts;
extern crate serialize;
@ -1069,7 +1071,7 @@ impl Bencher {
}
pub fn ns_elapsed(&mut self) -> u64 {
self.dur.num_nanoseconds().unwrap() as u64
self.dur.secs() * 1_000_000_000 + (self.dur.extra_nanos() as u64)
}
pub fn ns_per_iter(&mut self) -> u64 {
@ -1105,7 +1107,7 @@ impl Bencher {
// (i.e. larger error bars).
if n == 0 { n = 1; }
let mut total_run = Duration::nanoseconds(0);
let mut total_run = Duration::new(0, 0);
let samples : &mut [f64] = &mut [0.0_f64; 50];
loop {
let mut summ = None;
@ -1134,7 +1136,7 @@ impl Bencher {
// If we've run for 100ms and seem to have converged to a
// stable median.
if loop_run.num_milliseconds() > 100 &&
if loop_run > Duration::from_millis(100) &&
summ.median_abs_dev_pct < 1.0 &&
summ.median - summ5.median < summ5.median_abs_dev {
return summ5;
@ -1142,7 +1144,7 @@ impl Bencher {
total_run = total_run + loop_run;
// Longest we ever run for is 3s.
if total_run.num_seconds() > 3 {
if total_run > Duration::from_secs(3) {
return summ5;
}
@ -1166,7 +1168,7 @@ pub mod bench {
pub fn benchmark<F>(f: F) -> BenchSamples where F: FnMut(&mut Bencher) {
let mut bs = Bencher {
iterations: 0,
dur: Duration::nanoseconds(0),
dur: Duration::new(0, 0),
bytes: 0
};
@ -1185,7 +1187,7 @@ pub mod bench {
pub fn run_once<F>(f: F) where F: FnOnce(&mut Bencher) {
let mut bs = Bencher {
iterations: 0,
dur: Duration::nanoseconds(0),
dur: Duration::new(0, 0),
bytes: 0
};
bs.bench_n(1, f);

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(std_misc, rand)]
#![feature(std_misc, rand, duration, duration_span)]
use std::collections::{BTreeMap, HashMap, HashSet};
use std::env;

View File

@ -10,7 +10,7 @@
// ignore-pretty very bad with line comments
#![feature(unboxed_closures, rand, std_misc, collections)]
#![feature(unboxed_closures, rand, std_misc, collections, duration, duration_span)]
extern crate collections;
extern crate rand;
@ -167,13 +167,13 @@ fn write_results(label: &str, results: &Results) {
fn empty_results() -> Results {
Results {
sequential_ints: Duration::seconds(0),
random_ints: Duration::seconds(0),
delete_ints: Duration::seconds(0),
sequential_ints: Duration::new(0, 0),
random_ints: Duration::new(0, 0),
delete_ints: Duration::new(0, 0),
sequential_strings: Duration::seconds(0),
random_strings: Duration::seconds(0),
delete_strings: Duration::seconds(0),
sequential_strings: Duration::new(0, 0),
random_strings: Duration::new(0, 0),
delete_strings: Duration::new(0, 0),
}
}

View File

@ -10,7 +10,7 @@
// Microbenchmarks for various functions in std and extra
#![feature(rand, collections, std_misc)]
#![feature(rand, collections, std_misc, duration, duration_span)]
use std::iter::repeat;
use std::mem::swap;
@ -52,7 +52,7 @@ fn maybe_run_test<F>(argv: &[String], name: String, test: F) where F: FnOnce() {
let dur = Duration::span(test);
println!("{}:\t\t{} ms", name, dur.num_milliseconds());
println!("{}:\t\t{}", name, dur);
}
fn shift_push() {

View File

@ -18,7 +18,7 @@
// different scalability characteristics compared to the select
// version.
#![feature(std_misc)]
#![feature(duration, duration_span)]
use std::sync::mpsc::{channel, Sender, Receiver};
use std::env;
@ -88,9 +88,9 @@ fn run(args: &[String]) {
});
let result = result.unwrap();
print!("Count is {}\n", result);
print!("Test took {} ms\n", dur.num_milliseconds());
let thruput = ((size / workers * workers) as f64) / (dur.num_milliseconds() as f64);
print!("Throughput={} per sec\n", thruput / 1000.0);
print!("Test took {}\n", dur);
let thruput = ((size / workers * workers) as f64) / (dur.secs() as f64);
print!("Throughput={} per sec\n", thruput);
assert_eq!(result, num_bytes * size);
}

View File

@ -14,7 +14,7 @@
//
// I *think* it's the same, more or less.
#![feature(std_misc)]
#![feature(duration, duration_span)]
use std::sync::mpsc::{channel, Sender, Receiver};
use std::env;
@ -95,9 +95,9 @@ fn run(args: &[String]) {
});
let result = result.unwrap();
print!("Count is {}\n", result);
print!("Test took {} ms\n", dur.num_milliseconds());
let thruput = ((size / workers * workers) as f64) / (dur.num_milliseconds() as f64);
print!("Throughput={} per sec\n", thruput / 1000.0);
print!("Test took {}\n", dur);
let thruput = ((size / workers * workers) as f64) / (dur.secs() as f64);
print!("Throughput={} per sec\n", thruput);
assert_eq!(result, num_bytes * size);
}

View File

@ -17,7 +17,7 @@
// no-pretty-expanded FIXME #15189
#![feature(std_misc)]
#![feature(duration, duration_span, std_misc)]
use std::env;
use std::sync::{Arc, Future, Mutex, Condvar};
@ -107,9 +107,9 @@ fn main() {
// all done, report stats.
let num_msgs = num_tasks * msg_per_task;
let rate = (num_msgs as f64) / (dur.num_milliseconds() as f64);
let rate = (num_msgs as f64) / (dur.secs() as f64);
println!("Sent {} messages in {} ms", num_msgs, dur.num_milliseconds());
println!(" {} messages / second", rate / 1000.0);
println!(" {} μs / message", 1000000. / rate / 1000.0);
println!("Sent {} messages in {}", num_msgs, dur);
println!(" {} messages / second", rate);
println!(" {} μs / message", 1000000. / rate);
}

View File

@ -18,7 +18,7 @@
*/
#![feature(std_misc, rustc_private)]
#![feature(duration, duration_span, rustc_private)]
extern crate getopts;

View File

@ -10,7 +10,7 @@
// Microbenchmark for the smallintmap library
#![feature(collections, std_misc)]
#![feature(collections, duration, duration_span)]
use std::collections::VecMap;
use std::env;
@ -40,8 +40,8 @@ fn main() {
let max = args[1].parse::<usize>().unwrap();
let rep = args[2].parse::<usize>().unwrap();
let mut checkf = Duration::seconds(0);
let mut appendf = Duration::seconds(0);
let mut checkf = Duration::new(0, 0);
let mut appendf = Duration::new(0, 0);
for _ in 0..rep {
let mut map = VecMap::new();
@ -55,7 +55,7 @@ fn main() {
let maxf = max as f64;
println!("insert(): {} seconds\n", checkf);
println!(" : {} op/ms\n", maxf / checkf.num_milliseconds() as f64);
println!(" : {} op/s\n", maxf / checkf.secs() as f64);
println!("get() : {} seconds\n", appendf);
println!(" : {} op/ms\n", maxf / appendf.num_milliseconds() as f64);
println!(" : {} op/s\n", maxf / appendf.secs() as f64);
}

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(box_syntax, std_misc, collections)]
#![feature(box_syntax, duration, duration_span, collections)]
use std::env;
use std::thread;

View File

@ -16,7 +16,7 @@
// instead of in std.
#![reexport_test_harness_main = "test_main"]
#![feature(libc, std_misc)]
#![feature(libc, std_misc, duration)]
extern crate libc;

View File

@ -10,7 +10,7 @@
// pretty-expanded FIXME #23616
#![feature(std_misc, alloc)]
#![feature(std_misc, alloc, static_condvar)]
use std::sync;