1use std::convert::Infallible;
2use std::task::{Context, Poll};
3use std::time::{self, Duration, Instant};
4
5use scrappy_rt::time::delay_for;
6use scrappy_service::{Service, ServiceFactory};
7use futures::future::{ok, ready, FutureExt, Ready};
8
9use super::cell::Cell;
10
11#[derive(Clone, Debug)]
12pub struct LowResTime(Cell<Inner>);
13
14#[derive(Debug)]
15struct Inner {
16 resolution: Duration,
17 current: Option<Instant>,
18}
19
20impl Inner {
21 fn new(resolution: Duration) -> Self {
22 Inner {
23 resolution,
24 current: None,
25 }
26 }
27}
28
29impl LowResTime {
30 pub fn with(resolution: Duration) -> LowResTime {
31 LowResTime(Cell::new(Inner::new(resolution)))
32 }
33
34 pub fn timer(&self) -> LowResTimeService {
35 LowResTimeService(self.0.clone())
36 }
37}
38
39impl Default for LowResTime {
40 fn default() -> Self {
41 LowResTime(Cell::new(Inner::new(Duration::from_secs(1))))
42 }
43}
44
45impl ServiceFactory for LowResTime {
46 type Request = ();
47 type Response = Instant;
48 type Error = Infallible;
49 type InitError = Infallible;
50 type Config = ();
51 type Service = LowResTimeService;
52 type Future = Ready<Result<Self::Service, Self::InitError>>;
53
54 fn new_service(&self, _: ()) -> Self::Future {
55 ok(self.timer())
56 }
57}
58
59#[derive(Clone, Debug)]
60pub struct LowResTimeService(Cell<Inner>);
61
62impl LowResTimeService {
63 pub fn with(resolution: Duration) -> LowResTimeService {
64 LowResTimeService(Cell::new(Inner::new(resolution)))
65 }
66
67 pub fn now(&self) -> Instant {
70 let cur = self.0.get_ref().current;
71 if let Some(cur) = cur {
72 cur
73 } else {
74 let now = Instant::now();
75 let mut inner = self.0.clone();
76 let interval = {
77 let mut b = inner.get_mut();
78 b.current = Some(now);
79 b.resolution
80 };
81
82 scrappy_rt::spawn(delay_for(interval).then(move |_| {
83 inner.get_mut().current.take();
84 ready(())
85 }));
86 now
87 }
88 }
89}
90
91impl Service for LowResTimeService {
92 type Request = ();
93 type Response = Instant;
94 type Error = Infallible;
95 type Future = Ready<Result<Self::Response, Self::Error>>;
96
97 fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
98 Poll::Ready(Ok(()))
99 }
100
101 fn call(&mut self, _: ()) -> Self::Future {
102 ok(self.now())
103 }
104}
105
106#[derive(Clone, Debug)]
107pub struct SystemTime(Cell<SystemTimeInner>);
108
109#[derive(Debug)]
110struct SystemTimeInner {
111 resolution: Duration,
112 current: Option<time::SystemTime>,
113}
114
115impl SystemTimeInner {
116 fn new(resolution: Duration) -> Self {
117 SystemTimeInner {
118 resolution,
119 current: None,
120 }
121 }
122}
123
124#[derive(Clone, Debug)]
125pub struct SystemTimeService(Cell<SystemTimeInner>);
126
127impl SystemTimeService {
128 pub fn with(resolution: Duration) -> SystemTimeService {
129 SystemTimeService(Cell::new(SystemTimeInner::new(resolution)))
130 }
131
132 pub fn now(&self) -> time::SystemTime {
135 let cur = self.0.get_ref().current;
136 if let Some(cur) = cur {
137 cur
138 } else {
139 let now = time::SystemTime::now();
140 let mut inner = self.0.clone();
141 let interval = {
142 let mut b = inner.get_mut();
143 b.current = Some(now);
144 b.resolution
145 };
146
147 scrappy_rt::spawn(delay_for(interval).then(move |_| {
148 inner.get_mut().current.take();
149 ready(())
150 }));
151 now
152 }
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159 use std::time::{Duration, SystemTime};
160
161 #[scrappy_rt::test]
165 async fn system_time_service_time_does_not_immediately_change() {
166 let resolution = Duration::from_millis(50);
167
168 let time_service = SystemTimeService::with(resolution);
169 assert_eq!(time_service.now(), time_service.now());
170 }
171
172 #[scrappy_rt::test]
176 async fn lowres_time_service_time_does_not_immediately_change() {
177 let resolution = Duration::from_millis(50);
178 let time_service = LowResTimeService::with(resolution);
179 assert_eq!(time_service.now(), time_service.now());
180 }
181
182 #[scrappy_rt::test]
187 async fn system_time_service_time_updates_after_resolution_interval() {
188 let resolution = Duration::from_millis(100);
189 let wait_time = Duration::from_millis(300);
190
191 let time_service = SystemTimeService::with(resolution);
192
193 let first_time = time_service
194 .now()
195 .duration_since(SystemTime::UNIX_EPOCH)
196 .unwrap();
197
198 delay_for(wait_time).await;
199
200 let second_time = time_service
201 .now()
202 .duration_since(SystemTime::UNIX_EPOCH)
203 .unwrap();
204
205 assert!(second_time - first_time >= wait_time);
206 }
207
208 #[scrappy_rt::test]
213 async fn lowres_time_service_time_updates_after_resolution_interval() {
214 let resolution = Duration::from_millis(100);
215 let wait_time = Duration::from_millis(300);
216 let time_service = LowResTimeService::with(resolution);
217
218 let first_time = time_service.now();
219
220 delay_for(wait_time).await;
221
222 let second_time = time_service.now();
223 assert!(second_time - first_time >= wait_time);
224 }
225}