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
//! Implementation of [`Timer`]. //! //! Timers are futures that fire at a predefined point in time. use std::fmt::Debug; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use std::time::{Duration, Instant}; use crate::reactor::Reactor; /// Fires at the chosen point in time. /// /// Timers are futures that output the [`Instant`] at which they fired. /// /// # Examples /// /// Sleep for 1 second: /// /// ``` /// use smol::Timer; /// use std::time::Duration; /// /// async fn sleep(dur: Duration) { /// Timer::after(dur).await; /// } /// /// # smol::run(async { /// sleep(Duration::from_secs(1)).await; /// # }); /// ``` /// /// Set a timeout on an I/O operation: /// /// ``` /// use futures::future::Either; /// use futures::io::{self, BufReader}; /// use futures::prelude::*; /// use smol::Timer; /// use std::time::Duration; /// /// async fn timeout<T>( /// dur: Duration, /// f: impl Future<Output = io::Result<T>>, /// ) -> io::Result<T> { /// futures::pin_mut!(f); /// match future::select(f, Timer::after(dur)).await { /// Either::Left((out, _)) => out, /// Either::Right(_) => Err(io::ErrorKind::TimedOut.into()), /// } /// } /// /// # smol::run(async { /// // Create a buffered stdin reader. /// let mut stdin = BufReader::new(smol::reader(std::io::stdin())); /// /// // Read a line within 5 seconds. /// let mut line = String::new(); /// timeout(Duration::from_secs(5), stdin.read_line(&mut line)).await?; /// # io::Result::Ok(()) }); #[derive(Debug)] pub struct Timer { /// This timer's ID. /// /// When this field is set to `None`, this timer is not registered in the reactor. id: Option<usize>, /// When this timer fires. when: Instant, } impl Timer { /// Fires after the specified duration of time. /// /// # Examples /// /// ``` /// use smol::Timer; /// use std::time::Duration; /// /// # smol::run(async { /// Timer::after(Duration::from_secs(1)).await; /// # }); /// ``` pub fn after(dur: Duration) -> Timer { Timer::at(Instant::now() + dur) } /// Fires at the specified instant in time. /// /// # Examples /// /// ``` /// use smol::Timer; /// use std::time::{Duration, Instant}; /// /// # smol::run(async { /// let now = Instant::now(); /// let when = now + Duration::from_secs(1); /// Timer::at(when).await; /// # }); /// ``` pub fn at(when: Instant) -> Timer { let id = None; Timer { id, when } } } impl Drop for Timer { fn drop(&mut self) { if let Some(id) = self.id.take() { // Deregister the timer from the reactor. Reactor::get().remove_timer(self.when, id); } } } impl Future for Timer { type Output = Instant; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { // Check if the timer has already fired. if Instant::now() >= self.when { if let Some(id) = self.id.take() { // Deregister the timer from the reactor. Reactor::get().remove_timer(self.when, id); } Poll::Ready(self.when) } else { if self.id.is_none() { // Register the timer in the reactor. self.id = Some(Reactor::get().insert_timer(self.when, cx.waker())); } Poll::Pending } } }