///|
/// A `@sync.Timer` that bounds work on a clock, so sans-IO code such as
/// `gaato/sdk-runtime` can put a deadline on an attempt without importing
/// an async runtime.
pub struct ClockTimer {
priv clock : &@clock.Clock
}
///|
/// Creates a timer on `clock`, the wall clock by default. Pass the clock the
/// transport times its phases on, or a `VirtualClock` in tests.
///
/// ```mbt check
/// async test {
/// let timer = @adapter.ClockTimer::new()
/// let done = Ref(false)
/// assert_true(timer.within(1000, () => done.val = true))
/// assert_true(done.val)
/// }
/// ```
pub fn ClockTimer::new(clock? : &@clock.Clock) -> ClockTimer {
{ clock: clock.unwrap_or_else(() => AsyncClock::new()), }
}
///|
/// Explicit timer methods backed by the clock.
pub extend ClockTimer with @sync.Timer::{within}
///|
/// Runs `f` until it finishes or `milliseconds` pass on the clock, whichever
/// comes first; `false` means time ran out and `f` was cancelled. A
/// nonpositive budget returns `false` without starting `f`. Runtime
/// cancellation of the caller still propagates as a signal.
pub impl @sync.Timer for ClockTimer with fn within(self, milliseconds, f) {
if milliseconds <= 0 {
return false
}
let finished = with_timeout_opt(self.clock, milliseconds, () => f()) catch {
_ => None
}
finished is Some(_)
}