auto merge of #15934 : brson/rust/dur, r=aturon

Currently, the Timer methods take an integer number of ms. This is considered a bug because a) types, b) some timers have ns precision.

This plucks the `Duration` type from [rust-chrono](https://github.com/lifthrasiir/rust-chrono), plops it into `std::time`,  and replaces the arguments to `sleep`, `oneshot`, and `periodic` timers with it. It leaves the old methods intact as `sleep_ms`, `oneshot_ms`, and `periodic_ms`, for convenience.

Closes https://github.com/rust-lang/rust/issues/11189.

cc @lifthrasiir @aturon @kballard @alexcrichton
This commit is contained in:
bors 2014-08-13 23:11:28 +00:00
commit 28b5e4588f
19 changed files with 867 additions and 79 deletions

View file

@ -30,6 +30,7 @@ use std::os;
use std::str;
use std::string::String;
use std::task;
use std::time::Duration;
use test::MetricMap;
pub fn run(config: Config, testfile: String) {
@ -400,7 +401,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
.expect(format!("failed to exec `{}`", config.adb_path).as_slice());
loop {
//waiting 1 second for gdbserver start
timer::sleep(1000);
timer::sleep(Duration::milliseconds(1000));
let result = task::try(proc() {
tcp::TcpStream::connect("127.0.0.1", 5039).unwrap();
});

View file

@ -1029,6 +1029,7 @@ mod test {
use std::rt::task::TaskOpts;
use std::rt::task::Task;
use std::rt::local::Local;
use std::time::Duration;
use {TaskState, PoolConfig, SchedPool};
use basic;
@ -1291,7 +1292,7 @@ mod test {
// doesn't exit before emptying the work queue
pool.spawn(TaskOpts::new(), proc() {
spawn(proc() {
timer::sleep(10);
timer::sleep(Duration::milliseconds(10));
});
});

View file

@ -27,6 +27,7 @@ use io::net::addrinfo::get_host_addresses;
use io::net::ip::SocketAddr;
use io::{IoError, ConnectionFailed, InvalidInput};
use io::{Reader, Writer, Listener, Acceptor};
use io::{standard_error, TimedOut};
use from_str::FromStr;
use kinds::Send;
use option::{None, Some, Option};
@ -34,6 +35,7 @@ use boxed::Box;
use rt::rtio::{IoFactory, LocalIo, RtioSocket, RtioTcpListener};
use rt::rtio::{RtioTcpAcceptor, RtioTcpStream};
use rt::rtio;
use time::Duration;
/// A structure which represents a TCP stream between a local socket and a
/// remote socket.
@ -92,7 +94,7 @@ impl TcpStream {
}
/// Creates a TCP connection to a remote socket address, timing out after
/// the specified number of milliseconds.
/// the specified duration.
///
/// This is the same as the `connect` method, except that if the timeout
/// specified (in milliseconds) elapses before a connection is made an error
@ -100,13 +102,20 @@ impl TcpStream {
///
/// Note that the `addr` argument may one day be split into a separate host
/// and port, similar to the API seen in `connect`.
///
/// If a `timeout` with zero or negative duration is specified then
/// the function returns `Err`, with the error kind set to `TimedOut`.
#[experimental = "the timeout argument may eventually change types"]
pub fn connect_timeout(addr: SocketAddr,
timeout_ms: u64) -> IoResult<TcpStream> {
timeout: Duration) -> IoResult<TcpStream> {
if timeout <= Duration::milliseconds(0) {
return Err(standard_error(TimedOut));
}
let SocketAddr { ip, port } = addr;
let addr = rtio::SocketAddr { ip: super::to_rtio(ip), port: port };
LocalIo::maybe_raise(|io| {
io.tcp_connect(addr, Some(timeout_ms)).map(TcpStream::new)
io.tcp_connect(addr, Some(timeout.num_milliseconds() as u64)).map(TcpStream::new)
}).map_err(IoError::from_rtio_error)
}
@ -164,13 +173,14 @@ impl TcpStream {
/// # #![allow(unused_must_use)]
/// use std::io::timer;
/// use std::io::TcpStream;
/// use std::time::Duration;
///
/// let mut stream = TcpStream::connect("127.0.0.1", 34254).unwrap();
/// let stream2 = stream.clone();
///
/// spawn(proc() {
/// // close this stream after one second
/// timer::sleep(1000);
/// timer::sleep(Duration::seconds(1));
/// let mut stream = stream2;
/// stream.close_read();
/// });

View file

@ -29,10 +29,12 @@ use prelude::*;
use c_str::ToCStr;
use clone::Clone;
use io::{Listener, Acceptor, Reader, Writer, IoResult, IoError};
use io::{standard_error, TimedOut};
use kinds::Send;
use boxed::Box;
use rt::rtio::{IoFactory, LocalIo, RtioUnixListener};
use rt::rtio::{RtioUnixAcceptor, RtioPipe};
use time::Duration;
/// A stream which communicates over a named pipe.
pub struct UnixStream {
@ -66,11 +68,18 @@ impl UnixStream {
///
/// This function is similar to `connect`, except that if `timeout_ms`
/// elapses the function will return an error of kind `TimedOut`.
///
/// If a `timeout` with zero or negative duration is specified then
/// the function returns `Err`, with the error kind set to `TimedOut`.
#[experimental = "the timeout argument is likely to change types"]
pub fn connect_timeout<P: ToCStr>(path: &P,
timeout_ms: u64) -> IoResult<UnixStream> {
timeout: Duration) -> IoResult<UnixStream> {
if timeout <= Duration::milliseconds(0) {
return Err(standard_error(TimedOut));
}
LocalIo::maybe_raise(|io| {
let s = io.unix_connect(&path.to_c_str(), Some(timeout_ms));
let s = io.unix_connect(&path.to_c_str(), Some(timeout.num_milliseconds() as u64));
s.map(|p| UnixStream { obj: p })
}).map_err(IoError::from_rtio_error)
}
@ -499,13 +508,25 @@ mod tests {
iotest!(fn connect_timeout_error() {
let addr = next_test_unix();
assert!(UnixStream::connect_timeout(&addr, 100).is_err());
assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(100)).is_err());
})
iotest!(fn connect_timeout_success() {
let addr = next_test_unix();
let _a = UnixListener::bind(&addr).unwrap().listen().unwrap();
assert!(UnixStream::connect_timeout(&addr, 100).is_ok());
assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(100)).is_ok());
})
iotest!(fn connect_timeout_zero() {
let addr = next_test_unix();
let _a = UnixListener::bind(&addr).unwrap().listen().unwrap();
assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(0)).is_err());
})
iotest!(fn connect_timeout_negative() {
let addr = next_test_unix();
let _a = UnixListener::bind(&addr).unwrap().listen().unwrap();
assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(-1)).is_err());
})
iotest!(fn close_readwrite_smoke() {

View file

@ -976,7 +976,7 @@ mod tests {
assert!(!p.wait().unwrap().success());
return
}
timer::sleep(100);
timer::sleep(Duration::milliseconds(100));
}
fail!("never saw the child go away");
})

View file

@ -167,6 +167,7 @@ mod test_unix {
use comm::Empty;
use io::timer;
use super::{Listener, Interrupt};
use time::Duration;
fn sigint() {
unsafe {
@ -179,7 +180,7 @@ mod test_unix {
let mut signal = Listener::new();
signal.register(Interrupt).unwrap();
sigint();
timer::sleep(10);
timer::sleep(Duration::milliseconds(10));
match signal.rx.recv() {
Interrupt => (),
s => fail!("Expected Interrupt, got {:?}", s),
@ -193,7 +194,7 @@ mod test_unix {
s1.register(Interrupt).unwrap();
s2.register(Interrupt).unwrap();
sigint();
timer::sleep(10);
timer::sleep(Duration::milliseconds(10));
match s1.rx.recv() {
Interrupt => (),
s => fail!("Expected Interrupt, got {:?}", s),
@ -212,7 +213,7 @@ mod test_unix {
s2.register(Interrupt).unwrap();
s2.unregister(Interrupt);
sigint();
timer::sleep(10);
timer::sleep(Duration::milliseconds(10));
assert_eq!(s2.rx.try_recv(), Err(Empty));
}
}

View file

@ -39,6 +39,7 @@ macro_rules! iotest (
use io::process::*;
use rt::running_on_valgrind;
use str;
use time::Duration;
fn f() $b

View file

@ -17,7 +17,10 @@ and create receivers which will receive notifications after a period of time.
*/
// FIXME: These functions take Durations but only pass ms to the backend impls.
use comm::{Receiver, Sender, channel};
use time::Duration;
use io::{IoResult, IoError};
use kinds::Send;
use boxed::Box;
@ -35,15 +38,16 @@ use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback};
/// # fn main() {}
/// # fn foo() {
/// use std::io::Timer;
/// use std::time::Duration;
///
/// let mut timer = Timer::new().unwrap();
/// timer.sleep(10); // block the task for awhile
/// timer.sleep(Duration::milliseconds(10)); // block the task for awhile
///
/// let timeout = timer.oneshot(10);
/// let timeout = timer.oneshot(Duration::milliseconds(10));
/// // do some work
/// timeout.recv(); // wait for the timeout to expire
///
/// let periodic = timer.periodic(10);
/// let periodic = timer.periodic(Duration::milliseconds(10));
/// loop {
/// periodic.recv();
/// // this loop is only executed once every 10ms
@ -58,9 +62,10 @@ use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback};
/// # fn main() {}
/// # fn foo() {
/// use std::io::timer;
/// use std::time::Duration;
///
/// // Put this task to sleep for 5 seconds
/// timer::sleep(5000);
/// timer::sleep(Duration::seconds(5));
/// # }
/// ```
pub struct Timer {
@ -69,12 +74,15 @@ pub struct Timer {
struct TimerCallback { tx: Sender<()> }
/// Sleep the current task for `msecs` milliseconds.
pub fn sleep(msecs: u64) {
/// Sleep the current task for the specified duration.
///
/// When provided a zero or negative `duration`, the function will
/// return immediately.
pub fn sleep(duration: Duration) {
let timer = Timer::new();
let mut timer = timer.ok().expect("timer::sleep: could not create a Timer");
timer.sleep(msecs)
timer.sleep(duration)
}
impl Timer {
@ -87,16 +95,22 @@ impl Timer {
}).map_err(IoError::from_rtio_error)
}
/// Blocks the current task for `msecs` milliseconds.
/// Blocks the current task for the specified duration.
///
/// Note that this function will cause any other receivers for this timer to
/// be invalidated (the other end will be closed).
pub fn sleep(&mut self, msecs: u64) {
self.obj.sleep(msecs);
///
/// When provided a zero or negative `duration`, the function will
/// return immediately.
pub fn sleep(&mut self, duration: Duration) {
// Short-circuit the timer backend for 0 duration
let ms = in_ms_u64(duration);
if ms == 0 { return }
self.obj.sleep(ms);
}
/// Creates a oneshot receiver which will have a notification sent when
/// `msecs` milliseconds has elapsed.
/// the specified duration has elapsed.
///
/// This does *not* block the current task, but instead returns immediately.
///
@ -111,9 +125,10 @@ impl Timer {
///
/// ```rust
/// use std::io::Timer;
/// use std::time::Duration;
///
/// let mut timer = Timer::new().unwrap();
/// let ten_milliseconds = timer.oneshot(10);
/// let ten_milliseconds = timer.oneshot(Duration::milliseconds(10));
///
/// for _ in range(0u, 100) { /* do work */ }
///
@ -123,24 +138,33 @@ impl Timer {
///
/// ```rust
/// use std::io::Timer;
/// use std::time::Duration;
///
/// // Incorrect, method chaining-style:
/// let mut five_ms = Timer::new().unwrap().oneshot(5);
/// let mut five_ms = Timer::new().unwrap().oneshot(Duration::milliseconds(5));
/// // The timer object was destroyed, so this will always fail:
/// // five_ms.recv()
/// ```
pub fn oneshot(&mut self, msecs: u64) -> Receiver<()> {
///
/// When provided a zero or negative `duration`, the message will
/// be sent immediately.
pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> {
let (tx, rx) = channel();
self.obj.oneshot(msecs, box TimerCallback { tx: tx });
// Short-circuit the timer backend for 0 duration
if in_ms_u64(duration) != 0 {
self.obj.oneshot(in_ms_u64(duration), box TimerCallback { tx: tx });
} else {
tx.send(());
}
return rx
}
/// Creates a receiver which will have a continuous stream of notifications
/// being sent every `msecs` milliseconds.
/// being sent each time the specified duration has elapsed.
///
/// This does *not* block the current task, but instead returns
/// immediately. The first notification will not be received immediately,
/// but rather after `msec` milliseconds have passed.
/// but rather after the first duration.
///
/// Note that this invalidates any previous receiver which has been created
/// by this timer, and that the returned receiver will be invalidated once
@ -153,9 +177,10 @@ impl Timer {
///
/// ```rust
/// use std::io::Timer;
/// use std::time::Duration;
///
/// let mut timer = Timer::new().unwrap();
/// let ten_milliseconds = timer.periodic(10);
/// let ten_milliseconds = timer.periodic(Duration::milliseconds(10));
///
/// for _ in range(0u, 100) { /* do work */ }
///
@ -171,15 +196,24 @@ impl Timer {
///
/// ```rust
/// use std::io::Timer;
/// use std::time::Duration;
///
/// // Incorrect, method chaining-style.
/// let mut five_ms = Timer::new().unwrap().periodic(5);
/// let mut five_ms = Timer::new().unwrap().periodic(Duration::milliseconds(5));
/// // The timer object was destroyed, so this will always fail:
/// // five_ms.recv()
/// ```
pub fn periodic(&mut self, msecs: u64) -> Receiver<()> {
///
/// When provided a zero or negative `duration`, the messages will
/// be sent without delay.
pub fn periodic(&mut self, duration: Duration) -> Receiver<()> {
let ms = in_ms_u64(duration);
// FIXME: The backend implementations don't ever send a message
// if given a 0 ms duration. Temporarily using 1ms. It's
// not clear what use a 0ms period is anyway...
let ms = if ms == 0 { 1 } else { ms };
let (tx, rx) = channel();
self.obj.period(msecs, box TimerCallback { tx: tx });
self.obj.period(ms, box TimerCallback { tx: tx });
return rx
}
}
@ -190,42 +224,48 @@ impl Callback for TimerCallback {
}
}
fn in_ms_u64(d: Duration) -> u64 {
let ms = d.num_milliseconds();
if ms < 0 { return 0 };
return ms as u64;
}
#[cfg(test)]
mod test {
iotest!(fn test_io_timer_sleep_simple() {
let mut timer = Timer::new().unwrap();
timer.sleep(1);
timer.sleep(Duration::milliseconds(1));
})
iotest!(fn test_io_timer_sleep_oneshot() {
let mut timer = Timer::new().unwrap();
timer.oneshot(1).recv();
timer.oneshot(Duration::milliseconds(1)).recv();
})
iotest!(fn test_io_timer_sleep_oneshot_forget() {
let mut timer = Timer::new().unwrap();
timer.oneshot(100000000000);
timer.oneshot(Duration::milliseconds(100000000));
})
iotest!(fn oneshot_twice() {
let mut timer = Timer::new().unwrap();
let rx1 = timer.oneshot(10000);
let rx = timer.oneshot(1);
let rx1 = timer.oneshot(Duration::milliseconds(10000));
let rx = timer.oneshot(Duration::milliseconds(1));
rx.recv();
assert_eq!(rx1.recv_opt(), Err(()));
})
iotest!(fn test_io_timer_oneshot_then_sleep() {
let mut timer = Timer::new().unwrap();
let rx = timer.oneshot(100000000000);
timer.sleep(1); // this should invalidate rx
let rx = timer.oneshot(Duration::milliseconds(100000000));
timer.sleep(Duration::milliseconds(1)); // this should invalidate rx
assert_eq!(rx.recv_opt(), Err(()));
})
iotest!(fn test_io_timer_sleep_periodic() {
let mut timer = Timer::new().unwrap();
let rx = timer.periodic(1);
let rx = timer.periodic(Duration::milliseconds(1));
rx.recv();
rx.recv();
rx.recv();
@ -233,60 +273,60 @@ mod test {
iotest!(fn test_io_timer_sleep_periodic_forget() {
let mut timer = Timer::new().unwrap();
timer.periodic(100000000000);
timer.periodic(Duration::milliseconds(100000000));
})
iotest!(fn test_io_timer_sleep_standalone() {
sleep(1)
sleep(Duration::milliseconds(1))
})
iotest!(fn oneshot() {
let mut timer = Timer::new().unwrap();
let rx = timer.oneshot(1);
let rx = timer.oneshot(Duration::milliseconds(1));
rx.recv();
assert!(rx.recv_opt().is_err());
let rx = timer.oneshot(1);
let rx = timer.oneshot(Duration::milliseconds(1));
rx.recv();
assert!(rx.recv_opt().is_err());
})
iotest!(fn override() {
let mut timer = Timer::new().unwrap();
let orx = timer.oneshot(100);
let prx = timer.periodic(100);
timer.sleep(1);
let orx = timer.oneshot(Duration::milliseconds(100));
let prx = timer.periodic(Duration::milliseconds(100));
timer.sleep(Duration::milliseconds(1));
assert_eq!(orx.recv_opt(), Err(()));
assert_eq!(prx.recv_opt(), Err(()));
timer.oneshot(1).recv();
timer.oneshot(Duration::milliseconds(1)).recv();
})
iotest!(fn period() {
let mut timer = Timer::new().unwrap();
let rx = timer.periodic(1);
let rx = timer.periodic(Duration::milliseconds(1));
rx.recv();
rx.recv();
let rx2 = timer.periodic(1);
let rx2 = timer.periodic(Duration::milliseconds(1));
rx2.recv();
rx2.recv();
})
iotest!(fn sleep() {
let mut timer = Timer::new().unwrap();
timer.sleep(1);
timer.sleep(1);
timer.sleep(Duration::milliseconds(1));
timer.sleep(Duration::milliseconds(1));
})
iotest!(fn oneshot_fail() {
let mut timer = Timer::new().unwrap();
let _rx = timer.oneshot(1);
let _rx = timer.oneshot(Duration::milliseconds(1));
fail!();
} #[should_fail])
iotest!(fn period_fail() {
let mut timer = Timer::new().unwrap();
let _rx = timer.periodic(1);
let _rx = timer.periodic(Duration::milliseconds(1));
fail!();
} #[should_fail])
@ -298,7 +338,7 @@ mod test {
iotest!(fn closing_channel_during_drop_doesnt_kill_everything() {
// see issue #10375
let mut timer = Timer::new().unwrap();
let timer_rx = timer.periodic(1000);
let timer_rx = timer.periodic(Duration::milliseconds(1000));
spawn(proc() {
let _ = timer_rx.recv_opt();
@ -311,31 +351,31 @@ mod test {
iotest!(fn reset_doesnt_switch_tasks() {
// similar test to the one above.
let mut timer = Timer::new().unwrap();
let timer_rx = timer.periodic(1000);
let timer_rx = timer.periodic(Duration::milliseconds(1000));
spawn(proc() {
let _ = timer_rx.recv_opt();
});
timer.oneshot(1);
timer.oneshot(Duration::milliseconds(1));
})
iotest!(fn reset_doesnt_switch_tasks2() {
// similar test to the one above.
let mut timer = Timer::new().unwrap();
let timer_rx = timer.periodic(1000);
let timer_rx = timer.periodic(Duration::milliseconds(1000));
spawn(proc() {
let _ = timer_rx.recv_opt();
});
timer.sleep(1);
timer.sleep(Duration::milliseconds(1));
})
iotest!(fn sender_goes_away_oneshot() {
let rx = {
let mut timer = Timer::new().unwrap();
timer.oneshot(1000)
timer.oneshot(Duration::milliseconds(1000))
};
assert_eq!(rx.recv_opt(), Err(()));
})
@ -343,26 +383,67 @@ mod test {
iotest!(fn sender_goes_away_period() {
let rx = {
let mut timer = Timer::new().unwrap();
timer.periodic(1000)
timer.periodic(Duration::milliseconds(1000))
};
assert_eq!(rx.recv_opt(), Err(()));
})
iotest!(fn receiver_goes_away_oneshot() {
let mut timer1 = Timer::new().unwrap();
timer1.oneshot(1);
timer1.oneshot(Duration::milliseconds(1));
let mut timer2 = Timer::new().unwrap();
// while sleeping, the previous timer should fire and not have its
// callback do something terrible.
timer2.sleep(2);
timer2.sleep(Duration::milliseconds(2));
})
iotest!(fn receiver_goes_away_period() {
let mut timer1 = Timer::new().unwrap();
timer1.periodic(1);
timer1.periodic(Duration::milliseconds(1));
let mut timer2 = Timer::new().unwrap();
// while sleeping, the previous timer should fire and not have its
// callback do something terrible.
timer2.sleep(2);
timer2.sleep(Duration::milliseconds(2));
})
iotest!(fn sleep_zero() {
let mut timer = Timer::new().unwrap();
timer.sleep(Duration::milliseconds(0));
})
iotest!(fn sleep_negative() {
let mut timer = Timer::new().unwrap();
timer.sleep(Duration::milliseconds(-1000000));
})
iotest!(fn oneshot_zero() {
let mut timer = Timer::new().unwrap();
let rx = timer.oneshot(Duration::milliseconds(0));
rx.recv();
})
iotest!(fn oneshot_negative() {
let mut timer = Timer::new().unwrap();
let rx = timer.oneshot(Duration::milliseconds(-1000000));
rx.recv();
})
iotest!(fn periodic_zero() {
let mut timer = Timer::new().unwrap();
let rx = timer.periodic(Duration::milliseconds(0));
rx.recv();
rx.recv();
rx.recv();
rx.recv();
})
iotest!(fn periodic_negative() {
let mut timer = Timer::new().unwrap();
let rx = timer.periodic(Duration::milliseconds(-1000000));
rx.recv();
rx.recv();
rx.recv();
rx.recv();
})
}

View file

@ -233,6 +233,8 @@ pub mod ascii;
#[cfg(not(test))]
pub mod gc;
pub mod time;
/* Common traits */
pub mod from_str;

View file

@ -664,10 +664,11 @@ mod test {
#[test]
fn task_abort_no_kill_runtime() {
use std::io::timer;
use time::Duration;
use mem;
let tb = TaskBuilder::new();
let rx = tb.try_future(proc() {});
mem::drop(rx);
timer::sleep(1000);
timer::sleep(Duration::milliseconds(1000));
}

634
src/libstd/time/duration.rs Normal file
View file

@ -0,0 +1,634 @@
// 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]
use {fmt, i32};
use ops::{Add, Sub, Mul, Div, Neg};
use option::{Option, Some, None};
use num;
use num::{CheckedAdd, CheckedMul};
use result::{Result, Ok, Err};
/// `Duration`'s `days` component should have no more than this value.
static MIN_DAYS: i32 = i32::MIN;
/// `Duration`'s `days` component should have no less than this value.
static MAX_DAYS: i32 = i32::MAX;
/// The number of nanoseconds in seconds.
static NANOS_PER_SEC: i32 = 1_000_000_000;
/// The number of (non-leap) seconds in days.
static SECS_PER_DAY: i32 = 86400;
macro_rules! try_opt(
($e:expr) => (match $e { Some(v) => v, None => return None })
)
// FIXME #16466: This could be represented as (i64 seconds, u32 nanos)
/// ISO 8601 time duration with nanosecond precision.
/// This also allows for the negative duration; see individual methods for details.
#[deriving(PartialEq, Eq, PartialOrd, Ord)]
pub struct Duration {
days: i32,
secs: u32, // Always < SECS_PER_DAY
nanos: u32, // Always < NANOS_PR_SECOND
}
/// The minimum possible `Duration`.
pub static MIN: Duration = Duration { days: MIN_DAYS, secs: 0, nanos: 0 };
/// The maximum possible `Duration`.
pub static MAX: Duration = Duration { days: MAX_DAYS, secs: SECS_PER_DAY as u32 - 1,
nanos: NANOS_PER_SEC as u32 - 1 };
impl Duration {
/// Makes a new `Duration` with given number of weeks.
/// Equivalent to `Duration::new(weeks * 7, 0, 0)` with overflow checks.
///
/// Fails when the duration is out of bounds.
#[inline]
pub fn weeks(weeks: i32) -> Duration {
let days = weeks.checked_mul(&7).expect("Duration::weeks out of bounds");
Duration::days(days)
}
/// Makes a new `Duration` with given number of days.
/// Equivalent to `Duration::new(days, 0, 0)`.
#[inline]
pub fn days(days: i32) -> Duration {
Duration { days: days, secs: 0, nanos: 0 }
}
/// Makes a new `Duration` with given number of hours.
/// Equivalent to `Duration::new(0, hours * 3600, 0)` with overflow checks.
#[inline]
pub fn hours(hours: i32) -> Duration {
let (days, hours) = div_mod_floor(hours, (SECS_PER_DAY / 3600));
let secs = hours * 3600;
Duration { secs: secs as u32, ..Duration::days(days) }
}
/// Makes a new `Duration` with given number of minutes.
/// Equivalent to `Duration::new(0, mins * 60, 0)` with overflow checks.
#[inline]
pub fn minutes(mins: i32) -> Duration {
let (days, mins) = div_mod_floor(mins, (SECS_PER_DAY / 60));
let secs = mins * 60;
Duration { secs: secs as u32, ..Duration::days(days) }
}
/// Makes a new `Duration` with given number of seconds.
/// Equivalent to `Duration::new(0, secs, 0)`.
#[inline]
pub fn seconds(secs: i32) -> Duration {
let (days, secs) = div_mod_floor(secs, SECS_PER_DAY);
Duration { secs: secs as u32, ..Duration::days(days) }
}
/// Makes a new `Duration` with given number of milliseconds.
/// Equivalent to `Duration::new(0, 0, millis * 1_000_000)` with overflow checks.
#[inline]
pub fn milliseconds(millis: i32) -> Duration {
let (secs, millis) = div_mod_floor(millis, (NANOS_PER_SEC / 1_000_000));
let nanos = millis * 1_000_000;
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
}
/// Makes a new `Duration` with given number of microseconds.
/// Equivalent to `Duration::new(0, 0, micros * 1_000)` with overflow checks.
#[inline]
pub fn microseconds(micros: i32) -> Duration {
let (secs, micros) = div_mod_floor(micros, (NANOS_PER_SEC / 1_000));
let nanos = micros * 1_000;
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
}
/// Makes a new `Duration` with given number of nanoseconds.
/// Equivalent to `Duration::new(0, 0, nanos)`.
#[inline]
pub fn nanoseconds(nanos: i32) -> Duration {
let (secs, nanos) = div_mod_floor(nanos, NANOS_PER_SEC);
Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
}
/// Returns a tuple of the number of days, (non-leap) seconds and
/// nanoseconds in the duration. Note that the number of seconds
/// and nanoseconds are always positive, so that for example
/// `-Duration::seconds(3)` has -1 days and 86,397 seconds.
#[inline]
fn to_tuple_64(&self) -> (i64, u32, u32) {
(self.days as i64, self.secs, self.nanos)
}
/// Negates the duration and returns a tuple like `to_tuple`.
/// This does not overflow and thus is internally used for several methods.
fn to_negated_tuple_64(&self) -> (i64, u32, u32) {
let mut days = -(self.days as i64);
let mut secs = -(self.secs as i32);
let mut nanos = -(self.nanos as i32);
if nanos < 0 {
nanos += NANOS_PER_SEC;
secs -= 1;
}
if secs < 0 {
secs += SECS_PER_DAY;
days -= 1;
}
(days, secs as u32, nanos as u32)
}
/// Returns the total number of whole weeks in the duration.
#[inline]
pub fn num_weeks(&self) -> i32 {
self.num_days() / 7
}
/// Returns the total number of whole days in the duration.
pub fn num_days(&self) -> i32 {
if self.days < 0 {
let negated = -*self;
-negated.days
} else {
self.days
}
}
/// Returns the total number of whole hours in the duration.
#[inline]
pub fn num_hours(&self) -> i64 {
self.num_seconds() / 3600
}
/// Returns the total number of whole minutes in the duration.
#[inline]
pub fn num_minutes(&self) -> i64 {
self.num_seconds() / 60
}
/// Returns the total number of whole seconds in the duration.
pub fn num_seconds(&self) -> i64 {
// cannot overflow, 2^32 * 86400 < 2^64
fn secs((days, secs, _): (i64, u32, u32)) -> i64 {
days as i64 * SECS_PER_DAY as i64 + secs as i64
}
if self.days < 0 {-secs(self.to_negated_tuple_64())} else {secs(self.to_tuple_64())}
}
/// Returns the total number of whole milliseconds in the duration.
pub fn num_milliseconds(&self) -> i64 {
// cannot overflow, 2^32 * 86400 * 1000 < 2^64
fn millis((days, secs, nanos): (i64, u32, u32)) -> i64 {
static MILLIS_PER_SEC: i64 = 1_000;
static NANOS_PER_MILLI: i64 = 1_000_000;
(days as i64 * MILLIS_PER_SEC * SECS_PER_DAY as i64 +
secs as i64 * MILLIS_PER_SEC +
nanos as i64 / NANOS_PER_MILLI)
}
if self.days < 0 {-millis(self.to_negated_tuple_64())} else {millis(self.to_tuple_64())}
}
/// Returns the total number of whole microseconds in the duration,
/// or `None` on the overflow (exceeding 2^63 microseconds in either directions).
pub fn num_microseconds(&self) -> Option<i64> {
fn micros((days, secs, nanos): (i64, u32, u32)) -> Option<i64> {
static MICROS_PER_SEC: i64 = 1_000_000;
static MICROS_PER_DAY: i64 = MICROS_PER_SEC * SECS_PER_DAY as i64;
static NANOS_PER_MICRO: i64 = 1_000;
let nmicros = try_opt!((days as i64).checked_mul(&MICROS_PER_DAY));
let nmicros = try_opt!(nmicros.checked_add(&(secs as i64 * MICROS_PER_SEC)));
let nmicros = try_opt!(nmicros.checked_add(&(nanos as i64 / NANOS_PER_MICRO as i64)));
Some(nmicros)
}
if self.days < 0 {
// the final negation won't overflow since we start with positive numbers.
micros(self.to_negated_tuple_64()).map(|micros| -micros)
} else {
micros(self.to_tuple_64())
}
}
/// Returns the total number of whole nanoseconds in the duration,
/// or `None` on the overflow (exceeding 2^63 nanoseconds in either directions).
pub fn num_nanoseconds(&self) -> Option<i64> {
fn nanos((days, secs, nanos): (i64, u32, u32)) -> Option<i64> {
static NANOS_PER_DAY: i64 = NANOS_PER_SEC as i64 * SECS_PER_DAY as i64;
let nnanos = try_opt!((days as i64).checked_mul(&NANOS_PER_DAY));
let nnanos = try_opt!(nnanos.checked_add(&(secs as i64 * NANOS_PER_SEC as i64)));
let nnanos = try_opt!(nnanos.checked_add(&(nanos as i64)));
Some(nnanos)
}
if self.days < 0 {
// the final negation won't overflow since we start with positive numbers.
nanos(self.to_negated_tuple_64()).map(|micros| -micros)
} else {
nanos(self.to_tuple_64())
}
}
}
impl num::Bounded for Duration {
#[inline] fn min_value() -> Duration { MIN }
#[inline] fn max_value() -> Duration { MAX }
}
impl num::Zero for Duration {
#[inline]
fn zero() -> Duration {
Duration { days: 0, secs: 0, nanos: 0 }
}
#[inline]
fn is_zero(&self) -> bool {
self.days == 0 && self.secs == 0 && self.nanos == 0
}
}
impl Neg<Duration> for Duration {
#[inline]
fn neg(&self) -> Duration {
let (days, secs, nanos) = self.to_negated_tuple_64();
Duration { days: days as i32, secs: secs, nanos: nanos } // FIXME can overflow
}
}
impl Add<Duration,Duration> for Duration {
fn add(&self, rhs: &Duration) -> Duration {
let mut days = self.days + rhs.days;
let mut secs = self.secs + rhs.secs;
let mut nanos = self.nanos + rhs.nanos;
if nanos >= NANOS_PER_SEC as u32 {
nanos -= NANOS_PER_SEC as u32;
secs += 1;
}
if secs >= SECS_PER_DAY as u32 {
secs -= SECS_PER_DAY as u32;
days += 1;
}
Duration { days: days, secs: secs, nanos: nanos }
}
}
impl num::CheckedAdd for Duration {
fn checked_add(&self, rhs: &Duration) -> Option<Duration> {
let mut days = try_opt!(self.days.checked_add(&rhs.days));
let mut secs = self.secs + rhs.secs;
let mut nanos = self.nanos + rhs.nanos;
if nanos >= NANOS_PER_SEC as u32 {
nanos -= NANOS_PER_SEC as u32;
secs += 1;
}
if secs >= SECS_PER_DAY as u32 {
secs -= SECS_PER_DAY as u32;
days = try_opt!(days.checked_add(&1));
}
Some(Duration { days: days, secs: secs, nanos: nanos })
}
}
impl Sub<Duration,Duration> for Duration {
fn sub(&self, rhs: &Duration) -> Duration {
let mut days = self.days - rhs.days;
let mut secs = self.secs as i32 - rhs.secs as i32;
let mut nanos = self.nanos as i32 - rhs.nanos as i32;
if nanos < 0 {
nanos += NANOS_PER_SEC;
secs -= 1;
}
if secs < 0 {
secs += SECS_PER_DAY;
days -= 1;
}
Duration { days: days, secs: secs as u32, nanos: nanos as u32 }
}
}
impl num::CheckedSub for Duration {
fn checked_sub(&self, rhs: &Duration) -> Option<Duration> {
let mut days = try_opt!(self.days.checked_sub(&rhs.days));
let mut secs = self.secs as i32 - rhs.secs as i32;
let mut nanos = self.nanos as i32 - rhs.nanos as i32;
if nanos < 0 {
nanos += NANOS_PER_SEC;
secs -= 1;
}
if secs < 0 {
secs += SECS_PER_DAY;
days = try_opt!(days.checked_sub(&1));
}
Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 })
}
}
impl Mul<i32,Duration> for Duration {
fn mul(&self, rhs: &i32) -> Duration {
/// Given `0 <= y < limit <= 2^30`,
/// returns `(h,l)` such that `x * y = h * limit + l` where `0 <= l < limit`.
fn mul_i64_u32_limit(x: i64, y: u32, limit: u32) -> (i64,u32) {
let y = y as i64;
let limit = limit as i64;
let (xh, xl) = div_mod_floor_64(x, limit);
let (h, l) = (xh * y, xl * y);
let (h_, l) = div_rem_64(l, limit);
(h + h_, l as u32)
}
let rhs = *rhs as i64;
let (secs1, nanos) = mul_i64_u32_limit(rhs, self.nanos, NANOS_PER_SEC as u32);
let (days1, secs1) = div_mod_floor_64(secs1, (SECS_PER_DAY as i64));
let (days2, secs2) = mul_i64_u32_limit(rhs, self.secs, SECS_PER_DAY as u32);
let mut days = self.days as i64 * rhs + days1 + days2;
let mut secs = secs1 as u32 + secs2;
if secs >= SECS_PER_DAY as u32 {
secs -= 1;
days += 1;
}
Duration { days: days as i32, secs: secs, nanos: nanos }
}
}
impl Div<i32,Duration> for Duration {
fn div(&self, rhs: &i32) -> Duration {
let (rhs, days, secs, nanos) = if *rhs < 0 {
let (days, secs, nanos) = self.to_negated_tuple_64();
(-(*rhs as i64), days, secs as i64, nanos as i64)
} else {
(*rhs as i64, self.days as i64, self.secs as i64, self.nanos as i64)
};
let (days, carry) = div_mod_floor_64(days, rhs);
let secs = secs + carry * SECS_PER_DAY as i64;
let (secs, carry) = div_mod_floor_64(secs, rhs);
let nanos = nanos + carry * NANOS_PER_SEC as i64;
let nanos = nanos / rhs;
Duration { days: days as i32, secs: secs as u32, nanos: nanos as u32 }
}
}
impl fmt::Show for Duration {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let hasdate = self.days != 0;
let hastime = (self.secs != 0 || self.nanos != 0) || !hasdate;
try!(write!(f, "P"));
if hasdate {
// technically speaking the negative part is not the valid ISO 8601,
// but we need to print it anyway.
try!(write!(f, "{}D", self.days));
}
if hastime {
if self.nanos == 0 {
try!(write!(f, "T{}S", self.secs));
} else if self.nanos % 1_000_000 == 0 {
try!(write!(f, "T{}.{:03}S", self.secs, self.nanos / 1_000_000));
} else if self.nanos % 1_000 == 0 {
try!(write!(f, "T{}.{:06}S", self.secs, self.nanos / 1_000));
} else {
try!(write!(f, "T{}.{:09}S", self.secs, self.nanos));
}
}
Ok(())
}
}
// Copied from libnum
#[inline]
fn div_mod_floor(this: i32, other: i32) -> (i32, i32) {
(div_floor(this, other), mod_floor(this, other))
}
#[inline]
fn div_floor(this: i32, other: i32) -> i32 {
match div_rem(this, other) {
(d, r) if (r > 0 && other < 0)
|| (r < 0 && other > 0) => d - 1,
(d, _) => d,
}
}
#[inline]
fn mod_floor(this: i32, other: i32) -> i32 {
match this % other {
r if (r > 0 && other < 0)
|| (r < 0 && other > 0) => r + other,
r => r,
}
}
#[inline]
fn div_rem(this: i32, other: i32) -> (i32, i32) {
(this / other, this % other)
}
#[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_DAYS, MAX_DAYS, MIN, MAX};
use {i32, i64};
use num::{Zero, CheckedAdd, CheckedSub};
use option::{Some, None};
use to_string::ToString;
#[test]
fn test_duration() {
let d: Duration = Zero::zero();
assert_eq!(d, Zero::zero());
assert!(Duration::seconds(1) != Zero::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));
}
#[test]
fn test_duration_num_days() {
let d: Duration = Zero::zero();
assert_eq!(d.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).num_days(), i32::MAX);
assert_eq!(Duration::days(i32::MIN).num_days(), i32::MIN);
assert_eq!(MAX.num_days(), MAX_DAYS);
assert_eq!(MIN.num_days(), MIN_DAYS);
}
#[test]
fn test_duration_num_seconds() {
let d: Duration = Zero::zero();
assert_eq!(d.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);
assert_eq!(Duration::seconds(i32::MAX).num_seconds(), i32::MAX as i64);
assert_eq!(Duration::seconds(i32::MIN).num_seconds(), i32::MIN as i64);
assert_eq!(MAX.num_seconds(), (MAX_DAYS as i64 + 1) * 86400 - 1);
assert_eq!(MIN.num_seconds(), MIN_DAYS as i64 * 86400);
}
#[test]
fn test_duration_num_milliseconds() {
let d: Duration = Zero::zero();
assert_eq!(d.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(i32::MAX).num_milliseconds(), i32::MAX as i64);
assert_eq!(Duration::milliseconds(i32::MIN).num_milliseconds(), i32::MIN as i64);
assert_eq!(MAX.num_milliseconds(), (MAX_DAYS as i64 + 1) * 86400_000 - 1);
assert_eq!(MIN.num_milliseconds(), MIN_DAYS as i64 * 86400_000);
}
#[test]
fn test_duration_num_microseconds() {
let d: Duration = Zero::zero();
assert_eq!(d.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(i32::MAX).num_microseconds(), Some(i32::MAX as i64));
assert_eq!(Duration::microseconds(i32::MIN).num_microseconds(), Some(i32::MIN as i64));
assert_eq!(MAX.num_microseconds(), None);
assert_eq!(MIN.num_microseconds(), None);
// overflow checks
static MICROS_PER_DAY: i64 = 86400_000_000;
assert_eq!(Duration::days((i64::MAX / MICROS_PER_DAY) as i32).num_microseconds(),
Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY));
assert_eq!(Duration::days((i64::MIN / MICROS_PER_DAY) as i32).num_microseconds(),
Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY));
assert_eq!(Duration::days((i64::MAX / MICROS_PER_DAY + 1) as i32).num_microseconds(), None);
assert_eq!(Duration::days((i64::MIN / MICROS_PER_DAY - 1) as i32).num_microseconds(), None);
}
#[test]
fn test_duration_num_nanoseconds() {
let d: Duration = Zero::zero();
assert_eq!(d.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(i32::MAX).num_nanoseconds(), Some(i32::MAX as i64));
assert_eq!(Duration::nanoseconds(i32::MIN).num_nanoseconds(), Some(i32::MIN as i64));
assert_eq!(MAX.num_nanoseconds(), None);
assert_eq!(MIN.num_nanoseconds(), None);
// overflow checks
static NANOS_PER_DAY: i64 = 86400_000_000_000;
assert_eq!(Duration::days((i64::MAX / NANOS_PER_DAY) as i32).num_nanoseconds(),
Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY));
assert_eq!(Duration::days((i64::MIN / NANOS_PER_DAY) as i32).num_nanoseconds(),
Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY));
assert_eq!(Duration::days((i64::MAX / NANOS_PER_DAY + 1) as i32).num_nanoseconds(), None);
assert_eq!(Duration::days((i64::MIN / NANOS_PER_DAY - 1) as i32).num_nanoseconds(), None);
}
#[test]
fn test_duration_checked_ops() {
assert_eq!(Duration::days(MAX_DAYS).checked_add(&Duration::seconds(86399)),
Some(Duration::days(MAX_DAYS - 1) + Duration::seconds(86400+86399)));
assert!(Duration::days(MAX_DAYS).checked_add(&Duration::seconds(86400)).is_none());
assert_eq!(Duration::days(MIN_DAYS).checked_sub(&Duration::seconds(0)),
Some(Duration::days(MIN_DAYS)));
assert!(Duration::days(MIN_DAYS).checked_sub(&Duration::seconds(1)).is_none());
}
#[test]
fn test_duration_mul() {
let d: Duration = Zero::zero();
assert_eq!(d * i32::MAX, d);
assert_eq!(d * i32::MIN, d);
assert_eq!(Duration::nanoseconds(1) * 0, Zero::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));
}
#[test]
fn test_duration_div() {
let d: Duration = Zero::zero();
assert_eq!(d / i32::MAX, d);
assert_eq!(d / i32::MIN, d);
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));
}
#[test]
fn test_duration_fmt() {
let d: Duration = Zero::zero();
assert_eq!(d.to_string(), "PT0S".to_string());
assert_eq!(Duration::days(42).to_string(), "P42D".to_string());
assert_eq!(Duration::days(-42).to_string(), "P-42D".to_string());
assert_eq!(Duration::seconds(42).to_string(), "PT42S".to_string());
assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S".to_string());
assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S".to_string());
assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S".to_string());
assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(),
"P7DT6.543S".to_string());
// the format specifier should have no effect on `Duration`
assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)),
"P1DT2.345S".to_string());
}
}

15
src/libstd/time/mod.rs Normal file
View file

@ -0,0 +1,15 @@
// 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.
pub use self::duration::Duration;
pub mod duration;

View file

@ -128,10 +128,11 @@
//!
//! ```no_run
//! use std::io::timer::Timer;
//! use std::time::Duration;
//!
//! let (tx, rx) = channel::<int>();
//! let mut timer = Timer::new().unwrap();
//! let timeout = timer.oneshot(10000);
//! let timeout = timer.oneshot(Duration::seconds(10));
//!
//! loop {
//! select! {
@ -150,12 +151,13 @@
//!
//! ```no_run
//! use std::io::timer::Timer;
//! use std::time::Duration;
//!
//! let (tx, rx) = channel::<int>();
//! let mut timer = Timer::new().unwrap();
//!
//! loop {
//! let timeout = timer.oneshot(5000);
//! let timeout = timer.oneshot(Duration::seconds(5));
//!
//! select! {
//! val = rx.recv() => println!("Received {}", val),

View file

@ -25,6 +25,7 @@ extern crate green;
extern crate rustuv;
use std::io::{Process, Command};
use std::time::Duration;
macro_rules! succeed( ($e:expr) => (
match $e { Ok(..) => {}, Err(e) => fail!("failure: {}", e) }
@ -115,7 +116,7 @@ pub fn test_destroy_actually_kills(force: bool) {
// Don't let this test time out, this should be quick
let (tx, rx1) = channel();
let mut t = timer::Timer::new().unwrap();
let rx2 = t.oneshot(1000);
let rx2 = t.oneshot(Duration::milliseconds(1000));
spawn(proc() {
select! {
() = rx2.recv() => unsafe { libc::exit(1) },

View file

@ -13,6 +13,8 @@ extern crate native;
extern crate green;
extern crate rustuv;
use std::time::Duration;
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
green::start(argc, argv, rustuv::event_loop, main)
@ -24,6 +26,6 @@ fn main() {
fn customtask() {
let mut timer = std::io::timer::Timer::new().unwrap();
let periodic = timer.periodic(10);
let periodic = timer.periodic(Duration::milliseconds(10));
periodic.recv();
}

View file

@ -12,6 +12,7 @@
extern crate native;
use std::io::timer;
use std::time::Duration;
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
@ -19,5 +20,5 @@ fn start(argc: int, argv: *const *const u8) -> int {
}
fn main() {
timer::sleep(250);
timer::sleep(Duration::milliseconds(250));
}

View file

@ -10,12 +10,13 @@
use std::comm;
use std::io::timer::Timer;
use std::time::Duration;
pub fn main() {
let (tx, rx) = channel();
spawn(proc (){
let mut timer = Timer::new().unwrap();
timer.sleep(10);
timer.sleep(Duration::milliseconds(10));
tx.send(());
});
loop {

View file

@ -38,6 +38,7 @@ macro_rules! iotest (
use std::io::net::tcp::*;
use std::io::test::*;
use std::io;
use std::time::Duration;
fn f() $b
@ -72,7 +73,7 @@ iotest!(fn eventual_timeout() {
let mut v = Vec::new();
for _ in range(0u, 10000) {
match TcpStream::connect_timeout(addr, 100) {
match TcpStream::connect_timeout(addr, Duration::milliseconds(100)) {
Ok(e) => v.push(e),
Err(ref e) if e.kind == io::TimedOut => return,
Err(e) => fail!("other error: {}", e),
@ -87,11 +88,22 @@ iotest!(fn timeout_success() {
let port = addr.port;
let _l = TcpListener::bind(host.as_slice(), port).unwrap().listen();
assert!(TcpStream::connect_timeout(addr, 1000).is_ok());
assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(1000)).is_ok());
})
iotest!(fn timeout_error() {
let addr = next_test_ip4();
assert!(TcpStream::connect_timeout(addr, 1000).is_err());
assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(1000)).is_err());
})
iotest!(fn connect_timeout_zero() {
let addr = next_test_ip4();
assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(0)).is_err());
})
iotest!(fn connect_timeout_negative() {
let addr = next_test_ip4();
assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(-1)).is_err());
})

View file

@ -23,6 +23,7 @@ extern crate debug;
use std::io::net::tcp::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::task::TaskBuilder;
use std::time::Duration;
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
@ -33,7 +34,7 @@ fn main() {
// This test has a chance to time out, try to not let it time out
spawn(proc() {
use std::io::timer;
timer::sleep(30 * 1000);
timer::sleep(Duration::milliseconds(30 * 1000));
println!("timed out!");
unsafe { libc::exit(1) }
});