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 | |
72 | use core::future::Future; |
73 | use core::marker::PhantomData; |
74 | use core::pin::Pin; |
75 | use core::task::{Context, Poll}; |
76 | |
77 | use event_listener::{EventListener, Listener}; |
78 | |
79 | #[doc (hidden)] |
80 | pub use pin_project_lite::pin_project; |
81 | |
82 | #[doc (no_inline)] |
83 | pub 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 ] |
141 | macro_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. |
283 | pub 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 | |
323 | pin_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 | |
334 | impl<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 | |
348 | impl<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 | |
374 | impl<F: EventListenerFuture> From<F> for FutureWrapper<F> { |
375 | #[inline ] |
376 | fn from(inner: F) -> Self { |
377 | Self { inner } |
378 | } |
379 | } |
380 | |
381 | impl<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 | /// ``` |
429 | pub 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)] |
449 | pub 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 | |
459 | impl<'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" )))] |
490 | pub struct Blocking { |
491 | _private: (), |
492 | } |
493 | |
494 | #[cfg (all(feature = "std" , not(target_family = "wasm" )))] |
495 | impl 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: T = event_listenerL |
512 | .take() |
513 | .expect(msg:"`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)] |
523 | pub struct Ready { |
524 | _private: (), |
525 | } |
526 | |
527 | #[cfg (feature = "std" )] |
528 | impl 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 ] |
538 | fn 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 | } |
550 | |