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 | |
70 | use core::future::Future; |
71 | use core::marker::PhantomData; |
72 | use core::pin::Pin; |
73 | use core::task::{Context, Poll}; |
74 | |
75 | use event_listener::EventListener; |
76 | |
77 | #[doc (hidden)] |
78 | pub 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 ] |
136 | macro_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. |
278 | pub 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 | |
318 | pin_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 | |
329 | impl<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 | |
343 | impl<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 | |
369 | impl<F: EventListenerFuture> From<F> for FutureWrapper<F> { |
370 | #[inline ] |
371 | fn from(inner: F) -> Self { |
372 | Self { inner } |
373 | } |
374 | } |
375 | |
376 | impl<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 | /// ``` |
422 | pub 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)] |
442 | pub struct NonBlocking<'a> { |
443 | _marker: PhantomData<Context<'a>>, |
444 | } |
445 | |
446 | impl<'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" )))] |
468 | pub struct Blocking { |
469 | _private: (), |
470 | } |
471 | |
472 | #[cfg (all(feature = "std" , not(target_family = "wasm" )))] |
473 | impl<'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)] |
498 | pub struct Ready { |
499 | _private: (), |
500 | } |
501 | |
502 | #[cfg (feature = "std" )] |
503 | impl 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 | |