1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
//! A configurable source of time. //! //! This module provides an API to get the current instant in such a way that //! the source of time may be configured. This allows mocking out the source of //! time in tests. //! //! The [`now`][n] function returns the current [`Instant`]. By default, it delegates //! to [`Instant::now`]. //! //! The source of time used by [`now`][n] can be configured by implementing the //! [`Now`] trait and passing an instance to [`with_default`]. //! //! [n]: fn.now.html //! [`Now`]: trait.Now.html //! [`Instant`]: std::time::Instant //! [`Instant::now`]: std::time::Instant::now //! [`with_default`]: fn.with_default.html mod now; pub use self::now::Now; use crate::timer; use std::cell::Cell; use std::fmt; use std::sync::Arc; use std::time::Instant; /// A handle to a source of time. /// /// `Clock` instances return [`Instant`] values corresponding to "now". The source /// of these values is configurable. The default source is [`Instant::now`]. /// /// [`Instant`]: std::time::Instant /// [`Instant::now`]: std::time::Instant::now #[derive(Default, Clone)] pub struct Clock { now: Option<Arc<dyn Now>>, } thread_local! { /// Thread-local tracking the current clock static CLOCK: Cell<Option<*const Clock>> = Cell::new(None) } /// Returns an `Instant` corresponding to "now". /// /// This function delegates to the source of time configured for the current /// execution context. By default, this is `Instant::now()`. /// /// Note that, because the source of time is configurable, it is possible to /// observe non-monotonic behavior when calling `now` from different /// executors. /// /// See [module](index.html) level documentation for more details. /// /// # Examples /// /// ``` /// # use tokio_timer::clock; /// let now = clock::now(); /// ``` pub fn now() -> Instant { CLOCK.with(|current| match current.get() { Some(ptr) => unsafe { (*ptr).now() }, None => Instant::now(), }) } impl Clock { /// Return a new `Clock` instance that uses the current execution context's /// source of time. pub fn new() -> Clock { CLOCK.with(|current| match current.get() { Some(ptr) => unsafe { (*ptr).clone() }, None => Clock::system(), }) } /// Return a new `Clock` instance that uses `now` as the source of time. pub fn new_with_now<T: Now>(now: T) -> Clock { Clock { now: Some(Arc::new(now)), } } /// Return a new `Clock` instance that uses [`Instant::now`] as the source /// of time. /// /// [`Instant::now`]: std::time::Instant::now pub fn system() -> Clock { Clock { now: None } } /// Returns an instant corresponding to "now" by using the instance's source /// of time. pub fn now(&self) -> Instant { match self.now { Some(ref now) => now.now(), None => Instant::now(), } } } #[allow(deprecated)] impl timer::Now for Clock { fn now(&mut self) -> Instant { Clock::now(self) } } impl fmt::Debug for Clock { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("Clock") .field("now", { if self.now.is_some() { &"Some(Arc<Now>)" } else { &"None" } }) .finish() } } /// Set the default clock for the duration of the closure. /// /// # Panics /// /// This function panics if there already is a default clock set. pub fn with_default<F, R>(clock: &Clock, f: F) -> R where F: FnOnce() -> R, { CLOCK.with(|cell| { assert!( cell.get().is_none(), "default clock already set for execution context" ); // Ensure that the clock is removed from the thread-local context // when leaving the scope. This handles cases that involve panicking. struct Reset<'a>(&'a Cell<Option<*const Clock>>); impl Drop for Reset<'_> { fn drop(&mut self) { self.0.set(None); } } let _reset = Reset(cell); cell.set(Some(clock as *const Clock)); f() }) }