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::time::{Duration, Instant};
22
23/// Simple wrapper for the different type of timers
24#[derive(Debug)]
25#[cfg(any(feature = "async-io", feature = "tokio"))]
26pub struct Timer<T> {
27    inner: T,
28}
29
30/// Builder interface to homogenize the different implementations
31#[allow(unreachable_pub)] // Users should not depend on this.
32pub trait Builder: Send + Unpin + 'static {
33    /// Creates a timer that emits an event once at the given time instant.
34    fn at(instant: Instant) -> Self;
35
36    /// Creates a timer that emits events periodically.
37    fn interval(duration: Duration) -> Self;
38
39    /// Creates a timer that emits events periodically, starting at start.
40    fn interval_at(start: Instant, duration: Duration) -> Self;
41}
42
43#[cfg(feature = "async-io")]
44pub(crate) mod asio {
45    use std::{
46        pin::Pin,
47        task::{Context, Poll},
48    };
49
50    use async_io::Timer as AsioTimer;
51    use futures::Stream;
52
53    use super::*;
54
55    /// Async Timer
56    pub(crate) type AsyncTimer = Timer<AsioTimer>;
57    impl Builder for AsyncTimer {
58        fn at(instant: Instant) -> Self {
59            Self {
60                inner: AsioTimer::at(instant),
61            }
62        }
63
64        fn interval(duration: Duration) -> Self {
65            Self {
66                inner: AsioTimer::interval(duration),
67            }
68        }
69
70        fn interval_at(start: Instant, duration: Duration) -> Self {
71            Self {
72                inner: AsioTimer::interval_at(start, duration),
73            }
74        }
75    }
76
77    impl Stream for AsyncTimer {
78        type Item = Instant;
79
80        fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
81            Pin::new(&mut self.inner).poll_next(cx)
82        }
83    }
84}
85
86#[cfg(feature = "tokio")]
87pub(crate) mod tokio {
88    use std::{
89        pin::Pin,
90        task::{Context, Poll},
91    };
92
93    use ::tokio::time::{self, Instant as TokioInstant, Interval, MissedTickBehavior};
94    use futures::Stream;
95
96    use super::*;
97
98    /// Tokio wrapper
99    pub(crate) type TokioTimer = Timer<Interval>;
100    impl Builder for TokioTimer {
101        fn at(instant: Instant) -> Self {
102            // Taken from: https://docs.rs/async-io/1.7.0/src/async_io/lib.rs.html#91
103            let mut inner = time::interval_at(
104                TokioInstant::from_std(instant),
105                Duration::new(u64::MAX, 1_000_000_000 - 1),
106            );
107            inner.set_missed_tick_behavior(MissedTickBehavior::Skip);
108            Self { inner }
109        }
110
111        fn interval(duration: Duration) -> Self {
112            let mut inner = time::interval_at(TokioInstant::now() + duration, duration);
113            inner.set_missed_tick_behavior(MissedTickBehavior::Skip);
114            Self { inner }
115        }
116
117        fn interval_at(start: Instant, duration: Duration) -> Self {
118            let mut inner = time::interval_at(TokioInstant::from_std(start), duration);
119            inner.set_missed_tick_behavior(MissedTickBehavior::Skip);
120            Self { inner }
121        }
122    }
123
124    impl Stream for TokioTimer {
125        type Item = TokioInstant;
126
127        fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
128            self.inner.poll_tick(cx).map(Some)
129        }
130
131        fn size_hint(&self) -> (usize, Option<usize>) {
132            (usize::MAX, None)
133        }
134    }
135}