event_listener_strategy/
lib.rs

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