actix_utils/future/
poll_fn.rs1use core::{
4 fmt,
5 future::Future,
6 pin::Pin,
7 task::{Context, Poll},
8};
9
10#[inline]
37pub fn poll_fn<F, T>(f: F) -> PollFn<F>
38where
39 F: FnMut(&mut Context<'_>) -> Poll<T>,
40{
41 PollFn { f }
42}
43
44pub struct PollFn<F> {
46 f: F,
47}
48
49impl<F> fmt::Debug for PollFn<F> {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 f.debug_struct("PollFn").finish()
52 }
53}
54
55impl<F, T> Future for PollFn<F>
56where
57 F: FnMut(&mut Context<'_>) -> Poll<T>,
58{
59 type Output = T;
60
61 #[inline]
62 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
63 #[allow(clippy::needless_borrow)]
66 (unsafe { &mut self.get_unchecked_mut().f })(cx)
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use std::marker::PhantomPinned;
73
74 use super::*;
75
76 static_assertions::assert_impl_all!(PollFn<()>: Unpin);
77 static_assertions::assert_not_impl_all!(PollFn<PhantomPinned>: Unpin);
78
79 #[actix_rt::test]
80 async fn test_poll_fn() {
81 let res = poll_fn(|_| Poll::Ready(42)).await;
82 assert_eq!(res, 42);
83
84 let mut i = 5;
85 let res = poll_fn(|cx| {
86 i -= 1;
87
88 if i > 0 {
89 cx.waker().wake_by_ref();
90 Poll::Pending
91 } else {
92 Poll::Ready(42)
93 }
94 })
95 .await;
96 assert_eq!(res, 42);
97 }
98
99 #[allow(dead_code)]
102 fn require_send<T: Send>(_t: &T) {}
103 #[allow(dead_code)]
104 fn require_sync<T: Sync>(_t: &T) {}
105
106 #[allow(unused)]
107 trait AmbiguousIfUnpin<A> {
108 fn some_item(&self) {}
109 }
110 impl<T: ?Sized> AmbiguousIfUnpin<()> for T {}
111 impl<T: ?Sized + Unpin> AmbiguousIfUnpin<[u8; 0]> for T {}
112
113 const _: fn() = || {
114 let pinned = std::marker::PhantomPinned;
115 let f = poll_fn(move |_| {
116 let _ = &pinned;
118 std::task::Poll::Pending::<()>
119 });
120 require_send(&f);
121 require_sync(&f);
122 AmbiguousIfUnpin::some_item(&f);
123 };
124}