async_dnssd/
notify.rs

1// tokio::sync::Notify hides `Notified` and also uses lifetimes;
2// we need 'static lifetime and explicit types.
3
4use std::{
5	future::Future,
6	pin::Pin,
7	sync::Arc,
8	task::{
9		Context,
10		Poll,
11	},
12};
13
14type NotifiedBox<'a> = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
15
16pub struct Notify {
17	notify: Arc<tokio::sync::Notify>,
18}
19
20impl Notify {
21	pub fn new() -> Self {
22		Self {
23			notify: Arc::new(tokio::sync::Notify::new()),
24		}
25	}
26
27	pub fn notified(&self) -> Notified {
28		Notified {
29			notify: self.notify.clone(),
30			notified: None,
31		}
32	}
33
34	pub fn notify_waiters(&self) {
35		self.notify.notify_waiters();
36	}
37}
38
39pub struct Notified {
40	notify: Arc<tokio::sync::Notify>,
41	notified: Option<NotifiedBox<'static>>,
42}
43
44impl Drop for Notified {
45	fn drop(&mut self) {
46		// make sure we drop `Notified` first as we cheated the lifetime
47		drop(self.notified.take());
48	}
49}
50
51impl Clone for Notified {
52	fn clone(&self) -> Self {
53		Self {
54			notify: self.notify.clone(),
55			notified: None,
56		}
57	}
58}
59
60impl Future for Notified {
61	type Output = ();
62
63	fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
64		let this = self.get_mut();
65		if this.notified.is_none() {
66			let notified: NotifiedBox<'_> = Box::pin(this.notify.notified());
67			// convert to static lifetime: we make sure to keep the Arc<Notify> alive
68			// until `notified` is gone.
69			let notified =
70				unsafe { std::mem::transmute::<NotifiedBox<'_>, NotifiedBox<'static>>(notified) };
71			this.notified = Some(notified);
72		}
73		this.notified.as_mut().unwrap().as_mut().poll(cx)
74	}
75}