From 5778ed4c926da6069ab899c8d4694527ed89190c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 14 Jul 2014 19:18:07 -0700 Subject: [PATCH 01/22] std: Add a Duration type Taken from rust-chrono[1]. Needed for timers per #11189. Experimental. [1]: https://github.com/lifthrasiir/rust-chrono --- src/libstd/duration.rs | 415 +++++++++++++++++++++++++++++++++++++++++ src/libstd/lib.rs | 2 + 2 files changed, 417 insertions(+) create mode 100644 src/libstd/duration.rs diff --git a/src/libstd/duration.rs b/src/libstd/duration.rs new file mode 100644 index 0000000000000..7bc07d7acb6c8 --- /dev/null +++ b/src/libstd/duration.rs @@ -0,0 +1,415 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Temporal quantification + +#![experimental] +#![allow(missing_doc)] // FIXME + +use {fmt, num, i32}; +use option::{Option, Some, None}; +use result::{Result, Ok, Err}; +use ops::{Neg, Add, Sub, Mul, Div}; +use num::{CheckedAdd, ToPrimitive}; + +pub static MIN_DAYS: i32 = i32::MIN; +pub static MAX_DAYS: i32 = i32::MAX; + +static NANOS_PER_SEC: i32 = 1_000_000_000; +static SECS_PER_DAY: i32 = 86400; + +macro_rules! earlyexit( + ($e:expr) => (match $e { Some(v) => v, None => return None }) +) + +/// ISO 8601 duration +#[deriving(PartialEq, Eq, PartialOrd, Ord)] +pub struct Duration { + days: i32, + secs: u32, + nanos: u32, +} + +impl Duration { + pub fn new(days: i32, secs: i32, nanos: i32) -> Option { + let (secs_, nanos) = div_mod_floor(nanos, NANOS_PER_SEC); + let secs = earlyexit!(secs.checked_add(&secs_)); + let (days_, secs) = div_mod_floor(secs, SECS_PER_DAY); + let days = earlyexit!(days.checked_add(&days_).and_then(|v| v.to_i32())); + Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 }) + } + + #[inline] + pub fn weeks(weeks: i32) -> Duration { + Duration::days(weeks * 7) + } + + #[inline] + pub fn days(days: i32) -> Duration { + let days = days.to_i32().expect("Duration::days out of bounds"); + Duration { days: days, secs: 0, nanos: 0 } + } + + #[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) } + } + + #[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) } + } + + #[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) } + } + + #[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) } + } + + #[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) } + } + + #[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) } + } + + #[inline] + pub fn ndays(&self) -> i32 { + self.days as i32 + } + + #[inline] + pub fn nseconds(&self) -> u32 { + self.secs as u32 + } + + #[inline] + pub fn nnanoseconds(&self) -> u32 { + self.nanos as u32 + } +} + +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 for Duration { + fn neg(&self) -> Duration { + // FIXME overflow (e.g. `-Duration::days(i32::MIN as i32)`) + let mut days = -(self.days as i32); + 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; + } + Duration { days: days as i32, secs: secs as u32, nanos: nanos as u32 } + } +} + +impl Add 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 { + let mut days = earlyexit!(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 = earlyexit!(days.checked_add(&1)); + } + Some(Duration { days: days, secs: secs, nanos: nanos }) + } +} + +impl Sub 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 { + let mut days = earlyexit!(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 = earlyexit!(days.checked_sub(&1)); + } + Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 }) + } +} + +impl Mul 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 for Duration { + fn div(&self, rhs: &i32) -> Duration { + let (rhs, days, secs, nanos) = if *rhs < 0 { + let negated = -*self; + (-*rhs as i64, negated.days as i64, negated.secs as i64, negated.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!('P'.fmt(f)); + 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}; + use i32; + use num::{CheckedAdd, CheckedSub, Zero}; + use to_string::ToString; + + fn zero() -> Duration { Zero::zero() } + + #[test] + fn test_duration() { + assert!(zero() != Duration::seconds(1)); + 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_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() { + assert_eq!(zero() * i32::MAX, zero()); + assert_eq!(zero() * i32::MIN, zero()); + assert_eq!(Duration::nanoseconds(1) * 0, 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() { + assert_eq!(zero() / i32::MAX, zero()); + assert_eq!(zero() / i32::MIN, 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)); + } + + #[test] + fn test_duration_fmt() { + assert_eq!(zero().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()); + } +} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 20fc7efeb574f..f2db4944de43d 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -233,6 +233,8 @@ pub mod ascii; #[cfg(not(test))] pub mod gc; +pub mod duration; + /* Common traits */ pub mod from_str; From 657b679b158894556628f096a28aab364b605446 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 14 Jul 2014 19:30:05 -0700 Subject: [PATCH 02/22] std: Rename sleep, periodic, and oneshot timers to sleep_ms, etc. Rename io::timer::sleep, Timer::sleep, Timer::oneshot, Timer::periodic, to sleep_ms, oneshot_ms, periodic_ms. These functions all take an integer and interpret it as milliseconds. Replacement functions will be added that take Duration. [breaking-change] --- src/libstd/io/process.rs | 2 +- src/libstd/io/signal.rs | 6 +- src/libstd/io/timer.rs | 102 ++++++++++++++-------------- src/libstd/lib.rs | 2 +- src/libstd/task.rs | 2 +- src/libstd/{duration.rs => time.rs} | 1 + 6 files changed, 58 insertions(+), 57 deletions(-) rename src/libstd/{duration.rs => time.rs} (99%) diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index c82b4831341ef..41a621f6edf62 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -976,7 +976,7 @@ mod tests { assert!(!p.wait().unwrap().success()); return } - timer::sleep(100); + timer::sleep_ms(100); } fail!("never saw the child go away"); }) diff --git a/src/libstd/io/signal.rs b/src/libstd/io/signal.rs index c126866e7159a..4ea91131f17a7 100644 --- a/src/libstd/io/signal.rs +++ b/src/libstd/io/signal.rs @@ -179,7 +179,7 @@ mod test_unix { let mut signal = Listener::new(); signal.register(Interrupt).unwrap(); sigint(); - timer::sleep(10); + timer::sleep_ms(10); match signal.rx.recv() { Interrupt => (), s => fail!("Expected Interrupt, got {:?}", s), @@ -193,7 +193,7 @@ mod test_unix { s1.register(Interrupt).unwrap(); s2.register(Interrupt).unwrap(); sigint(); - timer::sleep(10); + timer::sleep_ms(10); match s1.rx.recv() { Interrupt => (), s => fail!("Expected Interrupt, got {:?}", s), @@ -212,7 +212,7 @@ mod test_unix { s2.register(Interrupt).unwrap(); s2.unregister(Interrupt); sigint(); - timer::sleep(10); + timer::sleep_ms(10); assert_eq!(s2.rx.try_recv(), Err(Empty)); } } diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs index 1c9e428dcad82..906a280020133 100644 --- a/src/libstd/io/timer.rs +++ b/src/libstd/io/timer.rs @@ -70,11 +70,11 @@ pub struct Timer { struct TimerCallback { tx: Sender<()> } /// Sleep the current task for `msecs` milliseconds. -pub fn sleep(msecs: u64) { +pub fn sleep_ms(msecs: u64) { let timer = Timer::new(); let mut timer = timer.ok().expect("timer::sleep: could not create a Timer"); - timer.sleep(msecs) + timer.sleep_ms(msecs) } impl Timer { @@ -91,7 +91,7 @@ impl Timer { /// /// 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) { + pub fn sleep_ms(&mut self, msecs: u64) { self.obj.sleep(msecs); } @@ -129,7 +129,7 @@ impl Timer { /// // The timer object was destroyed, so this will always fail: /// // five_ms.recv() /// ``` - pub fn oneshot(&mut self, msecs: u64) -> Receiver<()> { + pub fn oneshot_ms(&mut self, msecs: u64) -> Receiver<()> { let (tx, rx) = channel(); self.obj.oneshot(msecs, box TimerCallback { tx: tx }); return rx @@ -177,7 +177,7 @@ impl Timer { /// // The timer object was destroyed, so this will always fail: /// // five_ms.recv() /// ``` - pub fn periodic(&mut self, msecs: u64) -> Receiver<()> { + pub fn periodic_ms(&mut self, msecs: u64) -> Receiver<()> { let (tx, rx) = channel(); self.obj.period(msecs, box TimerCallback { tx: tx }); return rx @@ -192,101 +192,101 @@ impl Callback for TimerCallback { #[cfg(test)] mod test { - iotest!(fn test_io_timer_sleep_simple() { + iotest!(fn test_io_timer_sleep_ms_simple() { let mut timer = Timer::new().unwrap(); - timer.sleep(1); + timer.sleep_ms(1); }) - iotest!(fn test_io_timer_sleep_oneshot() { + iotest!(fn test_io_timer_sleep_oneshot_ms() { let mut timer = Timer::new().unwrap(); - timer.oneshot(1).recv(); + timer.oneshot_ms(1).recv(); }) - iotest!(fn test_io_timer_sleep_oneshot_forget() { + iotest!(fn test_io_timer_sleep_oneshot_ms_forget() { let mut timer = Timer::new().unwrap(); - timer.oneshot(100000000000); + timer.oneshot_ms(100000000000); }) - iotest!(fn oneshot_twice() { + iotest!(fn oneshot_ms_twice() { let mut timer = Timer::new().unwrap(); - let rx1 = timer.oneshot(10000); - let rx = timer.oneshot(1); + let rx1 = timer.oneshot_ms(10000); + let rx = timer.oneshot_ms(1); rx.recv(); assert_eq!(rx1.recv_opt(), Err(())); }) - iotest!(fn test_io_timer_oneshot_then_sleep() { + iotest!(fn test_io_timer_oneshot_ms_then_sleep() { let mut timer = Timer::new().unwrap(); - let rx = timer.oneshot(100000000000); - timer.sleep(1); // this should invalidate rx + let rx = timer.oneshot_ms(100000000000); + timer.sleep_ms(1); // this should invalidate rx assert_eq!(rx.recv_opt(), Err(())); }) - iotest!(fn test_io_timer_sleep_periodic() { + iotest!(fn test_io_timer_sleep_periodic_ms() { let mut timer = Timer::new().unwrap(); - let rx = timer.periodic(1); + let rx = timer.periodic_ms(1); rx.recv(); rx.recv(); rx.recv(); }) - iotest!(fn test_io_timer_sleep_periodic_forget() { + iotest!(fn test_io_timer_sleep_periodic_ms_forget() { let mut timer = Timer::new().unwrap(); - timer.periodic(100000000000); + timer.periodic_ms(100000000000); }) - iotest!(fn test_io_timer_sleep_standalone() { - sleep(1) + iotest!(fn test_io_timer_sleep_ms_standalone() { + sleep_ms(1) }) - iotest!(fn oneshot() { + iotest!(fn oneshot_ms() { let mut timer = Timer::new().unwrap(); - let rx = timer.oneshot(1); + let rx = timer.oneshot_ms(1); rx.recv(); assert!(rx.recv_opt().is_err()); - let rx = timer.oneshot(1); + let rx = timer.oneshot_ms(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_ms(100); + let prx = timer.periodic_ms(100); + timer.sleep_ms(1); assert_eq!(orx.recv_opt(), Err(())); assert_eq!(prx.recv_opt(), Err(())); - timer.oneshot(1).recv(); + timer.oneshot_ms(1).recv(); }) - iotest!(fn period() { + iotest!(fn period_ms() { let mut timer = Timer::new().unwrap(); - let rx = timer.periodic(1); + let rx = timer.periodic_ms(1); rx.recv(); rx.recv(); - let rx2 = timer.periodic(1); + let rx2 = timer.periodic_ms(1); rx2.recv(); rx2.recv(); }) - iotest!(fn sleep() { + iotest!(fn sleep_ms() { let mut timer = Timer::new().unwrap(); - timer.sleep(1); - timer.sleep(1); + timer.sleep_ms(1); + timer.sleep_ms(1); }) - iotest!(fn oneshot_fail() { + iotest!(fn oneshot_ms_fail() { let mut timer = Timer::new().unwrap(); - let _rx = timer.oneshot(1); + let _rx = timer.oneshot_ms(1); fail!(); } #[should_fail]) - iotest!(fn period_fail() { + iotest!(fn period_ms_fail() { let mut timer = Timer::new().unwrap(); - let _rx = timer.periodic(1); + let _rx = timer.periodic_ms(1); fail!(); } #[should_fail]) @@ -298,7 +298,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_ms(1000); spawn(proc() { let _ = timer_rx.recv_opt(); @@ -311,31 +311,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_ms(1000); spawn(proc() { let _ = timer_rx.recv_opt(); }); - timer.oneshot(1); + timer.oneshot_ms(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_ms(1000); spawn(proc() { let _ = timer_rx.recv_opt(); }); - timer.sleep(1); + timer.sleep_ms(1); }) iotest!(fn sender_goes_away_oneshot() { let rx = { let mut timer = Timer::new().unwrap(); - timer.oneshot(1000) + timer.oneshot_ms(1000) }; assert_eq!(rx.recv_opt(), Err(())); }) @@ -343,26 +343,26 @@ mod test { iotest!(fn sender_goes_away_period() { let rx = { let mut timer = Timer::new().unwrap(); - timer.periodic(1000) + timer.periodic_ms(1000) }; assert_eq!(rx.recv_opt(), Err(())); }) iotest!(fn receiver_goes_away_oneshot() { let mut timer1 = Timer::new().unwrap(); - timer1.oneshot(1); + timer1.oneshot_ms(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_ms(2); }) iotest!(fn receiver_goes_away_period() { let mut timer1 = Timer::new().unwrap(); - timer1.periodic(1); + timer1.periodic_ms(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_ms(2); }) } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f2db4944de43d..103cd574e7381 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -233,7 +233,7 @@ pub mod ascii; #[cfg(not(test))] pub mod gc; -pub mod duration; +pub mod time; /* Common traits */ diff --git a/src/libstd/task.rs b/src/libstd/task.rs index 19ad81a04834d..96036b54e36e1 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -669,5 +669,5 @@ fn task_abort_no_kill_runtime() { let tb = TaskBuilder::new(); let rx = tb.try_future(proc() {}); mem::drop(rx); - timer::sleep(1000); + timer::sleep_ms(1000); } diff --git a/src/libstd/duration.rs b/src/libstd/time.rs similarity index 99% rename from src/libstd/duration.rs rename to src/libstd/time.rs index 7bc07d7acb6c8..d9a2f4b3cab38 100644 --- a/src/libstd/duration.rs +++ b/src/libstd/time.rs @@ -342,6 +342,7 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) { #[cfg(test)] mod tests { + use option::Some; use super::{Duration, MIN_DAYS, MAX_DAYS}; use i32; use num::{CheckedAdd, CheckedSub, Zero}; From dc8b23bc1ffa227bdc7b95206c7b2dabe32818ac Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 14 Jul 2014 20:03:17 -0700 Subject: [PATCH 03/22] std: Add sleep, oneshot and periodic timers, taking Duration --- src/libstd/io/timer.rs | 97 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs index 906a280020133..ff6ae05bb4951 100644 --- a/src/libstd/io/timer.rs +++ b/src/libstd/io/timer.rs @@ -18,9 +18,11 @@ and create receivers which will receive notifications after a period of time. */ use comm::{Receiver, Sender, channel}; +use time::Duration; use io::{IoResult, IoError}; use kinds::Send; use boxed::Box; +use num::{CheckedMul, CheckedAdd}; use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback}; /// A synchronous timer object @@ -69,6 +71,33 @@ pub struct Timer { struct TimerCallback { tx: Sender<()> } +#[allow(missing_doc)] +trait DurationExtension { + fn in_ms(&self) -> u64; +} + +impl DurationExtension for Duration { + fn in_ms(&self) -> u64 { + if self.ndays() < 0 { fail!("negative duration") } + let nanos = self.nnanoseconds() as u64; + let secs = self.nseconds() as u64; + let days = self.ndays() as u64; + let nanos_in_ms = nanos / 1000; + let secs_in_ms = secs.checked_mul(&1000).expect("overflow"); + let ms_per_day = 24 * 60 * 60 * 1000; // hours/day * min/hour * sec/min * ms/sec + let days_in_ms = days.checked_mul(&ms_per_day).expect("overflow"); + let result = nanos_in_ms; + let result = result.checked_add(&secs_in_ms).expect("overflow"); + let result = result.checked_add(&(days_in_ms as u64)).expect("overflow"); + return result; + } +} + +/// Sleep the current task for the specified duration. +pub fn sleep(duration: Duration) { + sleep_ms(duration.in_ms()) +} + /// Sleep the current task for `msecs` milliseconds. pub fn sleep_ms(msecs: u64) { let timer = Timer::new(); @@ -87,6 +116,14 @@ impl Timer { }).map_err(IoError::from_rtio_error) } + /// 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, duration: Duration) { + self.obj.sleep(duration.in_ms()); + } + /// Blocks the current task for `msecs` milliseconds. /// /// Note that this function will cause any other receivers for this timer to @@ -95,6 +132,23 @@ impl Timer { self.obj.sleep(msecs); } + /// Creates a oneshot receiver which will have a notification sent when + /// the specified duration has elapsed. + /// + /// This does *not* block the current task, but instead returns immediately. + /// + /// Note that this invalidates any previous receiver which has been created + /// by this timer, and that the returned receiver will be invalidated once + /// the timer is destroyed (when it falls out of scope). In particular, if + /// this is called in method-chaining style, the receiver will be + /// invalidated at the end of that statement, and all `recv` calls will + /// fail. + pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> { + let (tx, rx) = channel(); + self.obj.oneshot(duration.in_ms(), box TimerCallback { tx: tx }); + return rx + } + /// Creates a oneshot receiver which will have a notification sent when /// `msecs` milliseconds has elapsed. /// @@ -135,6 +189,25 @@ impl Timer { return rx } + /// Creates a receiver which will have a continuous stream of notifications + /// 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 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 + /// the timer is destroyed (when it falls out of scope). In particular, if + /// this is called in method-chaining style, the receiver will be + /// invalidated at the end of that statement, and all `recv` calls will + /// fail. + pub fn periodic(&mut self, duration: Duration) -> Receiver<()> { + let (tx, rx) = channel(); + self.obj.period(duration.in_ms(), box TimerCallback { tx: tx }); + return rx + } + /// Creates a receiver which will have a continuous stream of notifications /// being sent every `msecs` milliseconds. /// @@ -365,4 +438,28 @@ mod test { // callback do something terrible. timer2.sleep_ms(2); }) + + + iotest!(fn test_io_timer_sleep_duration_simple() { + use time::Duration; + let mut timer = Timer::new().unwrap(); + timer.sleep(Duration::seconds(1)); + }) + + iotest!(fn test_io_timer_sleep_oneshot_duration() { + use time::Duration; + let mut timer = Timer::new().unwrap(); + timer.oneshot(Duration::seconds(1)).recv(); + }) + + iotest!(fn test_io_timer_sleep_periodic_duration() { + use time::Duration; + let mut timer = Timer::new().unwrap(); + let rx = timer.periodic(Duration::seconds(1)); + rx.recv(); + rx.recv(); + rx.recv(); + }) + + } From 18f75a9197a5b535f9804901bfefbaffe373d689 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 23 Jul 2014 18:13:29 -0700 Subject: [PATCH 04/22] std: Add comments to the time module --- src/libstd/time.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/libstd/time.rs b/src/libstd/time.rs index d9a2f4b3cab38..6e347711c1c07 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -29,7 +29,10 @@ macro_rules! earlyexit( ($e:expr) => (match $e { Some(v) => v, None => return None }) ) -/// ISO 8601 duration +/// The representation of a span of time. +/// +/// This type has nanosecond precision, and conforms to the ISO 8601 +/// standard for Date interchange. #[deriving(PartialEq, Eq, PartialOrd, Ord)] pub struct Duration { days: i32, @@ -38,6 +41,7 @@ pub struct Duration { } impl Duration { + /// Create a new `Duration`. pub fn new(days: i32, secs: i32, nanos: i32) -> Option { let (secs_, nanos) = div_mod_floor(nanos, NANOS_PER_SEC); let secs = earlyexit!(secs.checked_add(&secs_)); @@ -46,17 +50,20 @@ impl Duration { Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 }) } + /// Create a new `Duration` from an integer number of weeks. #[inline] pub fn weeks(weeks: i32) -> Duration { Duration::days(weeks * 7) } + /// Create a new `Duration` from an integer number of days. #[inline] pub fn days(days: i32) -> Duration { let days = days.to_i32().expect("Duration::days out of bounds"); Duration { days: days, secs: 0, nanos: 0 } } + /// Create a new `Duration` from an integer number of hours. #[inline] pub fn hours(hours: i32) -> Duration { let (days, hours) = div_mod_floor(hours, (SECS_PER_DAY / 3600)); @@ -64,6 +71,7 @@ impl Duration { Duration { secs: secs as u32, ..Duration::days(days) } } + /// Create a new `Duration` from an integer number of minutes. #[inline] pub fn minutes(mins: i32) -> Duration { let (days, mins) = div_mod_floor(mins, (SECS_PER_DAY / 60)); @@ -71,12 +79,14 @@ impl Duration { Duration { secs: secs as u32, ..Duration::days(days) } } + /// Create a new `Duration` from an integer number of seconds. #[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) } } + /// Create a new `Duration` from an integer number of milliseconds. #[inline] pub fn milliseconds(millis: i32) -> Duration { let (secs, millis) = div_mod_floor(millis, (NANOS_PER_SEC / 1_000_000)); @@ -84,6 +94,7 @@ impl Duration { Duration { nanos: nanos as u32, ..Duration::seconds(secs) } } + /// Create a new `Duration` from an integer number of microseconds. #[inline] pub fn microseconds(micros: i32) -> Duration { let (secs, micros) = div_mod_floor(micros, (NANOS_PER_SEC / 1_000)); @@ -91,22 +102,26 @@ impl Duration { Duration { nanos: nanos as u32, ..Duration::seconds(secs) } } + /// Create a new `Duration` from an integer number of nanoseconds. #[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) } } + /// Return the number of whole days in the `Duration`. #[inline] pub fn ndays(&self) -> i32 { self.days as i32 } + /// Return the fractional number of days in the `Duration` as seconds. #[inline] pub fn nseconds(&self) -> u32 { self.secs as u32 } + /// Return the fractional number of seconds in the `Duration` as nanoseconds. #[inline] pub fn nnanoseconds(&self) -> u32 { self.nanos as u32 From 6cb2093f7496a2539e343677b6f7f5dd2fa5f091 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 28 Jul 2014 15:54:05 -0700 Subject: [PATCH 05/22] std: Update Duration from upstream From rust-chrono 4f34003e03e259bd5cbda0cb4d35325861307cc6 --- src/libstd/io/timer.rs | 34 +--- src/libstd/time.rs | 394 +++++++++++++++++++++++++++++++++-------- 2 files changed, 328 insertions(+), 100 deletions(-) diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs index ff6ae05bb4951..41a0271fff2b8 100644 --- a/src/libstd/io/timer.rs +++ b/src/libstd/io/timer.rs @@ -22,7 +22,6 @@ use time::Duration; use io::{IoResult, IoError}; use kinds::Send; use boxed::Box; -use num::{CheckedMul, CheckedAdd}; use rt::rtio::{IoFactory, LocalIo, RtioTimer, Callback}; /// A synchronous timer object @@ -71,31 +70,16 @@ pub struct Timer { struct TimerCallback { tx: Sender<()> } -#[allow(missing_doc)] -trait DurationExtension { - fn in_ms(&self) -> u64; -} - -impl DurationExtension for Duration { - fn in_ms(&self) -> u64 { - if self.ndays() < 0 { fail!("negative duration") } - let nanos = self.nnanoseconds() as u64; - let secs = self.nseconds() as u64; - let days = self.ndays() as u64; - let nanos_in_ms = nanos / 1000; - let secs_in_ms = secs.checked_mul(&1000).expect("overflow"); - let ms_per_day = 24 * 60 * 60 * 1000; // hours/day * min/hour * sec/min * ms/sec - let days_in_ms = days.checked_mul(&ms_per_day).expect("overflow"); - let result = nanos_in_ms; - let result = result.checked_add(&secs_in_ms).expect("overflow"); - let result = result.checked_add(&(days_in_ms as u64)).expect("overflow"); - return result; - } +fn in_ms(d: Duration) -> u64 { + // FIXME: Do we really want to fail on negative duration? + let ms = d.num_milliseconds(); + if ms < 0 { fail!("negative duration") } + return ms as u64; } /// Sleep the current task for the specified duration. pub fn sleep(duration: Duration) { - sleep_ms(duration.in_ms()) + sleep_ms(in_ms(duration)) } /// Sleep the current task for `msecs` milliseconds. @@ -121,7 +105,7 @@ impl Timer { /// 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, duration: Duration) { - self.obj.sleep(duration.in_ms()); + self.obj.sleep(in_ms(duration)); } /// Blocks the current task for `msecs` milliseconds. @@ -145,7 +129,7 @@ impl Timer { /// fail. pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> { let (tx, rx) = channel(); - self.obj.oneshot(duration.in_ms(), box TimerCallback { tx: tx }); + self.obj.oneshot(in_ms(duration), box TimerCallback { tx: tx }); return rx } @@ -204,7 +188,7 @@ impl Timer { /// fail. pub fn periodic(&mut self, duration: Duration) -> Receiver<()> { let (tx, rx) = channel(); - self.obj.period(duration.in_ms(), box TimerCallback { tx: tx }); + self.obj.period(in_ms(duration), box TimerCallback { tx: tx }); return rx } diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 6e347711c1c07..e51296e5b9bcc 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -11,28 +11,31 @@ //! Temporal quantification #![experimental] -#![allow(missing_doc)] // FIXME -use {fmt, num, i32}; +use {fmt, i32}; +use ops::{Add, Sub, Mul, Div, Neg}; use option::{Option, Some, None}; +use num; +use num::{CheckedAdd, CheckedMul, ToPrimitive}; use result::{Result, Ok, Err}; -use ops::{Neg, Add, Sub, Mul, Div}; -use num::{CheckedAdd, ToPrimitive}; -pub static MIN_DAYS: i32 = i32::MIN; -pub static MAX_DAYS: i32 = i32::MAX; +/// `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! earlyexit( +macro_rules! try_opt( ($e:expr) => (match $e { Some(v) => v, None => return None }) ) -/// The representation of a span of time. -/// -/// This type has nanosecond precision, and conforms to the ISO 8601 -/// standard for Date interchange. +/// 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, @@ -40,30 +43,62 @@ pub struct Duration { nanos: u32, } +/// 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 { - /// Create a new `Duration`. - pub fn new(days: i32, secs: i32, nanos: i32) -> Option { + /// Makes a new `Duration` with given number of days, seconds and nanoseconds. + /// + /// Fails when the duration is out of bounds. + #[inline] + pub fn new(days: i32, secs: i32, nanos: i32) -> Duration { + Duration::new_opt(days, secs, nanos).expect("Duration::new out of bounds") + } + + /// Makes a new `Duration` with given number of days, seconds and nanoseconds. + /// + /// Returns `None` when the duration is out of bounds. + pub fn new_opt(days: i32, secs: i32, nanos: i32) -> Option { let (secs_, nanos) = div_mod_floor(nanos, NANOS_PER_SEC); - let secs = earlyexit!(secs.checked_add(&secs_)); + let secs = try_opt!(secs.checked_add(&secs_)); let (days_, secs) = div_mod_floor(secs, SECS_PER_DAY); - let days = earlyexit!(days.checked_add(&days_).and_then(|v| v.to_i32())); + let days = try_opt!(days.checked_add(&days_).and_then(|v| v.to_i32())); Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 }) } - /// Create a new `Duration` from an integer number of weeks. + /// Makes a new `Duration` with zero seconds. + #[inline] + pub fn zero() -> Duration { + Duration { days: 0, secs: 0, nanos: 0 } + } + + /// 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 { - Duration::days(weeks * 7) + let days = weeks.checked_mul(&7).expect("Duration::weeks out of bounds"); + Duration::days(days) } - /// Create a new `Duration` from an integer number of days. + /// Makes a new `Duration` with given number of days. + /// Equivalent to `Duration::new(days, 0, 0)`. + /// + /// Fails when the duration is out of bounds. #[inline] pub fn days(days: i32) -> Duration { let days = days.to_i32().expect("Duration::days out of bounds"); Duration { days: days, secs: 0, nanos: 0 } } - /// Create a new `Duration` from an integer number of hours. + /// Makes a new `Duration` with given number of hours. + /// Equivalent to `Duration::new(0, hours * 3600, 0)` with overflow checks. + /// + /// Fails when the duration is out of bounds. #[inline] pub fn hours(hours: i32) -> Duration { let (days, hours) = div_mod_floor(hours, (SECS_PER_DAY / 3600)); @@ -71,7 +106,10 @@ impl Duration { Duration { secs: secs as u32, ..Duration::days(days) } } - /// Create a new `Duration` from an integer number of minutes. + /// Makes a new `Duration` with given number of minutes. + /// Equivalent to `Duration::new(0, mins * 60, 0)` with overflow checks. + /// + /// Fails when the duration is out of bounds. #[inline] pub fn minutes(mins: i32) -> Duration { let (days, mins) = div_mod_floor(mins, (SECS_PER_DAY / 60)); @@ -79,14 +117,20 @@ impl Duration { Duration { secs: secs as u32, ..Duration::days(days) } } - /// Create a new `Duration` from an integer number of seconds. + /// Makes a new `Duration` with given number of seconds. + /// Equivalent to `Duration::new(0, secs, 0)`. + /// + /// Fails when the duration is out of bounds. #[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) } } - /// Create a new `Duration` from an integer number of milliseconds. + /// Makes a new `Duration` with given number of milliseconds. + /// Equivalent to `Duration::new(0, 0, millis * 1_000_000)` with overflow checks. + /// + /// Fails when the duration is out of bounds. #[inline] pub fn milliseconds(millis: i32) -> Duration { let (secs, millis) = div_mod_floor(millis, (NANOS_PER_SEC / 1_000_000)); @@ -94,7 +138,10 @@ impl Duration { Duration { nanos: nanos as u32, ..Duration::seconds(secs) } } - /// Create a new `Duration` from an integer number of microseconds. + /// Makes a new `Duration` with given number of microseconds. + /// Equivalent to `Duration::new(0, 0, micros * 1_000)` with overflow checks. + /// + /// Fails when the duration is out of bounds. #[inline] pub fn microseconds(micros: i32) -> Duration { let (secs, micros) = div_mod_floor(micros, (NANOS_PER_SEC / 1_000)); @@ -102,32 +149,141 @@ impl Duration { Duration { nanos: nanos as u32, ..Duration::seconds(secs) } } - /// Create a new `Duration` from an integer number of nanoseconds. + /// Makes a new `Duration` with given number of nanoseconds. + /// Equivalent to `Duration::new(0, 0, nanos)`. + /// + /// Fails when the duration is out of bounds. #[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) } } - /// Return the number of whole days in the `Duration`. + /// 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] - pub fn ndays(&self) -> i32 { - self.days as i32 + pub fn to_tuple(&self) -> (i32, u32, u32) { + (self.days, self.secs, self.nanos) } - /// Return the fractional number of days in the `Duration` as seconds. + /// Same as `to_tuple` but returns a tuple compatible to `to_negated_tuple`. #[inline] - pub fn nseconds(&self) -> u32 { - self.secs as u32 + 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) } - /// Return the fractional number of seconds in the `Duration` as nanoseconds. + /// Returns the total number of whole weeks in the duration. #[inline] - pub fn nnanoseconds(&self) -> u32 { - self.nanos as u32 + 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 (non-leap) 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 { + fn micros((days, secs, nanos): (i64, u32, u32)) -> Option { + 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 { + fn nanos((days, secs, nanos): (i64, u32, u32)) -> Option { + 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 { @@ -141,20 +297,10 @@ impl num::Zero for Duration { } impl Neg for Duration { + #[inline] fn neg(&self) -> Duration { - // FIXME overflow (e.g. `-Duration::days(i32::MIN as i32)`) - let mut days = -(self.days as i32); - 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; - } - Duration { days: days as i32, secs: secs as u32, nanos: nanos as u32 } + let (days, secs, nanos) = self.to_negated_tuple_64(); + Duration { days: days as i32, secs: secs, nanos: nanos } // FIXME can overflow } } @@ -177,7 +323,7 @@ impl Add for Duration { impl num::CheckedAdd for Duration { fn checked_add(&self, rhs: &Duration) -> Option { - let mut days = earlyexit!(self.days.checked_add(&rhs.days)); + 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 { @@ -186,7 +332,7 @@ impl num::CheckedAdd for Duration { } if secs >= SECS_PER_DAY as u32 { secs -= SECS_PER_DAY as u32; - days = earlyexit!(days.checked_add(&1)); + days = try_opt!(days.checked_add(&1)); } Some(Duration { days: days, secs: secs, nanos: nanos }) } @@ -211,7 +357,7 @@ impl Sub for Duration { impl num::CheckedSub for Duration { fn checked_sub(&self, rhs: &Duration) -> Option { - let mut days = earlyexit!(self.days.checked_sub(&rhs.days)); + 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 { @@ -220,7 +366,7 @@ impl num::CheckedSub for Duration { } if secs < 0 { secs += SECS_PER_DAY; - days = earlyexit!(days.checked_sub(&1)); + days = try_opt!(days.checked_sub(&1)); } Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 }) } @@ -256,8 +402,8 @@ impl Mul for Duration { impl Div for Duration { fn div(&self, rhs: &i32) -> Duration { let (rhs, days, secs, nanos) = if *rhs < 0 { - let negated = -*self; - (-*rhs as i64, negated.days as i64, negated.secs as i64, negated.nanos as i64) + 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) }; @@ -276,7 +422,7 @@ impl fmt::Show for Duration { let hasdate = self.days != 0; let hastime = (self.secs != 0 || self.nanos != 0) || !hasdate; - try!('P'.fmt(f)); + try!(write!(f, "P")); if hasdate { // technically speaking the negative part is not the valid ISO 8601, // but we need to print it anyway. @@ -286,11 +432,11 @@ impl fmt::Show for Duration { 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)); + 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)); + try!(write!(f, "T{}.{:06}S", self.secs, self.nanos / 1_000)); } else { - try!(write!(f, "T{},{:09}S", self.secs, self.nanos)); + try!(write!(f, "T{}.{:09}S", self.secs, self.nanos)); } } Ok(()) @@ -354,20 +500,15 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) { (this / other, this % other) } - #[cfg(test)] mod tests { - use option::Some; - use super::{Duration, MIN_DAYS, MAX_DAYS}; - use i32; - use num::{CheckedAdd, CheckedSub, Zero}; - use to_string::ToString; - - fn zero() -> Duration { Zero::zero() } + use super::{Duration, MIN_DAYS, MAX_DAYS, MIN, MAX}; + use std::{i32, i64}; #[test] fn test_duration() { - assert!(zero() != Duration::seconds(1)); + assert_eq!(Duration::zero(), Duration::zero()); + assert!(Duration::zero() != Duration::seconds(1)); 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)); @@ -380,6 +521,105 @@ mod tests { Duration::days(-4) + Duration::seconds(86400-70)); } + #[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::new(1, 2, 3_004_005).num_days(), 1); + assert_eq!(Duration::new(-1, -2, -3_004_005).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() { + 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); + assert_eq!(Duration::new(1, 2, 3_004_005).num_seconds(), 86402); + assert_eq!(Duration::new(-1, -2, -3_004_005).num_seconds(), -86402); + 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() { + 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::new(1, 2, 3_004_005).num_milliseconds(), 86402_003); + assert_eq!(Duration::new(-1, -2, -3_004_005).num_milliseconds(), -86402_003); + 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() { + 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::new(1, 2, 3_004_005).num_microseconds(), Some(86402_003_004)); + assert_eq!(Duration::new(-1, -2, -3_004_005).num_microseconds(), Some(-86402_003_004)); + 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() { + 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::new(1, 2, 3_004_005).num_nanoseconds(), Some(86402_003_004_005)); + assert_eq!(Duration::new(-1, -2, -3_004_005).num_nanoseconds(), Some(-86402_003_004_005)); + 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)), @@ -393,9 +633,9 @@ mod tests { #[test] fn test_duration_mul() { - assert_eq!(zero() * i32::MAX, zero()); - assert_eq!(zero() * i32::MIN, zero()); - assert_eq!(Duration::nanoseconds(1) * 0, zero()); + 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)); @@ -408,8 +648,8 @@ mod tests { #[test] fn test_duration_div() { - assert_eq!(zero() / i32::MAX, zero()); - assert_eq!(zero() / i32::MIN, zero()); + 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)); @@ -418,14 +658,18 @@ mod tests { #[test] fn test_duration_fmt() { - assert_eq!(zero().to_string(), "PT0S".to_string()); + assert_eq!(Duration::zero().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::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()); + "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()); } } From 51e9728292ec4b89de095e2f0c2e92aa60927a88 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 28 Jul 2014 15:58:22 -0700 Subject: [PATCH 06/22] std: Change time::MAX to time::MAX_DURATION, etc. --- src/libstd/time.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/libstd/time.rs b/src/libstd/time.rs index e51296e5b9bcc..8050891e2a921 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -44,9 +44,9 @@ pub struct Duration { } /// The minimum possible `Duration`. -pub static MIN: Duration = Duration { days: MIN_DAYS, secs: 0, nanos: 0 }; +pub static MIN_DURATION: 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, +pub static MAX_DURATION: Duration = Duration { days: MAX_DAYS, secs: SECS_PER_DAY as u32 - 1, nanos: NANOS_PER_SEC as u32 - 1 }; impl Duration { @@ -280,8 +280,8 @@ impl Duration { } impl num::Bounded for Duration { - #[inline] fn min_value() -> Duration { MIN } - #[inline] fn max_value() -> Duration { MAX } + #[inline] fn min_value() -> Duration { MIN_DURATION } + #[inline] fn max_value() -> Duration { MAX_DURATION } } impl num::Zero for Duration { @@ -502,7 +502,7 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) { #[cfg(test)] mod tests { - use super::{Duration, MIN_DAYS, MAX_DAYS, MIN, MAX}; + use super::{Duration, MIN_DAYS, MAX_DAYS, MIN_DURATION, MAX_DURATION}; use std::{i32, i64}; #[test] @@ -534,8 +534,8 @@ mod tests { assert_eq!(Duration::new(-1, -2, -3_004_005).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); + assert_eq!(MAX_DURATION.num_days(), MAX_DAYS); + assert_eq!(MIN_DURATION.num_days(), MIN_DAYS); } #[test] @@ -551,8 +551,8 @@ mod tests { assert_eq!(Duration::new(-1, -2, -3_004_005).num_seconds(), -86402); 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); + assert_eq!(MAX_DURATION.num_seconds(), (MAX_DAYS as i64 + 1) * 86400 - 1); + assert_eq!(MIN_DURATION.num_seconds(), MIN_DAYS as i64 * 86400); } #[test] @@ -568,8 +568,8 @@ mod tests { assert_eq!(Duration::new(-1, -2, -3_004_005).num_milliseconds(), -86402_003); 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); + assert_eq!(MAX_DURATION.num_milliseconds(), (MAX_DAYS as i64 + 1) * 86400_000 - 1); + assert_eq!(MIN_DURATION.num_milliseconds(), MIN_DAYS as i64 * 86400_000); } #[test] @@ -585,8 +585,8 @@ mod tests { assert_eq!(Duration::new(-1, -2, -3_004_005).num_microseconds(), Some(-86402_003_004)); 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); + assert_eq!(MAX_DURATION.num_microseconds(), None); + assert_eq!(MIN_DURATION.num_microseconds(), None); // overflow checks static MICROS_PER_DAY: i64 = 86400_000_000; @@ -607,8 +607,8 @@ mod tests { assert_eq!(Duration::new(-1, -2, -3_004_005).num_nanoseconds(), Some(-86402_003_004_005)); 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); + assert_eq!(MAX_DURATION.num_nanoseconds(), None); + assert_eq!(MIN_DURATION.num_nanoseconds(), None); // overflow checks static NANOS_PER_DAY: i64 = 86400_000_000_000; From 1666dabcbc2628fb4a5e4b9c43a13fd1179112b2 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 28 Jul 2014 16:04:57 -0700 Subject: [PATCH 07/22] std: Remove ms-taking methods from timers --- src/libstd/io/timer.rs | 221 +++++++++-------------------------------- 1 file changed, 49 insertions(+), 172 deletions(-) diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs index 41a0271fff2b8..d9d6bb0f1b3c6 100644 --- a/src/libstd/io/timer.rs +++ b/src/libstd/io/timer.rs @@ -79,15 +79,10 @@ fn in_ms(d: Duration) -> u64 { /// Sleep the current task for the specified duration. pub fn sleep(duration: Duration) { - sleep_ms(in_ms(duration)) -} - -/// Sleep the current task for `msecs` milliseconds. -pub fn sleep_ms(msecs: u64) { let timer = Timer::new(); let mut timer = timer.ok().expect("timer::sleep: could not create a Timer"); - timer.sleep_ms(msecs) + timer.sleep(duration) } impl Timer { @@ -108,14 +103,6 @@ impl Timer { self.obj.sleep(in_ms(duration)); } - /// Blocks the current task for `msecs` milliseconds. - /// - /// Note that this function will cause any other receivers for this timer to - /// be invalidated (the other end will be closed). - pub fn sleep_ms(&mut self, msecs: u64) { - self.obj.sleep(msecs); - } - /// Creates a oneshot receiver which will have a notification sent when /// the specified duration has elapsed. /// @@ -133,46 +120,6 @@ impl Timer { return rx } - /// Creates a oneshot receiver which will have a notification sent when - /// `msecs` milliseconds has elapsed. - /// - /// This does *not* block the current task, but instead returns immediately. - /// - /// Note that this invalidates any previous receiver which has been created - /// by this timer, and that the returned receiver will be invalidated once - /// the timer is destroyed (when it falls out of scope). In particular, if - /// this is called in method-chaining style, the receiver will be - /// invalidated at the end of that statement, and all `recv` calls will - /// fail. - /// - /// # Example - /// - /// ```rust - /// use std::io::Timer; - /// - /// let mut timer = Timer::new().unwrap(); - /// let ten_milliseconds = timer.oneshot(10); - /// - /// for _ in range(0u, 100) { /* do work */ } - /// - /// // blocks until 10 ms after the `oneshot` call - /// ten_milliseconds.recv(); - /// ``` - /// - /// ```rust - /// use std::io::Timer; - /// - /// // Incorrect, method chaining-style: - /// let mut five_ms = Timer::new().unwrap().oneshot(5); - /// // The timer object was destroyed, so this will always fail: - /// // five_ms.recv() - /// ``` - pub fn oneshot_ms(&mut self, msecs: u64) -> Receiver<()> { - let (tx, rx) = channel(); - self.obj.oneshot(msecs, box TimerCallback { tx: tx }); - return rx - } - /// Creates a receiver which will have a continuous stream of notifications /// being sent each time the specified duration has elapsed. /// @@ -191,54 +138,6 @@ impl Timer { self.obj.period(in_ms(duration), box TimerCallback { tx: tx }); return rx } - - /// Creates a receiver which will have a continuous stream of notifications - /// being sent every `msecs` milliseconds. - /// - /// 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. - /// - /// Note that this invalidates any previous receiver which has been created - /// by this timer, and that the returned receiver will be invalidated once - /// the timer is destroyed (when it falls out of scope). In particular, if - /// this is called in method-chaining style, the receiver will be - /// invalidated at the end of that statement, and all `recv` calls will - /// fail. - /// - /// # Example - /// - /// ```rust - /// use std::io::Timer; - /// - /// let mut timer = Timer::new().unwrap(); - /// let ten_milliseconds = timer.periodic(10); - /// - /// for _ in range(0u, 100) { /* do work */ } - /// - /// // blocks until 10 ms after the `periodic` call - /// ten_milliseconds.recv(); - /// - /// for _ in range(0u, 100) { /* do work */ } - /// - /// // blocks until 20 ms after the `periodic` call (*not* 10ms after the - /// // previous `recv`) - /// ten_milliseconds.recv(); - /// ``` - /// - /// ```rust - /// use std::io::Timer; - /// - /// // Incorrect, method chaining-style. - /// let mut five_ms = Timer::new().unwrap().periodic(5); - /// // The timer object was destroyed, so this will always fail: - /// // five_ms.recv() - /// ``` - pub fn periodic_ms(&mut self, msecs: u64) -> Receiver<()> { - let (tx, rx) = channel(); - self.obj.period(msecs, box TimerCallback { tx: tx }); - return rx - } } impl Callback for TimerCallback { @@ -249,101 +148,103 @@ impl Callback for TimerCallback { #[cfg(test)] mod test { - iotest!(fn test_io_timer_sleep_ms_simple() { + use time::Duration; + + iotest!(fn test_io_timer_sleep_simple() { let mut timer = Timer::new().unwrap(); - timer.sleep_ms(1); + timer.sleep(Duration::milliseconds(1)); }) - iotest!(fn test_io_timer_sleep_oneshot_ms() { + iotest!(fn test_io_timer_sleep_oneshot() { let mut timer = Timer::new().unwrap(); - timer.oneshot_ms(1).recv(); + timer.oneshot(Duration::milliseconds(1)).recv(); }) - iotest!(fn test_io_timer_sleep_oneshot_ms_forget() { + iotest!(fn test_io_timer_sleep_oneshot_forget() { let mut timer = Timer::new().unwrap(); - timer.oneshot_ms(100000000000); + timer.oneshot(Duration::milliseconds(100000000000)); }) - iotest!(fn oneshot_ms_twice() { + iotest!(fn oneshot_twice() { let mut timer = Timer::new().unwrap(); - let rx1 = timer.oneshot_ms(10000); - let rx = timer.oneshot_ms(1); + let rx1 = timer.oneshot(Duration::milliseconds(10000)); + let rx = timer.oneshot(1); rx.recv(); assert_eq!(rx1.recv_opt(), Err(())); }) - iotest!(fn test_io_timer_oneshot_ms_then_sleep() { + iotest!(fn test_io_timer_oneshot_then_sleep() { let mut timer = Timer::new().unwrap(); - let rx = timer.oneshot_ms(100000000000); - timer.sleep_ms(1); // this should invalidate rx + let rx = timer.oneshot(Duration::milliseconds(100000000000)); + timer.sleep(Duration::milliseconds(1)); // this should invalidate rx assert_eq!(rx.recv_opt(), Err(())); }) - iotest!(fn test_io_timer_sleep_periodic_ms() { + iotest!(fn test_io_timer_sleep_periodic() { let mut timer = Timer::new().unwrap(); - let rx = timer.periodic_ms(1); + let rx = timer.periodic(Duration::milliseconds(1)); rx.recv(); rx.recv(); rx.recv(); }) - iotest!(fn test_io_timer_sleep_periodic_ms_forget() { + iotest!(fn test_io_timer_sleep_periodic_forget() { let mut timer = Timer::new().unwrap(); - timer.periodic_ms(100000000000); + timer.periodic(Duration::milliseconds(100000000000)); }) - iotest!(fn test_io_timer_sleep_ms_standalone() { - sleep_ms(1) + iotest!(fn test_io_timer_sleep_standalone() { + sleep(Duration::milliseconds(1)) }) - iotest!(fn oneshot_ms() { + iotest!(fn oneshot() { let mut timer = Timer::new().unwrap(); - let rx = timer.oneshot_ms(1); + let rx = timer.oneshot(Duration::milliseconds(1)); rx.recv(); assert!(rx.recv_opt().is_err()); - let rx = timer.oneshot_ms(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_ms(100); - let prx = timer.periodic_ms(100); - timer.sleep_ms(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_ms(1).recv(); + timer.oneshot(Duration::milliseconds(1)).recv(); }) - iotest!(fn period_ms() { + iotest!(fn period() { let mut timer = Timer::new().unwrap(); - let rx = timer.periodic_ms(1); + let rx = timer.periodic(Duration::milliseconds(1)); rx.recv(); rx.recv(); - let rx2 = timer.periodic_ms(1); + let rx2 = timer.periodic(Durtion::milliseconds(1)); rx2.recv(); rx2.recv(); }) - iotest!(fn sleep_ms() { + iotest!(fn sleep() { let mut timer = Timer::new().unwrap(); - timer.sleep_ms(1); - timer.sleep_ms(1); + timer.sleep(Duration::milliseconds(1)); + timer.sleep(Duration::milliseconds(1)); }) - iotest!(fn oneshot_ms_fail() { + iotest!(fn oneshot_fail() { let mut timer = Timer::new().unwrap(); - let _rx = timer.oneshot_ms(1); + let _rx = timer.oneshot(Duration::milliseconds(1)); fail!(); } #[should_fail]) - iotest!(fn period_ms_fail() { + iotest!(fn period_fail() { let mut timer = Timer::new().unwrap(); - let _rx = timer.periodic_ms(1); + let _rx = timer.periodic(Duration::milliseconds(1)); fail!(); } #[should_fail]) @@ -355,7 +256,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_ms(1000); + let timer_rx = timer.periodic(Duration::milliseconds(1000)); spawn(proc() { let _ = timer_rx.recv_opt(); @@ -368,31 +269,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_ms(1000); + let timer_rx = timer.periodic(Duration::milliseconds(1000)); spawn(proc() { let _ = timer_rx.recv_opt(); }); - timer.oneshot_ms(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_ms(1000); + let timer_rx = timer.periodic(Duration::milliseconds(1000)); spawn(proc() { let _ = timer_rx.recv_opt(); }); - timer.sleep_ms(1); + timer.sleep(Duration::milliseconds(1)); }) iotest!(fn sender_goes_away_oneshot() { let rx = { let mut timer = Timer::new().unwrap(); - timer.oneshot_ms(1000) + timer.oneshot(Duration::milliseconds(1000)) }; assert_eq!(rx.recv_opt(), Err(())); }) @@ -400,50 +301,26 @@ mod test { iotest!(fn sender_goes_away_period() { let rx = { let mut timer = Timer::new().unwrap(); - timer.periodic_ms(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_ms(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_ms(2); + timer2.sleep(Duration::milliseconds(2)); }) iotest!(fn receiver_goes_away_period() { let mut timer1 = Timer::new().unwrap(); - timer1.periodic_ms(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_ms(2); - }) - - - iotest!(fn test_io_timer_sleep_duration_simple() { - use time::Duration; - let mut timer = Timer::new().unwrap(); - timer.sleep(Duration::seconds(1)); - }) - - iotest!(fn test_io_timer_sleep_oneshot_duration() { - use time::Duration; - let mut timer = Timer::new().unwrap(); - timer.oneshot(Duration::seconds(1)).recv(); + timer2.sleep(Duration::milliseconds(2)); }) - - iotest!(fn test_io_timer_sleep_periodic_duration() { - use time::Duration; - let mut timer = Timer::new().unwrap(); - let rx = timer.periodic(Duration::seconds(1)); - rx.recv(); - rx.recv(); - rx.recv(); - }) - - } From 8a5fe8655af5b8927cb6868d715c5bd9fa30c3b3 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 28 Jul 2014 16:25:58 -0700 Subject: [PATCH 08/22] std: Remove the `zero` constructor from `Duration` This is a workaround for having to write `Zero::zero` and will be solved at the language level someday. --- src/libstd/time.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 8050891e2a921..1025d5c06fcd5 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -69,12 +69,6 @@ impl Duration { Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 }) } - /// Makes a new `Duration` with zero seconds. - #[inline] - pub fn zero() -> Duration { - Duration { days: 0, secs: 0, nanos: 0 } - } - /// Makes a new `Duration` with given number of weeks. /// Equivalent to `Duration::new(weeks * 7, 0, 0)` with overflow checks. /// From 734834c7d6e4862c8348a8c9660bb338773047ca Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 30 Jul 2014 13:14:33 -0700 Subject: [PATCH 09/22] std: Restore missing timer examples --- src/libstd/io/timer.rs | 52 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs index d9d6bb0f1b3c6..d9f35ed73e0f9 100644 --- a/src/libstd/io/timer.rs +++ b/src/libstd/io/timer.rs @@ -114,6 +114,29 @@ impl Timer { /// this is called in method-chaining style, the receiver will be /// invalidated at the end of that statement, and all `recv` calls will /// fail. + /// + /// # Example + /// + /// ```rust + /// use std::io::Timer; + /// + /// let mut timer = Timer::new().unwrap(); + /// let ten_milliseconds = timer.oneshot(10); + /// + /// for _ in range(0u, 100) { /* do work */ } + /// + /// // blocks until 10 ms after the `oneshot` call + /// ten_milliseconds.recv(); + /// ``` + /// + /// ```rust + /// use std::io::Timer; + /// + /// // Incorrect, method chaining-style: + /// let mut five_ms = Timer::new().unwrap().oneshot(5); + /// // The timer object was destroyed, so this will always fail: + /// // five_ms.recv() + /// ``` pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> { let (tx, rx) = channel(); self.obj.oneshot(in_ms(duration), box TimerCallback { tx: tx }); @@ -133,6 +156,35 @@ impl Timer { /// this is called in method-chaining style, the receiver will be /// invalidated at the end of that statement, and all `recv` calls will /// fail. + /// + /// # Example + /// + /// ```rust + /// use std::io::Timer; + /// + /// let mut timer = Timer::new().unwrap(); + /// let ten_milliseconds = timer.periodic(10); + /// + /// for _ in range(0u, 100) { /* do work */ } + /// + /// // blocks until 10 ms after the `periodic` call + /// ten_milliseconds.recv(); + /// + /// for _ in range(0u, 100) { /* do work */ } + /// + /// // blocks until 20 ms after the `periodic` call (*not* 10ms after the + /// // previous `recv`) + /// ten_milliseconds.recv(); + /// ``` + /// + /// ```rust + /// use std::io::Timer; + /// + /// // Incorrect, method chaining-style. + /// let mut five_ms = Timer::new().unwrap().periodic(5); + /// // The timer object was destroyed, so this will always fail: + /// // five_ms.recv() + /// ``` pub fn periodic(&mut self, duration: Duration) -> Receiver<()> { let (tx, rx) = channel(); self.obj.period(in_ms(duration), box TimerCallback { tx: tx }); From 63cd4acf535f8df177459559fe2d7e6ab390c6d8 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 30 Jul 2014 20:07:41 -0700 Subject: [PATCH 10/22] std: Clarify what timers do with zero and negative durations Add tests. Also fix a bunch of broken time tests. --- src/libstd/io/process.rs | 2 +- src/libstd/io/signal.rs | 7 ++-- src/libstd/io/test.rs | 1 + src/libstd/io/timer.rs | 89 ++++++++++++++++++++++++++++++++++------ src/libstd/task.rs | 3 +- src/libstd/time.rs | 40 +++++++++++------- 6 files changed, 111 insertions(+), 31 deletions(-) diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 41a621f6edf62..3dd4343c5f4fc 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -976,7 +976,7 @@ mod tests { assert!(!p.wait().unwrap().success()); return } - timer::sleep_ms(100); + timer::sleep(Duration::milliseconds(100)); } fail!("never saw the child go away"); }) diff --git a/src/libstd/io/signal.rs b/src/libstd/io/signal.rs index 4ea91131f17a7..10739c70143cd 100644 --- a/src/libstd/io/signal.rs +++ b/src/libstd/io/signal.rs @@ -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_ms(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_ms(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_ms(10); + timer::sleep(Duration::milliseconds(10)); assert_eq!(s2.rx.try_recv(), Err(Empty)); } } diff --git a/src/libstd/io/test.rs b/src/libstd/io/test.rs index 331cfa1a59ef9..079a9aef648aa 100644 --- a/src/libstd/io/test.rs +++ b/src/libstd/io/test.rs @@ -39,6 +39,7 @@ macro_rules! iotest ( use io::process::*; use rt::running_on_valgrind; use str; + use time::Duration; fn f() $b diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs index d9f35ed73e0f9..0d3f932f4292d 100644 --- a/src/libstd/io/timer.rs +++ b/src/libstd/io/timer.rs @@ -17,6 +17,8 @@ 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}; @@ -71,13 +73,15 @@ pub struct Timer { struct TimerCallback { tx: Sender<()> } fn in_ms(d: Duration) -> u64 { - // FIXME: Do we really want to fail on negative duration? let ms = d.num_milliseconds(); - if ms < 0 { fail!("negative duration") } + if ms < 0 { return 0 }; return ms as 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"); @@ -99,8 +103,14 @@ impl Timer { /// /// Note that this function will cause any other receivers for this timer to /// be invalidated (the other end will be closed). + /// + /// When provided a zero or negative `duration`, the function will + /// return immediately. pub fn sleep(&mut self, duration: Duration) { - self.obj.sleep(in_ms(duration)); + // Short-circuit the timer backend for 0 duration + let ms = in_ms(duration); + if ms == 0 { return } + self.obj.sleep(ms); } /// Creates a oneshot receiver which will have a notification sent when @@ -137,9 +147,17 @@ impl Timer { /// // The timer object was destroyed, so this will always fail: /// // five_ms.recv() /// ``` + /// + /// 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(in_ms(duration), box TimerCallback { tx: tx }); + // Short-circuit the timer backend for 0 duration + if in_ms(duration) != 0 { + self.obj.oneshot(in_ms(duration), box TimerCallback { tx: tx }); + } else { + tx.send(()); + } return rx } @@ -185,9 +203,17 @@ impl Timer { /// // The timer object was destroyed, so this will always fail: /// // five_ms.recv() /// ``` + /// + /// 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(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(in_ms(duration), box TimerCallback { tx: tx }); + self.obj.period(ms, box TimerCallback { tx: tx }); return rx } } @@ -200,8 +226,6 @@ impl Callback for TimerCallback { #[cfg(test)] mod test { - use time::Duration; - iotest!(fn test_io_timer_sleep_simple() { let mut timer = Timer::new().unwrap(); timer.sleep(Duration::milliseconds(1)); @@ -214,20 +238,20 @@ mod test { iotest!(fn test_io_timer_sleep_oneshot_forget() { let mut timer = Timer::new().unwrap(); - timer.oneshot(Duration::milliseconds(100000000000)); + timer.oneshot(Duration::milliseconds(100000000)); }) iotest!(fn oneshot_twice() { let mut timer = Timer::new().unwrap(); let rx1 = timer.oneshot(Duration::milliseconds(10000)); - let rx = timer.oneshot(1); + 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(Duration::milliseconds(100000000000)); + let rx = timer.oneshot(Duration::milliseconds(100000000)); timer.sleep(Duration::milliseconds(1)); // this should invalidate rx assert_eq!(rx.recv_opt(), Err(())); @@ -243,7 +267,7 @@ mod test { iotest!(fn test_io_timer_sleep_periodic_forget() { let mut timer = Timer::new().unwrap(); - timer.periodic(Duration::milliseconds(100000000000)); + timer.periodic(Duration::milliseconds(100000000)); }) iotest!(fn test_io_timer_sleep_standalone() { @@ -277,7 +301,7 @@ mod test { let rx = timer.periodic(Duration::milliseconds(1)); rx.recv(); rx.recv(); - let rx2 = timer.periodic(Durtion::milliseconds(1)); + let rx2 = timer.periodic(Duration::milliseconds(1)); rx2.recv(); rx2.recv(); }) @@ -375,4 +399,45 @@ mod test { // callback do something terrible. 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(); + }) + } diff --git a/src/libstd/task.rs b/src/libstd/task.rs index 96036b54e36e1..9cace9c80ef5a 100644 --- a/src/libstd/task.rs +++ b/src/libstd/task.rs @@ -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_ms(1000); + timer::sleep(Duration::milliseconds(1000)); } diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 1025d5c06fcd5..5a374c37cd87b 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -497,12 +497,16 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) { #[cfg(test)] mod tests { use super::{Duration, MIN_DAYS, MAX_DAYS, MIN_DURATION, MAX_DURATION}; - use std::{i32, i64}; + use {i32, i64}; + use num::{Zero, CheckedAdd, CheckedSub}; + use option::{Some, None}; + use to_string::ToString; #[test] fn test_duration() { - assert_eq!(Duration::zero(), Duration::zero()); - assert!(Duration::zero() != Duration::seconds(1)); + 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)); @@ -517,7 +521,8 @@ mod tests { #[test] fn test_duration_num_days() { - assert_eq!(Duration::zero().num_days(), 0); + 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); @@ -534,7 +539,8 @@ mod tests { #[test] fn test_duration_num_seconds() { - assert_eq!(Duration::zero().num_seconds(), 0); + 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); @@ -551,7 +557,8 @@ mod tests { #[test] fn test_duration_num_milliseconds() { - assert_eq!(Duration::zero().num_milliseconds(), 0); + 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); @@ -568,7 +575,8 @@ mod tests { #[test] fn test_duration_num_microseconds() { - assert_eq!(Duration::zero().num_microseconds(), Some(0)); + 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)); @@ -594,7 +602,8 @@ mod tests { #[test] fn test_duration_num_nanoseconds() { - assert_eq!(Duration::zero().num_nanoseconds(), Some(0)); + 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::new(1, 2, 3_004_005).num_nanoseconds(), Some(86402_003_004_005)); @@ -627,9 +636,10 @@ mod tests { #[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()); + 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)); @@ -642,8 +652,9 @@ mod tests { #[test] fn test_duration_div() { - assert_eq!(Duration::zero() / i32::MAX, Duration::zero()); - assert_eq!(Duration::zero() / i32::MIN, Duration::zero()); + 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)); @@ -652,7 +663,8 @@ mod tests { #[test] fn test_duration_fmt() { - assert_eq!(Duration::zero().to_string(), "PT0S".to_string()); + 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()); From 9fdcddb3178d4705db4aee5ee12c05796203658c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Jul 2014 15:58:39 -0700 Subject: [PATCH 11/22] std: Make the TCP/UDP connect_timeout methods take Duration [breaking-change] --- src/libstd/io/net/tcp.rs | 11 +++++++++-- src/libstd/io/net/unix.rs | 9 +++++---- src/libstd/io/timer.rs | 20 ++++++++++---------- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index 0b0c22ed88799..84065bc936ecd 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -34,6 +34,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. @@ -102,11 +103,11 @@ impl TcpStream { /// and port, similar to the API seen in `connect`. #[experimental = "the timeout argument may eventually change types"] pub fn connect_timeout(addr: SocketAddr, - timeout_ms: u64) -> IoResult { + timeout: Duration) -> IoResult { 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(in_ms_u64(timeout))).map(TcpStream::new) }).map_err(IoError::from_rtio_error) } @@ -443,6 +444,12 @@ impl Acceptor for TcpAcceptor { } } +fn in_ms_u64(d: Duration) -> u64 { + let ms = d.num_milliseconds(); + if ms < 0 { return 0 }; + return ms as u64; +} + #[cfg(test)] #[allow(experimental)] mod test { diff --git a/src/libstd/io/net/unix.rs b/src/libstd/io/net/unix.rs index 5e7c421497772..8847b4c9214ad 100644 --- a/src/libstd/io/net/unix.rs +++ b/src/libstd/io/net/unix.rs @@ -33,6 +33,7 @@ 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 { @@ -68,9 +69,9 @@ impl UnixStream { /// elapses the function will return an error of kind `TimedOut`. #[experimental = "the timeout argument is likely to change types"] pub fn connect_timeout(path: &P, - timeout_ms: u64) -> IoResult { + timeout: Duration) -> IoResult { 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(in_ms_u64(timeout))); s.map(|p| UnixStream { obj: p }) }).map_err(IoError::from_rtio_error) } @@ -499,13 +500,13 @@ 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 close_readwrite_smoke() { diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs index 0d3f932f4292d..3045871ce7ac4 100644 --- a/src/libstd/io/timer.rs +++ b/src/libstd/io/timer.rs @@ -72,12 +72,6 @@ pub struct Timer { struct TimerCallback { tx: Sender<()> } -fn in_ms(d: Duration) -> u64 { - let ms = d.num_milliseconds(); - if ms < 0 { return 0 }; - return ms as u64; -} - /// Sleep the current task for the specified duration. /// /// When provided a zero or negative `duration`, the function will @@ -108,7 +102,7 @@ impl Timer { /// return immediately. pub fn sleep(&mut self, duration: Duration) { // Short-circuit the timer backend for 0 duration - let ms = in_ms(duration); + let ms = in_ms_u64(duration); if ms == 0 { return } self.obj.sleep(ms); } @@ -153,8 +147,8 @@ impl Timer { pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> { let (tx, rx) = channel(); // Short-circuit the timer backend for 0 duration - if in_ms(duration) != 0 { - self.obj.oneshot(in_ms(duration), box TimerCallback { tx: tx }); + if in_ms_u64(duration) != 0 { + self.obj.oneshot(in_ms_u64(duration), box TimerCallback { tx: tx }); } else { tx.send(()); } @@ -207,7 +201,7 @@ impl Timer { /// 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(duration); + 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... @@ -224,6 +218,12 @@ 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() { From 4475e6a095a8fe4459ac8b854ae2336e47aaafe5 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Jul 2014 17:03:27 -0700 Subject: [PATCH 12/22] std: connect_timeout requires a positive Duration This is only breaking if you were previously specifying a duration of zero for some mysterious reason. [breaking-change] --- src/libstd/io/net/tcp.rs | 16 ++++++++-------- src/libstd/io/net/unix.rs | 20 +++++++++++++++++++- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index 84065bc936ecd..76368ac282139 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -93,7 +93,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 @@ -101,13 +101,19 @@ 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`. + /// + /// # Failure + /// + /// Fails on a `timeout` of zero or negative duration. #[experimental = "the timeout argument may eventually change types"] pub fn connect_timeout(addr: SocketAddr, timeout: Duration) -> IoResult { + assert!(timeout > Duration::milliseconds(0)); + 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(in_ms_u64(timeout))).map(TcpStream::new) + io.tcp_connect(addr, Some(timeout.num_milliseconds() as u64)).map(TcpStream::new) }).map_err(IoError::from_rtio_error) } @@ -444,12 +450,6 @@ impl Acceptor for TcpAcceptor { } } -fn in_ms_u64(d: Duration) -> u64 { - let ms = d.num_milliseconds(); - if ms < 0 { return 0 }; - return ms as u64; -} - #[cfg(test)] #[allow(experimental)] mod test { diff --git a/src/libstd/io/net/unix.rs b/src/libstd/io/net/unix.rs index 8847b4c9214ad..0b647e67a2db6 100644 --- a/src/libstd/io/net/unix.rs +++ b/src/libstd/io/net/unix.rs @@ -67,11 +67,17 @@ impl UnixStream { /// /// This function is similar to `connect`, except that if `timeout_ms` /// elapses the function will return an error of kind `TimedOut`. + /// + /// # Failure + /// + /// Fails on a `timeout` of zero or negative duration. #[experimental = "the timeout argument is likely to change types"] pub fn connect_timeout(path: &P, timeout: Duration) -> IoResult { + assert!(timeout > Duration::milliseconds(0)); + LocalIo::maybe_raise(|io| { - let s = io.unix_connect(&path.to_c_str(), Some(in_ms_u64(timeout))); + 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) } @@ -509,6 +515,18 @@ mod tests { 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_ok()); + } #[should_fail]) + + 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_ok()); + } #[should_fail]) + iotest!(fn close_readwrite_smoke() { let addr = next_test_unix(); let a = UnixListener::bind(&addr).listen().unwrap(); From 77cdaf018c98c1a89afcf8382c3f3e90907f49a7 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Jul 2014 17:24:54 -0700 Subject: [PATCH 13/22] std: Refactor time module a bit Put `Duration` in `time::duration`, where the two constants can be called just `MAX` and `MIN`. Reexport from `time`. This provides more room for the time module to expand. --- src/libstd/{time.rs => time/duration.rs} | 30 ++++++++++++------------ src/libstd/time/mod.rs | 15 ++++++++++++ 2 files changed, 30 insertions(+), 15 deletions(-) rename src/libstd/{time.rs => time/duration.rs} (96%) create mode 100644 src/libstd/time/mod.rs diff --git a/src/libstd/time.rs b/src/libstd/time/duration.rs similarity index 96% rename from src/libstd/time.rs rename to src/libstd/time/duration.rs index 5a374c37cd87b..7f31df96b0740 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time/duration.rs @@ -44,9 +44,9 @@ pub struct Duration { } /// The minimum possible `Duration`. -pub static MIN_DURATION: Duration = Duration { days: MIN_DAYS, secs: 0, nanos: 0 }; +pub static MIN: Duration = Duration { days: MIN_DAYS, secs: 0, nanos: 0 }; /// The maximum possible `Duration`. -pub static MAX_DURATION: Duration = Duration { days: MAX_DAYS, secs: SECS_PER_DAY as u32 - 1, +pub static MAX: Duration = Duration { days: MAX_DAYS, secs: SECS_PER_DAY as u32 - 1, nanos: NANOS_PER_SEC as u32 - 1 }; impl Duration { @@ -274,8 +274,8 @@ impl Duration { } impl num::Bounded for Duration { - #[inline] fn min_value() -> Duration { MIN_DURATION } - #[inline] fn max_value() -> Duration { MAX_DURATION } + #[inline] fn min_value() -> Duration { MIN } + #[inline] fn max_value() -> Duration { MAX } } impl num::Zero for Duration { @@ -496,7 +496,7 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) { #[cfg(test)] mod tests { - use super::{Duration, MIN_DAYS, MAX_DAYS, MIN_DURATION, MAX_DURATION}; + use super::{Duration, MIN_DAYS, MAX_DAYS, MIN, MAX}; use {i32, i64}; use num::{Zero, CheckedAdd, CheckedSub}; use option::{Some, None}; @@ -533,8 +533,8 @@ mod tests { assert_eq!(Duration::new(-1, -2, -3_004_005).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_DURATION.num_days(), MAX_DAYS); - assert_eq!(MIN_DURATION.num_days(), MIN_DAYS); + assert_eq!(MAX.num_days(), MAX_DAYS); + assert_eq!(MIN.num_days(), MIN_DAYS); } #[test] @@ -551,8 +551,8 @@ mod tests { assert_eq!(Duration::new(-1, -2, -3_004_005).num_seconds(), -86402); 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_DURATION.num_seconds(), (MAX_DAYS as i64 + 1) * 86400 - 1); - assert_eq!(MIN_DURATION.num_seconds(), MIN_DAYS as i64 * 86400); + assert_eq!(MAX.num_seconds(), (MAX_DAYS as i64 + 1) * 86400 - 1); + assert_eq!(MIN.num_seconds(), MIN_DAYS as i64 * 86400); } #[test] @@ -569,8 +569,8 @@ mod tests { assert_eq!(Duration::new(-1, -2, -3_004_005).num_milliseconds(), -86402_003); 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_DURATION.num_milliseconds(), (MAX_DAYS as i64 + 1) * 86400_000 - 1); - assert_eq!(MIN_DURATION.num_milliseconds(), MIN_DAYS as i64 * 86400_000); + 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] @@ -587,8 +587,8 @@ mod tests { assert_eq!(Duration::new(-1, -2, -3_004_005).num_microseconds(), Some(-86402_003_004)); 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_DURATION.num_microseconds(), None); - assert_eq!(MIN_DURATION.num_microseconds(), None); + assert_eq!(MAX.num_microseconds(), None); + assert_eq!(MIN.num_microseconds(), None); // overflow checks static MICROS_PER_DAY: i64 = 86400_000_000; @@ -610,8 +610,8 @@ mod tests { assert_eq!(Duration::new(-1, -2, -3_004_005).num_nanoseconds(), Some(-86402_003_004_005)); 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_DURATION.num_nanoseconds(), None); - assert_eq!(MIN_DURATION.num_nanoseconds(), None); + assert_eq!(MAX.num_nanoseconds(), None); + assert_eq!(MIN.num_nanoseconds(), None); // overflow checks static NANOS_PER_DAY: i64 = 86400_000_000_000; diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs new file mode 100644 index 0000000000000..436fa5ebdea72 --- /dev/null +++ b/src/libstd/time/mod.rs @@ -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 or the MIT license +// , 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; From 80d32438d665ae74ffb1bc5ad60f7329ed17f39a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 31 Jul 2014 18:03:20 -0700 Subject: [PATCH 14/22] Fix compiletest to use Duration --- src/compiletest/runtest.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index a9c7673d4ddfb..318609f44fda6 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -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(); }); From a391934ba8fb99b999f9956e855316692612f1ab Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 1 Aug 2014 18:05:26 -0700 Subject: [PATCH 15/22] Fix various fallout from timer changes --- src/libgreen/sched.rs | 3 ++- src/libstd/io/net/tcp.rs | 3 ++- src/libstd/io/timer.rs | 22 ++++++++++++++-------- src/libsync/comm/mod.rs | 6 ++++-- src/test/run-pass/core-run-destroy.rs | 3 ++- src/test/run-pass/issue-12684.rs | 4 +++- src/test/run-pass/issue-12699.rs | 3 ++- src/test/run-pass/issue-9396.rs | 3 ++- src/test/run-pass/tcp-connect-timeouts.rs | 7 ++++--- 9 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/libgreen/sched.rs b/src/libgreen/sched.rs index b9144047df5c0..e041547082885 100644 --- a/src/libgreen/sched.rs +++ b/src/libgreen/sched.rs @@ -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)); }); }); diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index 76368ac282139..34ccf9e617a69 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -171,13 +171,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(); /// }); diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs index 3045871ce7ac4..39c6c74e45eef 100644 --- a/src/libstd/io/timer.rs +++ b/src/libstd/io/timer.rs @@ -38,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 @@ -61,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 { @@ -123,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 */ } /// @@ -135,9 +138,10 @@ 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() /// ``` @@ -173,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 */ } /// @@ -191,9 +196,10 @@ 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() /// ``` diff --git a/src/libsync/comm/mod.rs b/src/libsync/comm/mod.rs index 45016b97566ce..e4df661b56201 100644 --- a/src/libsync/comm/mod.rs +++ b/src/libsync/comm/mod.rs @@ -128,10 +128,11 @@ //! //! ```no_run //! use std::io::timer::Timer; +//! use std::time::Duration; //! //! let (tx, rx) = channel::(); //! 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::(); //! 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), diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index 34f1e681608a3..9cee83a8598c7 100644 --- a/src/test/run-pass/core-run-destroy.rs +++ b/src/test/run-pass/core-run-destroy.rs @@ -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) }, diff --git a/src/test/run-pass/issue-12684.rs b/src/test/run-pass/issue-12684.rs index 37e675b52ebd8..e21338746be2c 100644 --- a/src/test/run-pass/issue-12684.rs +++ b/src/test/run-pass/issue-12684.rs @@ -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(); } diff --git a/src/test/run-pass/issue-12699.rs b/src/test/run-pass/issue-12699.rs index c24128f97e372..6b6e770bc99a4 100644 --- a/src/test/run-pass/issue-12699.rs +++ b/src/test/run-pass/issue-12699.rs @@ -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)); } diff --git a/src/test/run-pass/issue-9396.rs b/src/test/run-pass/issue-9396.rs index 9f08f1db41057..c16319a16f282 100644 --- a/src/test/run-pass/issue-9396.rs +++ b/src/test/run-pass/issue-9396.rs @@ -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 { diff --git a/src/test/run-pass/tcp-connect-timeouts.rs b/src/test/run-pass/tcp-connect-timeouts.rs index 6f6fff15814d5..1bdd06ca0e92b 100644 --- a/src/test/run-pass/tcp-connect-timeouts.rs +++ b/src/test/run-pass/tcp-connect-timeouts.rs @@ -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,11 @@ 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()); }) From ee10f3501c1df04a015a5331c8343792e519c7a7 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 4 Aug 2014 16:21:47 -0700 Subject: [PATCH 16/22] std: Make connect_timeout return Err on zero duration [breaking-change] --- src/libstd/io/net/tcp.rs | 10 ++++++---- src/libstd/io/net/unix.rs | 18 ++++++++++-------- src/test/run-pass/tcp-connect-timeouts.rs | 11 +++++++++++ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index 34ccf9e617a69..6d03d4a8eed6d 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -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}; @@ -102,13 +103,14 @@ 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`. /// - /// # Failure - /// - /// Fails on a `timeout` of zero or negative duration. + /// 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: Duration) -> IoResult { - assert!(timeout > Duration::milliseconds(0)); + if timeout <= Duration::milliseconds(0) { + return standard_error(TimedOut); + } let SocketAddr { ip, port } = addr; let addr = rtio::SocketAddr { ip: super::to_rtio(ip), port: port }; diff --git a/src/libstd/io/net/unix.rs b/src/libstd/io/net/unix.rs index 0b647e67a2db6..99e4822afeb9e 100644 --- a/src/libstd/io/net/unix.rs +++ b/src/libstd/io/net/unix.rs @@ -29,6 +29,7 @@ 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}; @@ -68,13 +69,14 @@ impl UnixStream { /// This function is similar to `connect`, except that if `timeout_ms` /// elapses the function will return an error of kind `TimedOut`. /// - /// # Failure - /// - /// Fails on a `timeout` of zero or negative duration. + /// 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(path: &P, timeout: Duration) -> IoResult { - assert!(timeout > Duration::milliseconds(0)); + if timeout <= Duration::milliseconds(0) { + return standard_error(TimedOut); + } LocalIo::maybe_raise(|io| { let s = io.unix_connect(&path.to_c_str(), Some(timeout.num_milliseconds() as u64)); @@ -518,14 +520,14 @@ mod tests { 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_ok()); - } #[should_fail]) + 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_ok()); - } #[should_fail]) + assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(-1)).is_err()); + }) iotest!(fn close_readwrite_smoke() { let addr = next_test_unix(); diff --git a/src/test/run-pass/tcp-connect-timeouts.rs b/src/test/run-pass/tcp-connect-timeouts.rs index 1bdd06ca0e92b..5519963693d7a 100644 --- a/src/test/run-pass/tcp-connect-timeouts.rs +++ b/src/test/run-pass/tcp-connect-timeouts.rs @@ -96,3 +96,14 @@ iotest!(fn timeout_error() { 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()); + }) + From c6b02f65589cd3d1e94fd585ad93a5e720789d5a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 7 Aug 2014 15:45:48 -0700 Subject: [PATCH 17/22] std: Improve Duration comments --- src/libstd/time/duration.rs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 7f31df96b0740..ddec5f8b3b8b5 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -39,8 +39,8 @@ macro_rules! try_opt( #[deriving(PartialEq, Eq, PartialOrd, Ord)] pub struct Duration { days: i32, - secs: u32, - nanos: u32, + secs: u32, // Always < SECS_PER_DAY + nanos: u32, // Always < NANOS_PR_SECOND } /// The minimum possible `Duration`. @@ -81,18 +81,13 @@ impl Duration { /// Makes a new `Duration` with given number of days. /// Equivalent to `Duration::new(days, 0, 0)`. - /// - /// Fails when the duration is out of bounds. #[inline] pub fn days(days: i32) -> Duration { - let days = days.to_i32().expect("Duration::days out of bounds"); 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. - /// - /// Fails when the duration is out of bounds. #[inline] pub fn hours(hours: i32) -> Duration { let (days, hours) = div_mod_floor(hours, (SECS_PER_DAY / 3600)); @@ -102,8 +97,6 @@ impl Duration { /// Makes a new `Duration` with given number of minutes. /// Equivalent to `Duration::new(0, mins * 60, 0)` with overflow checks. - /// - /// Fails when the duration is out of bounds. #[inline] pub fn minutes(mins: i32) -> Duration { let (days, mins) = div_mod_floor(mins, (SECS_PER_DAY / 60)); @@ -113,8 +106,6 @@ impl Duration { /// Makes a new `Duration` with given number of seconds. /// Equivalent to `Duration::new(0, secs, 0)`. - /// - /// Fails when the duration is out of bounds. #[inline] pub fn seconds(secs: i32) -> Duration { let (days, secs) = div_mod_floor(secs, SECS_PER_DAY); @@ -123,8 +114,6 @@ impl Duration { /// Makes a new `Duration` with given number of milliseconds. /// Equivalent to `Duration::new(0, 0, millis * 1_000_000)` with overflow checks. - /// - /// Fails when the duration is out of bounds. #[inline] pub fn milliseconds(millis: i32) -> Duration { let (secs, millis) = div_mod_floor(millis, (NANOS_PER_SEC / 1_000_000)); @@ -134,8 +123,6 @@ impl Duration { /// Makes a new `Duration` with given number of microseconds. /// Equivalent to `Duration::new(0, 0, micros * 1_000)` with overflow checks. - /// - /// Fails when the duration is out of bounds. #[inline] pub fn microseconds(micros: i32) -> Duration { let (secs, micros) = div_mod_floor(micros, (NANOS_PER_SEC / 1_000)); @@ -145,8 +132,6 @@ impl Duration { /// Makes a new `Duration` with given number of nanoseconds. /// Equivalent to `Duration::new(0, 0, nanos)`. - /// - /// Fails when the duration is out of bounds. #[inline] pub fn nanoseconds(nanos: i32) -> Duration { let (secs, nanos) = div_mod_floor(nanos, NANOS_PER_SEC); From 500b600362b4e119dd1725fd99db745341459f82 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 7 Aug 2014 15:48:52 -0700 Subject: [PATCH 18/22] std: Remove Duration::new/new_opt/to_tuple These all expose the underlying data representation and are not the most convenient way of instantiation anyway. --- src/libstd/time/duration.rs | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index ddec5f8b3b8b5..30e5ea44385d7 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -50,25 +50,6 @@ pub static MAX: Duration = Duration { days: MAX_DAYS, secs: SECS_PER_DAY as u32 nanos: NANOS_PER_SEC as u32 - 1 }; impl Duration { - /// Makes a new `Duration` with given number of days, seconds and nanoseconds. - /// - /// Fails when the duration is out of bounds. - #[inline] - pub fn new(days: i32, secs: i32, nanos: i32) -> Duration { - Duration::new_opt(days, secs, nanos).expect("Duration::new out of bounds") - } - - /// Makes a new `Duration` with given number of days, seconds and nanoseconds. - /// - /// Returns `None` when the duration is out of bounds. - pub fn new_opt(days: i32, secs: i32, nanos: i32) -> Option { - let (secs_, nanos) = div_mod_floor(nanos, NANOS_PER_SEC); - let secs = try_opt!(secs.checked_add(&secs_)); - let (days_, secs) = div_mod_floor(secs, SECS_PER_DAY); - let days = try_opt!(days.checked_add(&days_).and_then(|v| v.to_i32())); - Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 }) - } - /// Makes a new `Duration` with given number of weeks. /// Equivalent to `Duration::new(weeks * 7, 0, 0)` with overflow checks. /// @@ -138,14 +119,6 @@ impl Duration { 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] - pub fn to_tuple(&self) -> (i32, u32, u32) { - (self.days, self.secs, self.nanos) - } - /// Same as `to_tuple` but returns a tuple compatible to `to_negated_tuple`. #[inline] fn to_tuple_64(&self) -> (i64, u32, u32) { @@ -514,8 +487,6 @@ mod tests { 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::new(1, 2, 3_004_005).num_days(), 1); - assert_eq!(Duration::new(-1, -2, -3_004_005).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); @@ -532,8 +503,6 @@ mod tests { 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::new(1, 2, 3_004_005).num_seconds(), 86402); - assert_eq!(Duration::new(-1, -2, -3_004_005).num_seconds(), -86402); 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); @@ -550,8 +519,6 @@ mod tests { 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::new(1, 2, 3_004_005).num_milliseconds(), 86402_003); - assert_eq!(Duration::new(-1, -2, -3_004_005).num_milliseconds(), -86402_003); 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); @@ -568,8 +535,6 @@ mod tests { 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::new(1, 2, 3_004_005).num_microseconds(), Some(86402_003_004)); - assert_eq!(Duration::new(-1, -2, -3_004_005).num_microseconds(), Some(-86402_003_004)); 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); @@ -591,8 +556,6 @@ mod tests { 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::new(1, 2, 3_004_005).num_nanoseconds(), Some(86402_003_004_005)); - assert_eq!(Duration::new(-1, -2, -3_004_005).num_nanoseconds(), Some(-86402_003_004_005)); 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); From 31281b4bd12bb4bbd52a23a29f59a3398cca1a8f Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 7 Aug 2014 16:00:22 -0700 Subject: [PATCH 19/22] std: Fix build errors --- src/libstd/io/net/tcp.rs | 2 +- src/libstd/io/net/unix.rs | 2 +- src/libstd/time/duration.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index 6d03d4a8eed6d..5c91c48c55d5b 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -109,7 +109,7 @@ impl TcpStream { pub fn connect_timeout(addr: SocketAddr, timeout: Duration) -> IoResult { if timeout <= Duration::milliseconds(0) { - return standard_error(TimedOut); + return Err(standard_error(TimedOut)); } let SocketAddr { ip, port } = addr; diff --git a/src/libstd/io/net/unix.rs b/src/libstd/io/net/unix.rs index 99e4822afeb9e..d88af8dd30aa3 100644 --- a/src/libstd/io/net/unix.rs +++ b/src/libstd/io/net/unix.rs @@ -75,7 +75,7 @@ impl UnixStream { pub fn connect_timeout(path: &P, timeout: Duration) -> IoResult { if timeout <= Duration::milliseconds(0) { - return standard_error(TimedOut); + return Err(standard_error(TimedOut)); } LocalIo::maybe_raise(|io| { diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 30e5ea44385d7..c8c319f4121b5 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -16,7 +16,7 @@ use {fmt, i32}; use ops::{Add, Sub, Mul, Div, Neg}; use option::{Option, Some, None}; use num; -use num::{CheckedAdd, CheckedMul, ToPrimitive}; +use num::{CheckedAdd, CheckedMul}; use result::{Result, Ok, Err}; From 49a40d8ad15b69410f24423d86954268d1f1503b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 7 Aug 2014 18:22:31 -0700 Subject: [PATCH 20/22] Update docs --- src/libstd/time/duration.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index c8c319f4121b5..2fc7f47dc215e 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -119,7 +119,10 @@ impl Duration { Duration { nanos: nanos as u32, ..Duration::seconds(secs) } } - /// Same as `to_tuple` but returns a tuple compatible to `to_negated_tuple`. + /// 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) @@ -170,7 +173,7 @@ impl Duration { self.num_seconds() / 60 } - /// Returns the total number of (non-leap) whole seconds in the duration. + /// 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 { From 02e39b05c6d3b9f553076af7273233e161bb76a3 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 12 Aug 2014 16:25:21 -0700 Subject: [PATCH 21/22] Add a fixme about Duration representation --- src/libstd/time/duration.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 2fc7f47dc215e..545d1f2aab44f 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -34,6 +34,8 @@ 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)] From 075256a0701e23ce56e9c09206d6c8f581c46115 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 13 Aug 2014 15:26:48 -0700 Subject: [PATCH 22/22] Fix test fallout --- src/test/run-pass/tcp-connect-timeouts.rs | 4 ++-- src/test/run-pass/tcp-stress.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/test/run-pass/tcp-connect-timeouts.rs b/src/test/run-pass/tcp-connect-timeouts.rs index 5519963693d7a..c1d93033ab6fe 100644 --- a/src/test/run-pass/tcp-connect-timeouts.rs +++ b/src/test/run-pass/tcp-connect-timeouts.rs @@ -99,11 +99,11 @@ iotest!(fn timeout_error() { iotest!(fn connect_timeout_zero() { let addr = next_test_ip4(); - assert!(TcpStream::connect_timeout(&addr, Duration::milliseconds(0)).is_err()); + 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()); + assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(-1)).is_err()); }) diff --git a/src/test/run-pass/tcp-stress.rs b/src/test/run-pass/tcp-stress.rs index f52a3455e4157..864d005f37344 100644 --- a/src/test/run-pass/tcp-stress.rs +++ b/src/test/run-pass/tcp-stress.rs @@ -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) } });