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: Some(listener) }
31//! }
32//!
33//! struct WaitThreeSeconds {
34//! listener: Option<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(&mut self.listener, 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, Listener};
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: 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 listener = ev.listen();
411/// ev.notify(1);
412///
413/// wait_on(listener, &mut Blocking::default()).await;
414///
415/// // Poll the future.
416/// let listener = ev.listen();
417/// ev.notify(1);
418///
419/// wait_on(listener, &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, L: Listener<T> + Unpin>(
431 &mut self,
432 event_listener: &mut Option<L>,
433 context: &mut Self::Context,
434 ) -> Poll<T>;
435
436 /// Wait for the event listener to become ready.
437 fn wait(&mut self, evl: 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 /// The type `&'a mut &'a T` is invariant over `'a`, like `Context` is.
444 ///
445 /// We used to just use `Context` here, but then `Context` became `!Send`
446 /// and `!Sync`, making all of the futures that use this type `!Send` and
447 /// `!Sync` as well. So we just take the lifetime invariance and none of
448 /// the downsides.
449 _marker: PhantomData<&'a mut &'a ()>,
450}
451
452impl<'a, 'evl> Strategy<'evl> for NonBlocking<'a> {
453 type Context = Context<'a>;
454 type Future = EventListener;
455
456 #[inline]
457 fn wait(&mut self, evl: EventListener) -> Self::Future {
458 evl
459 }
460
461 #[inline]
462 fn poll<T, L: Listener<T> + Unpin>(
463 &mut self,
464 event_listener: &mut Option<L>,
465 context: &mut Self::Context,
466 ) -> Poll<T> {
467 let poll = Pin::new(
468 event_listener
469 .as_mut()
470 .expect("`event_listener` should never be `None`"),
471 )
472 .poll(context);
473 if poll.is_ready() {
474 *event_listener = None;
475 }
476 poll
477 }
478}
479
480/// A strategy that blocks the current thread until the event is signalled.
481#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
482#[cfg(all(feature = "std", not(target_family = "wasm")))]
483pub struct Blocking {
484 _private: (),
485}
486
487#[cfg(all(feature = "std", not(target_family = "wasm")))]
488impl<'evl> Strategy<'evl> for Blocking {
489 type Context = ();
490 type Future = Ready;
491
492 #[inline]
493 fn wait(&mut self, evl: EventListener) -> Self::Future {
494 evl.wait();
495 Ready { _private: () }
496 }
497
498 #[inline]
499 fn poll<T, L: Listener<T> + Unpin>(
500 &mut self,
501 event_listener: &mut Option<L>,
502 _context: &mut Self::Context,
503 ) -> Poll<T> {
504 let result: T = event_listenerL
505 .take()
506 .expect(msg:"`event_listener` should never be `None`")
507 .wait();
508 Poll::Ready(result)
509 }
510}
511
512/// A future that is always ready.
513#[cfg(feature = "std")]
514#[doc(hidden)]
515#[derive(Debug, Clone)]
516pub struct Ready {
517 _private: (),
518}
519
520#[cfg(feature = "std")]
521impl Future for Ready {
522 type Output = ();
523
524 #[inline]
525 fn poll(self: Pin<&mut Self>, _context: &mut Context<'_>) -> Poll<Self::Output> {
526 Poll::Ready(())
527 }
528}
529
530#[test]
531fn send_and_sync() {
532 fn assert_send_and_sync<T: Send + Sync>() {}
533
534 #[cfg(all(feature = "std", not(target_family = "wasm")))]
535 {
536 assert_send_and_sync::<Blocking>();
537 assert_send_and_sync::<Ready>();
538 }
539
540 assert_send_and_sync::<NonBlocking<'static>>();
541 assert_send_and_sync::<FutureWrapper<()>>();
542}
543