• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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`].
poll_fn<T, F>(f: F) -> PollFn<F> where F: FnMut(&mut Context<'_>) -> Poll<T>,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> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result36     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37         f.debug_struct("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 
poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T>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 = unsafe { Pin::into_inner_unchecked(self) };
58         (me.f)(cx)
59     }
60 }
61