async_time_mock_core/
timer.rs

1use crate::time_handler_guard::TimeHandlerFinished;
2use crate::TimeHandlerGuard;
3use event_listener::{Event, EventListener};
4use pin_project_lite::pin_project;
5use std::future::Future;
6use std::pin::Pin;
7use std::task::{ready, Context, Poll};
8
9pub(crate) struct Timer {
10	trigger: Event,
11	handler_finished_waiter: TimeHandlerFinished,
12}
13
14impl Timer {
15	pub(crate) fn new() -> (Self, TimerListener) {
16		let (handler_guard, handler_finished_waiter) = TimeHandlerGuard::new();
17		let trigger = Event::new();
18		let listener = trigger.listen();
19		(
20			Self {
21				trigger,
22				handler_finished_waiter,
23			},
24			TimerListener {
25				listener,
26				handler_guard: Some(handler_guard),
27			},
28		)
29	}
30
31	pub(crate) fn trigger(self) -> TimeHandlerFinished {
32		let Self {
33			trigger,
34			handler_finished_waiter,
35		} = self;
36		trigger.notify(1);
37		handler_finished_waiter
38	}
39}
40
41pin_project! {
42	#[derive(Debug)]
43	pub struct TimerListener {
44		#[pin]
45		listener: EventListener,
46		handler_guard: Option<TimeHandlerGuard>,
47	}
48}
49
50impl Future for TimerListener {
51	type Output = TimeHandlerGuard;
52
53	fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
54		let this = self.project();
55
56		ready!(this.listener.poll(context));
57
58		match this.handler_guard.take() {
59			Some(handler_guard) => Poll::Ready(handler_guard),
60			None => Poll::Pending,
61		}
62	}
63}
64
65#[cfg(test)]
66mod test {
67	use super::*;
68	use futures_lite::future::poll_once;
69	use std::pin::pin;
70
71	#[tokio::test]
72	async fn timer_should_trigger_timer_listener() {
73		let (timer, listener) = Timer::new();
74
75		let mut listener = pin!(listener);
76		assert!(
77			poll_once(listener.as_mut()).await.is_none(),
78			"Future should have been pending before the timer is triggered",
79		);
80		let _ = timer.trigger();
81
82		assert!(
83			poll_once(listener.as_mut()).await.is_some(),
84			"Future should have been ready after timer was triggered"
85		);
86	}
87
88	#[tokio::test]
89	async fn time_handler_finished_should_be_triggered_by_time_handler_completion() {
90		let (timer, listener) = Timer::new();
91
92		let time_handler_finished = timer.trigger();
93		let time_handler_guard = listener.await;
94
95		let mut waiter = pin!(time_handler_finished.wait());
96		assert!(
97			poll_once(waiter.as_mut()).await.is_none(),
98			"Future should have been pending before the time handler is finished (guard dropped)",
99		);
100
101		drop(time_handler_guard);
102		assert!(
103			poll_once(waiter.as_mut()).await.is_some(),
104			"Future should have been ready after the time handler is finished (guard dropped)",
105		);
106	}
107}