libp2p_mdns/behaviour/
timer.rs

1// Copyright 2018 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21use std::{
22    marker::Unpin,
23    time::{Duration, Instant},
24};
25
26/// Simple wrapper for the different type of timers
27#[derive(Debug)]
28#[cfg(any(feature = "async-io", feature = "tokio"))]
29pub struct Timer<T> {
30    inner: T,
31}
32
33/// Builder interface to homogenize the different implementations
34#[allow(unreachable_pub)] // Users should not depend on this.
35pub trait Builder: Send + Unpin + 'static {
36    /// Creates a timer that emits an event once at the given time instant.
37    fn at(instant: Instant) -> Self;
38
39    /// Creates a timer that emits events periodically.
40    fn interval(duration: Duration) -> Self;
41
42    /// Creates a timer that emits events periodically, starting at start.
43    fn interval_at(start: Instant, duration: Duration) -> Self;
44}
45
46#[cfg(feature = "async-io")]
47pub(crate) mod asio {
48    use super::*;
49    use async_io::Timer as AsioTimer;
50    use futures::Stream;
51    use std::{
52        pin::Pin,
53        task::{Context, Poll},
54    };
55
56    /// Async Timer
57    pub(crate) type AsyncTimer = Timer<AsioTimer>;
58    impl Builder for AsyncTimer {
59        fn at(instant: Instant) -> Self {
60            Self {
61                inner: AsioTimer::at(instant),
62            }
63        }
64
65        fn interval(duration: Duration) -> Self {
66            Self {
67                inner: AsioTimer::interval(duration),
68            }
69        }
70
71        fn interval_at(start: Instant, duration: Duration) -> Self {
72            Self {
73                inner: AsioTimer::interval_at(start, duration),
74            }
75        }
76    }
77
78    impl Stream for AsyncTimer {
79        type Item = Instant;
80
81        fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
82            Pin::new(&mut self.inner).poll_next(cx)
83        }
84    }
85}
86
87#[cfg(feature = "tokio")]
88pub(crate) mod tokio {
89    use super::*;
90    use ::tokio::time::{self, Instant as TokioInstant, Interval, MissedTickBehavior};
91    use futures::Stream;
92    use std::{
93        pin::Pin,
94        task::{Context, Poll},
95    };
96
97    /// Tokio wrapper
98    pub(crate) type TokioTimer = Timer<Interval>;
99    impl Builder for TokioTimer {
100        fn at(instant: Instant) -> Self {
101            // Taken from: https://docs.rs/async-io/1.7.0/src/async_io/lib.rs.html#91
102            let mut inner = time::interval_at(
103                TokioInstant::from_std(instant),
104                Duration::new(std::u64::MAX, 1_000_000_000 - 1),
105            );
106            inner.set_missed_tick_behavior(MissedTickBehavior::Skip);
107            Self { inner }
108        }
109
110        fn interval(duration: Duration) -> Self {
111            let mut inner = time::interval_at(TokioInstant::now() + duration, duration);
112            inner.set_missed_tick_behavior(MissedTickBehavior::Skip);
113            Self { inner }
114        }
115
116        fn interval_at(start: Instant, duration: Duration) -> Self {
117            let mut inner = time::interval_at(TokioInstant::from_std(start), duration);
118            inner.set_missed_tick_behavior(MissedTickBehavior::Skip);
119            Self { inner }
120        }
121    }
122
123    impl Stream for TokioTimer {
124        type Item = TokioInstant;
125
126        fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
127            self.inner.poll_tick(cx).map(Some)
128        }
129
130        fn size_hint(&self) -> (usize, Option<usize>) {
131            (std::usize::MAX, None)
132        }
133    }
134}