1// SPDX-Licenser-Identifier: MIT OR Apache-2.0
2//! A strategy for using the [`event-listener`] crate in both blocking and non-blocking contexts.
3//!
4//! One of the stand-out features of the [`event-listener`] crate is the ability to use it in both
5//! asynchronous and synchronous contexts. However, sometimes using it like this causes a lot of
6//! boilerplate to be duplicated. This crate aims to reduce that boilerplate by providing an
7//! [`EventListenerFuture`] trait that implements both blocking and non-blocking functionality.
8//!
9//! # Examples
10//!
11//! ```
12//! use event_listener::{Event, EventListener};
13//! use event_listener_strategy::{EventListenerFuture, FutureWrapper, Strategy};
14//!
15//! use std::pin::Pin;
16//! use std::task::Poll;
17//! use std::thread;
18//! use std::sync::Arc;
19//!
20//! // A future that waits three seconds for an event to be fired.
21//! fn wait_three_seconds() -> WaitThreeSeconds {
22//! let event = Event::new();
23//! let listener = event.listen();
24//!
25//! thread::spawn(move || {
26//! thread::sleep(std::time::Duration::from_secs(3));
27//! event.notify(1);
28//! });
29//!
30//! WaitThreeSeconds { listener }
31//! }
32//!
33//! struct WaitThreeSeconds {
34//! listener: Pin<Box<EventListener>>,
35//! }
36//!
37//! impl EventListenerFuture for WaitThreeSeconds {
38//! type Output = ();
39//!
40//! fn poll_with_strategy<'a, S: Strategy<'a>>(
41//! mut self: Pin<&mut Self>,
42//! strategy: &mut S,
43//! context: &mut S::Context,
44//! ) -> Poll<Self::Output> {
45//! strategy.poll(self.listener.as_mut(), context)
46//! }
47//! }
48//!
49//! // Use the future in a blocking context.
50//! let future = wait_three_seconds();
51//! future.wait();
52//!
53//! // Use the future in a non-blocking context.
54//! futures_lite::future::block_on(async {
55//! let future = FutureWrapper::new(wait_three_seconds());
56//! future.await;
57//! });
58//! ```
59
60#![cfg_attr(not(feature = "std"), no_std)]
61#![cfg_attr(docsrs, feature(doc_cfg))]
62#![forbid(future_incompatible, missing_docs)]
63#![doc(
64 html_favicon_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
65)]
66#![doc(
67 html_logo_url = "https://raw.githubusercontent.com/smol-rs/smol/master/assets/images/logo_fullsize_transparent.png"
68)]
69
70use core::future::Future;
71use core::marker::PhantomData;
72use core::pin::Pin;
73use core::task::{Context, Poll};
74
75use event_listener::EventListener;
76
77#[doc(hidden)]
78pub use pin_project_lite::pin_project;
79
80/// A wrapper around an [`EventListenerFuture`] that can be easily exported for use.
81///
82/// This type implements [`Future`], has a `_new()` constructor, and a `wait()` method
83/// that uses the [`Blocking`] strategy to poll the future until it is ready.
84///
85/// # Examples
86///
87/// ```
88/// mod my_future {
89/// use event_listener_strategy::{easy_wrapper, EventListenerFuture, Strategy};
90/// use std::pin::Pin;
91/// use std::task::Poll;
92///
93/// struct MyFuture;
94///
95/// impl EventListenerFuture for MyFuture {
96/// type Output = ();
97///
98/// fn poll_with_strategy<'a, S: Strategy<'a>>(
99/// self: Pin<&mut Self>,
100/// strategy: &mut S,
101/// context: &mut S::Context,
102/// ) -> Poll<Self::Output> {
103/// /* ... */
104/// # Poll::Ready(())
105/// }
106/// }
107///
108/// easy_wrapper! {
109/// /// A future that does something.
110/// pub struct MyFutureWrapper(MyFuture => ());
111/// /// Wait for it.
112/// pub wait();
113/// }
114///
115/// impl MyFutureWrapper {
116/// /// Create a new instance of the future.
117/// pub fn new() -> Self {
118/// Self::_new(MyFuture)
119/// }
120/// }
121/// }
122///
123/// use my_future::MyFutureWrapper;
124///
125/// // Use the future in a blocking context.
126/// let future = MyFutureWrapper::new();
127/// future.wait();
128///
129/// // Use the future in a non-blocking context.
130/// futures_lite::future::block_on(async {
131/// let future = MyFutureWrapper::new();
132/// future.await;
133/// });
134/// ```
135#[macro_export]
136macro_rules! easy_wrapper {
137 (
138 $(#[$meta:meta])*
139 $vis:vis struct $name:ident
140
141 $(<
142 $( $lifetime:lifetime $(: $lifetime_bound:lifetime)? ),* $(,)?
143 $( $generics:ident
144 $(: $generics_bound:path)?
145 $(: ?$generics_unsized_bound:path)?
146 $(: $generics_lifetime_bound:lifetime)?
147 $(= $generics_default:ty)?
148 ),* $(,)?
149 >)?
150
151 ($inner:ty => $output:ty)
152
153 $(where
154 $( $where_clause_ty:ty
155 $(: $where_clause_bound:path)?
156 $(: ?$where_clause_unsized_bound:path)?
157 $(: $where_clause_lifetime_bound:lifetime)?
158 ),* $(,)?
159 )?
160
161 ;
162
163 $(#[$wait_meta:meta])*
164 $wait_vis: vis wait();
165 ) => {
166 $crate::pin_project! {
167 $(#[$meta])*
168 $vis struct $name $(<
169 $( $lifetime $(: $lifetime_bound)? ),*
170 $( $generics
171 $(: $generics_bound)?
172 $(: ?$generics_unsized_bound)?
173 $(: $generics_lifetime_bound)?
174 $(= $generics_default)?
175 ),*
176 >)? $(
177 where
178 $( $where_clause_ty
179 $(: $where_clause_bound)?
180 $(: ?$where_clause_unsized_bound)?
181 $(: $where_clause_lifetime_bound)?
182 ),*
183 )? {
184 #[pin]
185 _inner: $crate::FutureWrapper<$inner>
186 }
187 }
188
189 impl $(<
190 $( $lifetime $(: $lifetime_bound)? ,)*
191 $( $generics
192 $(: $generics_bound)?
193 $(: ?$generics_unsized_bound)?
194 $(: $generics_lifetime_bound)?
195 $(= $generics_default)?
196 ),*
197 >)? $name $(<
198 $( $lifetime ,)*
199 $( $generics ),*
200 >)? $(
201 where
202 $( $where_clause_ty
203 $(: $where_clause_bound)?
204 $(: ?$where_clause_unsized_bound)?
205 $(: $where_clause_lifetime_bound)?
206 ),*
207 )? {
208 #[inline]
209 fn _new(inner: $inner) -> Self {
210 Self {
211 _inner: $crate::FutureWrapper::new(inner)
212 }
213 }
214
215 $(#[$wait_meta])*
216 #[inline]
217 $wait_vis fn wait(self) -> $output {
218 use $crate::EventListenerFuture;
219 self._inner.into_inner().wait()
220 }
221
222 pub(crate) fn poll_with_strategy<'__strategy, __S: $crate::Strategy<'__strategy>>(
223 self: ::core::pin::Pin<&mut Self>,
224 strategy: &mut __S,
225 context: &mut __S::Context,
226 ) -> ::core::task::Poll<$output> {
227 self.project()._inner.get_pin_mut().poll_with_strategy(strategy, context)
228 }
229 }
230
231 impl $(<
232 $( $lifetime $(: $lifetime_bound)? ,)*
233 $( $generics
234 $(: $generics_bound)?
235 $(: ?$generics_unsized_bound)?
236 $(: $generics_lifetime_bound)?
237 $(= $generics_default)?
238 ),*
239 >)? ::core::future::Future for $name $(
240 <
241 $( $lifetime ,)*
242 $( $generics ),*
243 >
244 )? $(
245 where
246 $( $where_clause_ty
247 $(: $where_clause_bound)?
248 $(: ?$where_clause_unsized_bound)?
249 $(: $where_clause_lifetime_bound)?
250 ),*
251 )? {
252 type Output = $output;
253
254 #[inline]
255 fn poll(
256 self: ::core::pin::Pin<&mut Self>,
257 context: &mut ::core::task::Context<'_>
258 ) -> ::core::task::Poll<Self::Output> {
259 self.project()._inner.poll(context)
260 }
261 }
262 };
263}
264
265/// A future that runs using the [`event-listener`] crate.
266///
267/// This is similar to the [`Future`] trait from libstd, with one notable difference: it takes
268/// a strategy that tells it whether to operate in a blocking or non-blocking context. The
269/// `poll_with_strategy` method is the equivalent of the `poll` method in this regard; it uses
270/// the [`Strategy`] trait to determine how to poll the future.
271///
272/// From here, there are two additional things one can do with this trait:
273///
274/// - The `wait` method, which uses the [`Blocking`] strategy to poll the future until it is
275/// ready, blocking the current thread until it is.
276/// - The [`FutureWrapper`] type, which implements [`Future`] and uses the [`NonBlocking`]
277/// strategy to poll the future.
278pub trait EventListenerFuture {
279 /// The type of value produced on completion.
280 type Output;
281
282 /// Poll the future using the provided strategy.
283 ///
284 /// This function should use the `Strategy::poll` method to poll the future, and proceed
285 /// based on the result.
286 fn poll_with_strategy<'a, S: Strategy<'a>>(
287 self: Pin<&mut Self>,
288 strategy: &mut S,
289 context: &mut S::Context,
290 ) -> Poll<Self::Output>;
291
292 /// Wait for the future to complete, blocking the current thread.
293 ///
294 /// This function uses the [`Blocking`] strategy to poll the future until it is ready.
295 ///
296 /// The future should only return `Pending` if `Strategy::poll` returns error. Otherwise,
297 /// this function polls the future in a hot loop.
298 #[cfg(all(feature = "std", not(target_family = "wasm")))]
299 #[cfg_attr(docsrs, doc(all(feature = "std", not(target_family = "wasm"))))]
300 fn wait(mut self) -> Self::Output
301 where
302 Self: Sized,
303 {
304 // SAFETY: `self`/`this` is not moved out after this.
305 let mut this = unsafe { Pin::new_unchecked(&mut self) };
306
307 loop {
308 if let Poll::Ready(res) = this
309 .as_mut()
310 .poll_with_strategy(&mut Blocking::default(), &mut ())
311 {
312 return res;
313 }
314 }
315 }
316}
317
318pin_project_lite::pin_project! {
319 /// A wrapper around an [`EventListenerFuture`] that implements [`Future`].
320 ///
321 /// [`Future`]: core::future::Future
322 #[derive(Debug, Clone)]
323 pub struct FutureWrapper<F: ?Sized> {
324 #[pin]
325 inner: F,
326 }
327}
328
329impl<F: EventListenerFuture> FutureWrapper<F> {
330 /// Create a new `FutureWrapper` from the provided future.
331 #[inline]
332 pub fn new(inner: F) -> Self {
333 Self { inner }
334 }
335
336 /// Consume the `FutureWrapper`, returning the inner future.
337 #[inline]
338 pub fn into_inner(self) -> F {
339 self.inner
340 }
341}
342
343impl<F: ?Sized> FutureWrapper<F> {
344 /// Get a reference to the inner future.
345 #[inline]
346 pub fn get_ref(&self) -> &F {
347 &self.inner
348 }
349
350 /// Get a mutable reference to the inner future.
351 #[inline]
352 pub fn get_mut(&mut self) -> &mut F {
353 &mut self.inner
354 }
355
356 /// Get a pinned mutable reference to the inner future.
357 #[inline]
358 pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut F> {
359 self.project().inner
360 }
361
362 /// Get a pinned reference to the inner future.
363 #[inline]
364 pub fn get_pin_ref(self: Pin<&Self>) -> Pin<&F> {
365 self.project_ref().inner
366 }
367}
368
369impl<F: EventListenerFuture> From<F> for FutureWrapper<F> {
370 #[inline]
371 fn from(inner: F) -> Self {
372 Self { inner }
373 }
374}
375
376impl<F: EventListenerFuture + ?Sized> Future for FutureWrapper<F> {
377 type Output = F::Output;
378
379 #[inline]
380 fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
381 self.project()
382 .inner
383 .poll_with_strategy(&mut NonBlocking::default(), context)
384 }
385}
386
387/// A strategy for polling an [`EventListenerFuture`] or an [`EventListener`].
388///
389/// This trait is used by the [`EventListenerFuture::poll_with_strategy`] method to determine
390/// how to poll the future. It can also be used standalone, by calling the [`Strategy::wait`]
391/// method.
392///
393/// [`EventListenerFuture::poll_with_strategy`]: EventListenerFuture::poll_with_strategy
394/// [`EventListener`]: event_listener::EventListener
395///
396/// # Examples
397///
398/// ```
399/// use event_listener::{Event, EventListener};
400/// use event_listener_strategy::{EventListenerFuture, Strategy, Blocking, NonBlocking};
401/// use std::pin::Pin;
402///
403/// async fn wait_on<'a, S: Strategy<'a>>(evl: Pin<&'a mut EventListener>, strategy: &mut S) {
404/// strategy.wait(evl).await;
405/// }
406///
407/// # futures_lite::future::block_on(async {
408/// // Block on the future.
409/// let ev = Event::new();
410/// let mut listener = ev.listen();
411/// ev.notify(1);
412///
413/// wait_on(listener.as_mut(), &mut Blocking::default()).await;
414///
415/// // Poll the future.
416/// listener.as_mut().listen(&ev);
417/// ev.notify(1);
418///
419/// wait_on(listener.as_mut(), &mut NonBlocking::default()).await;
420/// # });
421/// ```
422pub trait Strategy<'a> {
423 /// The context needed to poll the future.
424 type Context: ?Sized;
425
426 /// The future returned by the [`Strategy::wait`] method.
427 type Future: Future + 'a;
428
429 /// Poll the event listener until it is ready.
430 fn poll<T>(
431 &mut self,
432 event_listener: Pin<&mut EventListener<T>>,
433 context: &mut Self::Context,
434 ) -> Poll<T>;
435
436 /// Wait for the event listener to become ready.
437 fn wait(&mut self, evl: Pin<&'a mut EventListener>) -> Self::Future;
438}
439
440/// A strategy that uses polling to efficiently wait for an event.
441#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
442pub struct NonBlocking<'a> {
443 _marker: PhantomData<Context<'a>>,
444}
445
446impl<'a, 'evl> Strategy<'evl> for NonBlocking<'a> {
447 type Context = Context<'a>;
448 type Future = Pin<&'evl mut EventListener>;
449
450 #[inline]
451 fn wait(&mut self, evl: Pin<&'evl mut EventListener>) -> Self::Future {
452 evl
453 }
454
455 #[inline]
456 fn poll<T>(
457 &mut self,
458 event_listener: Pin<&mut EventListener<T>>,
459 context: &mut Self::Context,
460 ) -> Poll<T> {
461 event_listener.poll(cx:context)
462 }
463}
464
465/// A strategy that blocks the current thread until the event is signalled.
466#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
467#[cfg(all(feature = "std", not(target_family = "wasm")))]
468pub struct Blocking {
469 _private: (),
470}
471
472#[cfg(all(feature = "std", not(target_family = "wasm")))]
473impl<'evl> Strategy<'evl> for Blocking {
474 type Context = ();
475 type Future = Ready;
476
477 #[inline]
478 fn wait(&mut self, evl: Pin<&'evl mut EventListener>) -> Self::Future {
479 evl.wait();
480 Ready { _private: () }
481 }
482
483 #[inline]
484 fn poll<T>(
485 &mut self,
486 event_listener: Pin<&mut EventListener<T>>,
487 _context: &mut Self::Context,
488 ) -> Poll<T> {
489 let result: T = event_listener.wait();
490 Poll::Ready(result)
491 }
492}
493
494/// A future that is always ready.
495#[cfg(feature = "std")]
496#[doc(hidden)]
497#[derive(Debug, Clone)]
498pub struct Ready {
499 _private: (),
500}
501
502#[cfg(feature = "std")]
503impl Future for Ready {
504 type Output = ();
505
506 #[inline]
507 fn poll(self: Pin<&mut Self>, _context: &mut Context<'_>) -> Poll<Self::Output> {
508 Poll::Ready(())
509 }
510}
511