1 | #![allow (dead_code)] |
2 | |
3 | //! Definition of the `PollFn` adapter combinator. |
4 | |
5 | use std::fmt; |
6 | use std::future::Future; |
7 | use std::pin::Pin; |
8 | use std::task::{Context, Poll}; |
9 | |
10 | // This struct is intentionally `!Unpin` when `F` is `!Unpin`. This is to |
11 | // mitigate the issue where rust puts noalias on mutable references to the |
12 | // `PollFn` type if it is `Unpin`. If the closure has ownership of a future, |
13 | // then this "leaks" and the future is affected by noalias too, which we don't |
14 | // want. |
15 | // |
16 | // See this thread for more information: |
17 | // <https://internals.rust-lang.org/t/surprising-soundness-trouble-around-pollfn/17484> |
18 | // |
19 | // The fact that `PollFn` is not `Unpin` when it shouldn't be is tested in |
20 | // `tests/async_send_sync.rs`. |
21 | |
22 | /// Future for the [`poll_fn`] function. |
23 | pub struct PollFn<F> { |
24 | f: F, |
25 | } |
26 | |
27 | /// Creates a new future wrapping around a function returning [`Poll`]. |
28 | pub fn poll_fn<T, F>(f: F) -> PollFn<F> |
29 | where |
30 | F: FnMut(&mut Context<'_>) -> Poll<T>, |
31 | { |
32 | PollFn { f } |
33 | } |
34 | |
35 | impl<F> fmt::Debug for PollFn<F> { |
36 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
37 | f.debug_struct(name:"PollFn" ).finish() |
38 | } |
39 | } |
40 | |
41 | impl<T, F> Future for PollFn<F> |
42 | where |
43 | F: FnMut(&mut Context<'_>) -> Poll<T>, |
44 | { |
45 | type Output = T; |
46 | |
47 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> { |
48 | // Safety: We never construct a `Pin<&mut F>` anywhere, so accessing `f` |
49 | // mutably in an unpinned way is sound. |
50 | // |
51 | // This use of unsafe cannot be replaced with the pin-project macro |
52 | // because: |
53 | // * If we put `#[pin]` on the field, then it gives us a `Pin<&mut F>`, |
54 | // which we can't use to call the closure. |
55 | // * If we don't put `#[pin]` on the field, then it makes `PollFn` be |
56 | // unconditionally `Unpin`, which we also don't want. |
57 | let me: &mut PollFn = unsafe { Pin::into_inner_unchecked(self) }; |
58 | (me.f)(cx) |
59 | } |
60 | } |
61 | |