Функция poll_fn
#![allow(unused)] fn main() { pub fn poll_fn<T, F>(f: F) -> PollFn<F> ⓘ where F: FnMut(&mut Context<'_>) -> Poll<T>, }
Создает фьючер, который оборачивает функцию, возвращающую
Poll.
Опрос фьючера делегируется обернутой функции. Если возвращенный фьючер закреплен (pinned), то захваченное окружение обернутой функции также закрепляется на месте, поэтому до тех пор, пока замыкание не перемещает свои захваты, оно может безопасно создавать закрепленные ссылки на них.
Примеры
#![allow(unused)] fn main() { use core::future::poll_fn; use std::task::{Context, Poll}; fn read_line(_cx: &mut Context<'_>) -> Poll<String> { Poll::Ready("Hello, World!".into()) } let read_future = poll_fn(read_line); assert_eq!(read_future.await, "Hello, World!".to_owned()); }
Захват закрепленного состояния
Пример замыкания, оборачивающего внутренние фьючеры:
#![allow(unused)] fn main() { use core::future::{self, Future}; use core::task::Poll; /// Разрешается в первый завершившийся фьючер. В случае ничьей побеждает `a`. fn naive_select<T>( a: impl Future<Output = T>, b: impl Future<Output = T>, ) -> impl Future<Output = T> { let (mut a, mut b) = (Box::pin(a), Box::pin(b)); future::poll_fn(move |cx| { if let Poll::Ready(r) = a.as_mut().poll(cx) { Poll::Ready(r) } else if let Poll::Ready(r) = b.as_mut().poll(cx) { Poll::Ready(r) } else { Poll::Pending } }) } let a = async { 42 }; let b = future::pending(); let v = naive_select(a, b).await; assert_eq!(v, 42); let a = future::pending(); let b = async { 27 }; let v = naive_select(a, b).await; assert_eq!(v, 27); let a = async { 42 }; let b = async { 27 }; let v = naive_select(a, b).await; assert_eq!(v, 42); // предвзятость к `a` в случае ничьей! }
На этот раз без Box::pin:
#![allow(unused)] fn main() { use core::future::{self, Future}; use core::pin::pin; use core::task::Poll; /// Разрешается в первый завершившийся фьючер. В случае ничьей побеждает `a`. fn naive_select<T>( a: impl Future<Output = T>, b: impl Future<Output = T>, ) -> impl Future<Output = T> { async { let (mut a, mut b) = (pin!(a), pin!(b)); future::poll_fn(move |cx| { if let Poll::Ready(r) = a.as_mut().poll(cx) { Poll::Ready(r) } else if let Poll::Ready(r) = b.as_mut().poll(cx) { Poll::Ready(r) } else { Poll::Pending } }).await } } let a = async { 42 }; let b = future::pending(); let v = naive_select(a, b).await; assert_eq!(v, 42); }
Обратите внимание, как благодаря нахождению в асинхронном контексте мы смогли заставить работать макрос
pin!, тем самым избежав необходимости использования небезопасного конструктораPin::new_unchecked(&mut fut).