1#![allow(
7 clippy::cast_possible_truncation,
8 clippy::cast_sign_loss,
9 clippy::cast_possible_wrap
10)]
11use std::{cmp, future::Future, future::poll_fn, pin::Pin, task, task::Poll};
12
13mod callbacks;
14mod types;
15mod wheel;
16
17pub use self::callbacks::CallbackTimer;
18pub use self::types::{Millis, Seconds};
19pub use self::wheel::{TimerHandle, now, system_time};
20
21#[inline]
29pub fn sleep<T: Into<Millis>>(dur: T) -> Sleep {
30 Sleep::new(dur.into())
31}
32
33#[inline]
37pub fn deadline<T: Into<Millis>>(dur: T) -> Deadline {
38 Deadline::new(dur.into())
39}
40
41#[inline]
48pub fn interval<T: Into<Millis>>(period: T) -> Interval {
49 Interval::new(period.into())
50}
51
52#[inline]
60pub fn timeout<T, U>(dur: U, future: T) -> Timeout<T>
61where
62 T: Future,
63 U: Into<Millis>,
64{
65 Timeout::new_with_delay(future, Sleep::new(dur.into()))
66}
67
68#[inline]
74pub fn timeout_checked<T, U>(dur: U, future: T) -> TimeoutChecked<T>
75where
76 T: Future,
77 U: Into<Millis>,
78{
79 TimeoutChecked::new_with_delay(future, dur.into())
80}
81
82#[derive(Debug)]
106#[must_use = "futures do nothing unless you `.await` or poll them"]
107pub struct Sleep {
108 hnd: TimerHandle,
110}
111
112impl Sleep {
113 #[inline]
117 pub fn new(duration: Millis) -> Sleep {
118 Sleep {
119 hnd: TimerHandle::new(u64::from(cmp::max(duration.0, 1))),
120 }
121 }
122
123 #[inline]
125 pub fn is_elapsed(&self) -> bool {
126 self.hnd.is_elapsed()
127 }
128
129 #[inline]
131 pub fn elapse(&self) {
132 self.hnd.elapse();
133 }
134
135 pub fn reset<T: Into<Millis>>(&self, millis: T) {
143 self.hnd.reset(u64::from(cmp::max(millis.into().0, 1)));
144 }
145
146 #[inline]
147 pub async fn wait(&self) {
151 poll_fn(|cx| self.hnd.poll_elapsed(cx)).await;
152 }
153
154 #[inline]
155 pub fn poll_elapsed(&self, cx: &mut task::Context<'_>) -> Poll<()> {
160 self.hnd.poll_elapsed(cx)
161 }
162}
163
164impl Future for Sleep {
165 type Output = ();
166
167 fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
168 self.hnd.poll_elapsed(cx)
169 }
170}
171
172#[derive(Debug)]
188#[must_use = "futures do nothing unless you `.await` or poll them"]
189pub struct Deadline {
190 hnd: Option<TimerHandle>,
191}
192
193impl Deadline {
194 #[inline]
198 pub fn new(duration: Millis) -> Deadline {
199 if duration.0 != 0 {
200 Deadline {
201 hnd: Some(TimerHandle::new(u64::from(duration.0))),
202 }
203 } else {
204 Deadline { hnd: None }
205 }
206 }
207
208 #[inline]
209 pub async fn wait(&self) {
214 poll_fn(|cx| self.poll_elapsed(cx)).await;
215 }
216
217 pub fn reset<T: Into<Millis>>(&mut self, millis: T) {
225 let millis = millis.into();
226 if millis.0 != 0 {
227 if let Some(ref mut hnd) = self.hnd {
228 hnd.reset(u64::from(millis.0));
229 } else {
230 self.hnd = Some(TimerHandle::new(u64::from(millis.0)));
231 }
232 } else {
233 let _ = self.hnd.take();
234 }
235 }
236
237 #[inline]
243 pub fn is_elapsed(&self) -> bool {
244 self.hnd.as_ref().is_some_and(TimerHandle::is_elapsed)
245 }
246
247 #[inline]
248 pub fn poll_elapsed(&self, cx: &mut task::Context<'_>) -> Poll<()> {
254 self.hnd
255 .as_ref()
256 .map_or(Poll::Pending, |t| t.poll_elapsed(cx))
257 }
258}
259
260impl Future for Deadline {
261 type Output = ();
262
263 fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
264 self.poll_elapsed(cx)
265 }
266}
267
268pin_project_lite::pin_project! {
269 #[must_use = "futures do nothing unless you `.await` or poll them"]
271 #[derive(Debug)]
272 pub struct Timeout<T> {
273 #[pin]
274 value: T,
275 delay: Sleep,
276 }
277}
278
279impl<T> Timeout<T> {
280 pub(crate) fn new_with_delay(value: T, delay: Sleep) -> Timeout<T> {
281 Timeout { value, delay }
282 }
283}
284
285impl<T> Future for Timeout<T>
286where
287 T: Future,
288{
289 type Output = Result<T::Output, ()>;
290
291 fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
292 let this = self.project();
293
294 if let Poll::Ready(v) = this.value.poll(cx) {
296 return Poll::Ready(Ok(v));
297 }
298
299 match this.delay.poll_elapsed(cx) {
301 Poll::Ready(()) => Poll::Ready(Err(())),
302 Poll::Pending => Poll::Pending,
303 }
304 }
305}
306
307pin_project_lite::pin_project! {
308 #[must_use = "futures do nothing unless you `.await` or poll them"]
310 pub struct TimeoutChecked<T> {
311 #[pin]
312 state: TimeoutCheckedState<T>,
313 }
314}
315
316pin_project_lite::pin_project! {
317 #[project = TimeoutCheckedStateProject]
318 enum TimeoutCheckedState<T> {
319 Timeout{ #[pin] fut: Timeout<T> },
320 NoTimeout{ #[pin] fut: T },
321 }
322}
323
324impl<T> TimeoutChecked<T> {
325 pub(crate) fn new_with_delay(value: T, delay: Millis) -> TimeoutChecked<T> {
326 if delay.is_zero() {
327 TimeoutChecked {
328 state: TimeoutCheckedState::NoTimeout { fut: value },
329 }
330 } else {
331 TimeoutChecked {
332 state: TimeoutCheckedState::Timeout {
333 fut: Timeout::new_with_delay(value, sleep(delay)),
334 },
335 }
336 }
337 }
338}
339
340impl<T> Future for TimeoutChecked<T>
341where
342 T: Future,
343{
344 type Output = Result<T::Output, ()>;
345
346 fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
347 match self.project().state.as_mut().project() {
348 TimeoutCheckedStateProject::Timeout { fut } => fut.poll(cx),
349 TimeoutCheckedStateProject::NoTimeout { fut } => fut.poll(cx).map(Result::Ok),
350 }
351 }
352}
353
354#[must_use = "futures do nothing unless you `.await` or poll them"]
359#[derive(Debug)]
360pub struct Interval {
361 hnd: TimerHandle,
362 period: u32,
363}
364
365impl Interval {
366 #[inline]
371 pub fn new(period: Millis) -> Interval {
372 Interval {
373 hnd: TimerHandle::new(0),
374 period: cmp::max(period.0, 1),
375 }
376 }
377
378 #[inline]
379 pub async fn tick(&self) {
381 poll_fn(|cx| self.poll_tick(cx)).await;
382 }
383
384 #[inline]
385 pub fn poll_tick(&self, cx: &mut task::Context<'_>) -> Poll<()> {
387 if self.hnd.poll_elapsed(cx).is_ready() {
388 self.hnd.reset(u64::from(self.period));
389 Poll::Ready(())
390 } else {
391 Poll::Pending
392 }
393 }
394}
395
396impl crate::Stream for Interval {
397 type Item = ();
398
399 #[inline]
400 fn poll_next(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
401 self.poll_tick(cx).map(|()| Some(()))
402 }
403}
404
405#[cfg(test)]
406mod tests {
407 use futures_util::StreamExt;
408 use std::{future::poll_fn, rc::Rc, time};
409
410 use super::*;
411 use crate::future::lazy;
412
413 #[ntex::test]
419 async fn now_is_current() {
420 sleep(Millis(25)).await;
421
422 let now = now();
423 let cur = time::Instant::now();
424 assert!(cur >= now);
425 assert!(cur - now < time::Duration::from_millis(50));
426 }
427
428 #[ntex::test]
434 async fn now_updates_after_sleep() {
435 sleep(Millis(50)).await;
436
437 let first_time = now();
438
439 sleep(Millis(25)).await;
440
441 let second_time = now();
442 assert!(second_time - first_time >= time::Duration::from_millis(25));
443 }
444
445 #[ntex::test]
450 async fn system_time_service_time_does_not_immediately_change() {
451 sleep(Seconds(1)).await;
452
453 assert_eq!(system_time(), system_time());
454 }
455
456 #[ntex::test]
462 async fn system_time_service_time_updates_after_resolution_interval() {
463 sleep(Millis(100)).await;
464
465 let wait_time = 600;
466
467 let first_time = system_time()
468 .duration_since(time::SystemTime::UNIX_EPOCH)
469 .unwrap();
470
471 sleep(Millis(wait_time)).await;
472
473 let second_time = system_time()
474 .duration_since(time::SystemTime::UNIX_EPOCH)
475 .unwrap();
476
477 assert!(
478 second_time.checked_sub(first_time).unwrap()
479 >= time::Duration::from_millis(u64::from(wait_time))
480 );
481 }
482
483 #[ntex::test]
489 async fn test_sleep_0() {
490 sleep(Seconds(1)).await;
491
492 let first_time = time::Instant::now();
493 sleep(Millis(0)).await;
494 let second_time = time::Instant::now();
495 assert!(second_time - first_time >= time::Duration::from_millis(1));
496
497 let first_time = time::Instant::now();
498 sleep(Millis(1)).await;
499 let second_time = time::Instant::now();
500 assert!(second_time - first_time >= time::Duration::from_millis(1));
501
502 let first_time = time::Instant::now();
503 let fut = sleep(Millis(10000));
504 assert!(!fut.is_elapsed());
505 fut.reset(Millis::ZERO);
507 assert!(!fut.is_elapsed());
508 fut.await;
509 let second_time = time::Instant::now();
510 assert!(second_time - first_time >= time::Duration::from_millis(1));
511
512 let fut = sleep(Millis::ZERO);
513 assert!(!fut.is_elapsed());
514 fut.await;
515
516 let first_time = time::Instant::now();
520 let fut = Sleep {
521 hnd: TimerHandle::new(0),
522 };
523 assert!(fut.is_elapsed());
524 fut.await;
525 let second_time = time::Instant::now();
526 assert!(second_time - first_time < time::Duration::from_millis(50));
527
528 let first_time = time::Instant::now();
529 let fut = Rc::new(sleep(Millis(10_0000)));
530 let s = fut.clone();
531 ntex::rt::spawn(async move {
532 s.elapse();
533 });
534 poll_fn(|cx| fut.poll_elapsed(cx)).await;
535 assert!(fut.is_elapsed());
536 let second_time = time::Instant::now();
537 assert!(second_time - first_time < time::Duration::from_millis(50));
538 }
539
540 #[ntex::test]
551 async fn test_deadline_is_elapsed_matches_polling() {
552 let dl = deadline(Millis::ZERO);
553 assert!(!dl.is_elapsed());
554 assert!(lazy(|cx| dl.poll_elapsed(cx)).await.is_pending());
555 assert!(timeout(Millis(20), dl.wait()).await.is_err());
556 assert!(!dl.is_elapsed());
557
558 let dl = deadline(Millis(50));
559 assert!(!dl.is_elapsed());
560 assert!(lazy(|cx| dl.poll_elapsed(cx)).await.is_pending());
561
562 let mut dl = deadline(Millis(1));
563 dl.wait().await;
564 assert!(dl.is_elapsed());
565 assert!(lazy(|cx| dl.poll_elapsed(cx)).await.is_ready());
566
567 dl.reset(Millis(50));
568 assert!(!dl.is_elapsed());
569 assert!(lazy(|cx| dl.poll_elapsed(cx)).await.is_pending());
570
571 dl.reset(Millis::ZERO);
572 sleep(Millis(20)).await;
573 assert!(!dl.is_elapsed());
574 assert!(lazy(|cx| dl.poll_elapsed(cx)).await.is_pending());
575 }
576
577 #[ntex::test]
583 async fn test_deadline() {
584 sleep(Seconds(1)).await;
585
586 let first_time = now();
587 let dl = deadline(Millis(1));
588 dl.await;
589 let second_time = now();
590 assert!(second_time - first_time >= time::Duration::from_millis(1));
591 assert!(timeout(Millis(100), deadline(Millis(0))).await.is_err());
592
593 let mut dl = deadline(Millis(1));
594 dl.reset(Millis::ZERO);
595 assert!(lazy(|cx| dl.poll_elapsed(cx)).await.is_pending());
596
597 let mut dl = deadline(Millis(1));
598 dl.reset(Millis(100));
599 let first_time = now();
600 dl.await;
601 let second_time = now();
602 assert!(second_time - first_time >= time::Duration::from_millis(100));
603
604 let mut dl = deadline(Millis(0));
605 dl.reset(Millis(1));
606 assert!(lazy(|cx| dl.poll_elapsed(cx)).await.is_pending());
607
608 assert!(format!("{dl:?}").contains("Deadline"));
609 }
610
611 #[ntex::test]
616 async fn test_interval_zero_period() {
617 let int = interval(Millis::ZERO);
618 int.tick().await;
619
620 assert!(lazy(|cx| int.poll_tick(cx)).await.is_pending());
622 int.tick().await;
623 }
624
625 #[ntex::test]
631 async fn test_interval() {
632 let mut int = interval(Millis(250));
633
634 let time = time::Instant::now();
636 int.tick().await;
637 assert!(time.elapsed() < time::Duration::from_millis(50));
638
639 let time = time::Instant::now();
640 int.tick().await;
641 let elapsed = time.elapsed();
642 assert!(
643 elapsed > time::Duration::from_millis(200)
644 && elapsed < time::Duration::from_millis(450),
645 "elapsed: {elapsed:?}"
646 );
647
648 let time = time::Instant::now();
649 int.next().await;
650 let elapsed = time.elapsed();
651 assert!(
652 elapsed > time::Duration::from_millis(200)
653 && elapsed < time::Duration::from_millis(450),
654 "elapsed: {elapsed:?}"
655 );
656 }
657
658 #[ntex::test]
663 async fn test_interval_one_sec() {
664 let int = interval(Millis::ONE_SEC);
665 int.tick().await;
666
667 for _i in 0..3 {
668 let time = time::Instant::now();
669 int.tick().await;
670 let elapsed = time.elapsed();
671 assert!(
672 elapsed > time::Duration::from_secs(1)
673 && elapsed < time::Duration::from_millis(1500),
674 "elapsed: {elapsed:?}"
675 );
676 }
677 }
678
679 #[ntex::test]
685 async fn test_timeout_checked() {
686 let result = timeout_checked(Millis(200), sleep(Millis(100))).await;
687 assert!(result.is_ok());
688
689 let result = timeout_checked(Millis(5), std::future::pending::<()>()).await;
692 assert!(result.is_err());
693
694 let result = timeout_checked(Millis(0), sleep(Millis(100))).await;
695 assert!(result.is_ok());
696 }
697
698 #[ntex::test]
704 async fn sleep_and_deadline_wait() {
705 let start = now();
706 sleep(Millis(5)).wait().await;
707 deadline(Millis(5)).wait().await;
708 assert!(now() >= start);
709
710 let hnd = Deadline::new(Millis::ZERO);
711 assert!(
712 crate::time::timeout(Millis(20), hnd.wait()).await.is_err(),
713 "zero deadline never completes"
714 );
715 }
716
717 #[ntex::test]
725 async fn single_waiter_wakes_latest_task_only() {
726 use crate::task::hooks::counted_waker;
727
728 let poll_pair = |poll: &dyn Fn(&mut task::Context<'_>) -> Poll<()>, elapse: &dyn Fn()| {
729 let (first, first_waker) = counted_waker();
730 let (second, second_waker) = counted_waker();
731 let mut first_cx = task::Context::from_waker(&first_waker);
732 let mut second_cx = task::Context::from_waker(&second_waker);
733
734 assert_eq!(poll(&mut first_cx), Poll::Pending);
735 assert_eq!(poll(&mut second_cx), Poll::Pending);
736 elapse();
737 assert_eq!((first.get(), second.get()), (0, 1));
738 assert_eq!(poll(&mut first_cx), Poll::Ready(()));
739 };
740
741 let slp = Sleep::new(Millis(10_000));
742 poll_pair(&|cx| slp.poll_elapsed(cx), &|| slp.elapse());
743
744 let dl = Deadline::new(Millis(10_000));
745 let hnd = dl.hnd.as_ref().unwrap();
746 poll_pair(&|cx| dl.poll_elapsed(cx), &|| hnd.elapse());
747 }
748}