|
| 1 | +use crate::enter::Enter; |
| 2 | +use std::time::Duration; |
| 3 | +use futures_util::task::WakerRef; |
| 4 | + |
| 5 | +/// Determines how long `park` will block |
| 6 | +#[derive(Clone, Copy, Debug)] |
| 7 | +pub enum ParkDuration { |
| 8 | + /// Don't block at all |
| 9 | + Poll, |
| 10 | + /// Block until explicit (possibly spurious) unpark |
| 11 | + Block, |
| 12 | + /// Block at most for given Duration; might get rounded up to some |
| 13 | + /// minimum "sleepable" value by `Park` implementation if timeout is |
| 14 | + /// too small (including zero). |
| 15 | + Timeout(Duration), |
| 16 | +} |
| 17 | + |
| 18 | +impl ParkDuration { |
| 19 | + /// Create a new duration specification which doesn't block longer |
| 20 | + /// than the passed limit. |
| 21 | + pub fn limit(self, max_duration: Duration) -> Self { |
| 22 | + match self { |
| 23 | + ParkDuration::Poll => ParkDuration::Poll, |
| 24 | + ParkDuration::Block => ParkDuration::Timeout(max_duration), |
| 25 | + ParkDuration::Timeout(d) => ParkDuration::Timeout(std::cmp::min(d, max_duration)), |
| 26 | + } |
| 27 | + } |
| 28 | +} |
| 29 | + |
| 30 | +/// Convert zero duration to `Poll`; other durations are wrapped in |
| 31 | +/// `Timeout(..)`. |
| 32 | +impl From<Duration> for ParkDuration { |
| 33 | + fn from(duration: Duration) -> Self { |
| 34 | + if duration == Duration::from_secs(0) { |
| 35 | + ParkDuration::Poll |
| 36 | + } else { |
| 37 | + ParkDuration::Timeout(duration) |
| 38 | + } |
| 39 | + } |
| 40 | +} |
| 41 | + |
| 42 | +/// Convert `None` to `Block`, zero durations to `Poll` and other |
| 43 | +/// durations are wrapped in `Timeout(..)`. |
| 44 | +impl From<Option<Duration>> for ParkDuration { |
| 45 | + fn from(duration: Option<Duration>) -> Self { |
| 46 | + match duration { |
| 47 | + Some(duration) => ParkDuration::from(duration), |
| 48 | + None => ParkDuration::Block, |
| 49 | + } |
| 50 | + } |
| 51 | +} |
| 52 | + |
| 53 | +/// Block the current thread. |
| 54 | +pub trait Park { |
| 55 | + /// Error returned by `park` |
| 56 | + type Error; |
| 57 | + |
| 58 | + /// Get a new `Waker` associated with this `Park` instance. |
| 59 | + fn waker(&self) -> WakerRef<'_>; |
| 60 | + |
| 61 | + /// Block the current thread unless or until the token is available; |
| 62 | + /// `duration` determines for how long. |
| 63 | + /// |
| 64 | + /// A call to `park` does not guarantee that the thread will remain |
| 65 | + /// blocked forever, and callers should be prepared for this |
| 66 | + /// possibility. This function may wakeup spuriously for any reason. |
| 67 | + /// |
| 68 | + /// # Panics |
| 69 | + /// |
| 70 | + /// This function **should** not panic, but ultimately, panics are |
| 71 | + /// left as an implementation detail. Refer to the documentation for |
| 72 | + /// the specific `Park` implementation |
| 73 | + fn park(&mut self, enter: &mut Enter, duration: ParkDuration) -> Result<(), Self::Error>; |
| 74 | +} |
| 75 | + |
| 76 | +impl<P: Park> Park for &'_ mut P { |
| 77 | + type Error = P::Error; |
| 78 | + |
| 79 | + fn waker(&self) -> WakerRef<'_> { |
| 80 | + (**self).waker() |
| 81 | + } |
| 82 | + |
| 83 | + fn park(&mut self, enter: &mut Enter, duration: ParkDuration) -> Result<(), Self::Error> { |
| 84 | + (**self).park(enter, duration) |
| 85 | + } |
| 86 | +} |
0 commit comments