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
use
{
	std          :: { time::Duration, future::Future, task::{ Poll, Context }, pin::Pin } ,
	futures_core :: { future::BoxFuture                                                 } ,

	pin_project::pin_project,
};

/// Represents the fact that an executor has timer functionality.
///
//  Implementation:
//  - for tokio: use tokio when tokio_time feature is enabled, futures-timer otherwise.
//  - for async-global-executor: use futures-timer.
//  - for glommio: has own timer that can't be turned off. But we don't use it because
//    it's not Send.
//  - for bindgen: use futures-timer
//  - for async-std: has a timer that cannot be turned off. Isn't Send on Wasm.
//
//  The trait needs to be available inconditionally, as a library must be able
//  to depend on it without specifying a backend.
//
#[ blanket::blanket( derive( Ref, Mut, Rc, Arc, Box ) ) ]
//
pub trait Timer
{
	/// Future that resolves after a given duration.
	//
	#[ must_use = "sleep() returns a future, which does nothing unless awaited" ]
	//
	fn sleep( &self, dur: Duration ) -> BoxFuture<'static, ()>;
}




// The following code was taken from tor-rtcompat https://gitlab.torproject.org/tpo/core/arti/-/blob/main/tor-rtcompat/src/timer.rs
// This is licenced: "MIT OR Apache-2.0".
//



/// An extension trait on [`Timer`] for timeouts and clock delays.
//
pub trait TimerExt: Timer
{
	/// Wrap a [`Future`] with a timeout.
	///
	/// The output of the new future will be the returned value of
	/// `future` if it completes within `duration`.  Otherwise, it
	/// will be `Err(TimeoutError)`.
	///
	/// # Limitations
	///
	/// This uses [`Timer::sleep`] for its timer, and is
	/// subject to the same limitations.
	//
	#[ must_use = "timeout() returns a future, which does nothing unless awaited." ]
	//
	fn timeout<F: Future>( &self, duration: Duration, future: F ) -> Timeout<F>
	{
		let sleep_future = self.sleep( duration );

		Timeout { future, sleep_future }
	}
}


impl<T: Timer> TimerExt for T {}


/// An error value given when a function times out.
///
/// This value is generated when the timeout from
/// [`TimerExt::timeout`] expires before the provided future
/// is ready.
//
#[ derive( Copy, Clone, Debug, Eq, PartialEq ) ]
//
#[allow(clippy::exhaustive_structs)]
//
pub struct TimeoutError;


impl std::error::Error for TimeoutError {}


impl std::fmt::Display for TimeoutError
{
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
	{
		write!( f, "Timeout expired" )
	}
}


impl From<TimeoutError> for std::io::Error
{
	fn from( err: TimeoutError ) -> std::io::Error
	{
		std::io::Error::new( std::io::ErrorKind::TimedOut, err )
	}
}


/// A timeout returned by [`TimerExt::timeout`].
//
#[pin_project]
//
pub struct Timeout<T>
{
	/// The future we want to execute.
	//
	#[pin] future: T,

	/// The future implementing the timeout.
	//
	sleep_future: BoxFuture<'static, ()>,
}



impl<T> Future for Timeout<T>

	where T: Future,

{
	type Output = Result< T::Output, TimeoutError >;


	fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>
	{
		let this = self.project();


		if let Poll::Ready(x) = this.future.poll(cx)
		{
			return Poll::Ready(Ok(x));
		}


		match this.sleep_future.as_mut().poll(cx)
		{
			Poll::Pending   => Poll::Pending                    ,
			Poll::Ready(()) => Poll::Ready( Err(TimeoutError) ) ,
		}
	}
}


impl<T> std::fmt::Debug for Timeout<T>
{
	fn fmt( &self, f: &mut std::fmt::Formatter<'_> ) -> std::fmt::Result
	{
		write!( f, "Timeout future" )
	}
}