@@ -8,6 +8,31 @@ use core::{
8
8
} ;
9
9
10
10
/// Creates a future driven by the provided function that receives a task context.
11
+ ///
12
+ /// # Examples
13
+ /// ```
14
+ /// # use std::task::Poll;
15
+ /// # use actix_utils::future::poll_fn;
16
+ /// # async fn test_poll_fn() {
17
+ /// let res = poll_fn(|_| Poll::Ready(42)).await;
18
+ /// assert_eq!(res, 42);
19
+ ///
20
+ /// let mut i = 5;
21
+ /// let res = poll_fn(|cx| {
22
+ /// i -= 1;
23
+ ///
24
+ /// if i > 0 {
25
+ /// cx.waker().wake_by_ref();
26
+ /// Poll::Pending
27
+ /// } else {
28
+ /// Poll::Ready(42)
29
+ /// }
30
+ /// })
31
+ /// .await;
32
+ /// assert_eq!(res, 42);
33
+ /// # }
34
+ /// # actix_rt::Runtime::new().unwrap().block_on(test_poll_fn());
35
+ /// ```
11
36
#[ inline]
12
37
pub fn poll_fn < F , T > ( f : F ) -> PollFn < F >
13
38
where
@@ -16,13 +41,11 @@ where
16
41
PollFn { f }
17
42
}
18
43
19
- /// A Future driven by the inner function.
44
+ /// Future for the [`poll_fn`] function.
20
45
pub struct PollFn < F > {
21
46
f : F ,
22
47
}
23
48
24
- impl < F > Unpin for PollFn < F > { }
25
-
26
49
impl < F > fmt:: Debug for PollFn < F > {
27
50
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
28
51
f. debug_struct ( "PollFn" ) . finish ( )
@@ -36,15 +59,22 @@ where
36
59
type Output = T ;
37
60
38
61
#[ inline]
39
- fn poll ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
40
- ( self . f ) ( cx)
62
+ fn poll ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Self :: Output > {
63
+ // SAFETY: we are not moving out of the pinned field
64
+ // see https://github.com/rust-lang/rust/pull/102737
65
+ ( unsafe { & mut self . get_unchecked_mut ( ) . f } ) ( cx)
41
66
}
42
67
}
43
68
44
69
#[ cfg( test) ]
45
70
mod tests {
71
+ use std:: marker:: PhantomPinned ;
72
+
46
73
use super :: * ;
47
74
75
+ static_assertions:: assert_impl_all!( PollFn <( ) >: Unpin ) ;
76
+ static_assertions:: assert_not_impl_all!( PollFn <PhantomPinned >: Unpin ) ;
77
+
48
78
#[ actix_rt:: test]
49
79
async fn test_poll_fn ( ) {
50
80
let res = poll_fn ( |_| Poll :: Ready ( 42 ) ) . await ;
@@ -64,4 +94,29 @@ mod tests {
64
94
. await ;
65
95
assert_eq ! ( res, 42 ) ;
66
96
}
97
+
98
+ // following soundness tests taken from https://github.com/tokio-rs/tokio/pull/5087
99
+
100
+ #[ allow( dead_code) ]
101
+ fn require_send < T : Send > ( _t : & T ) { }
102
+ #[ allow( dead_code) ]
103
+ fn require_sync < T : Sync > ( _t : & T ) { }
104
+
105
+ trait AmbiguousIfUnpin < A > {
106
+ fn some_item ( & self ) { }
107
+ }
108
+ impl < T : ?Sized > AmbiguousIfUnpin < ( ) > for T { }
109
+ impl < T : ?Sized + Unpin > AmbiguousIfUnpin < [ u8 ; 0 ] > for T { }
110
+
111
+ const _: fn ( ) = || {
112
+ let pinned = std:: marker:: PhantomPinned ;
113
+ let f = poll_fn ( move |_| {
114
+ // Use `pinned` to take ownership of it.
115
+ let _ = & pinned;
116
+ std:: task:: Poll :: Pending :: < ( ) >
117
+ } ) ;
118
+ require_send ( & f) ;
119
+ require_sync ( & f) ;
120
+ AmbiguousIfUnpin :: some_item ( & f) ;
121
+ } ;
67
122
}
0 commit comments