lightning/util/
async_poll.rs

1// This file is Copyright its original authors, visible in version control
2// history.
3//
4// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7// You may not use this file except in accordance with one or both of these
8// licenses.
9
10//! Some utilities to make working with the standard library's [`Future`]s easier
11
12use alloc::boxed::Box;
13use alloc::vec::Vec;
14use core::future::Future;
15use core::marker::Unpin;
16use core::pin::Pin;
17use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
18
19pub(crate) enum ResultFuture<F: Future<Output = Result<(), E>>, E: Unpin> {
20	Pending(F),
21	Ready(Result<(), E>),
22}
23
24pub(crate) struct MultiResultFuturePoller<F: Future<Output = Result<(), E>> + Unpin, E: Unpin> {
25	futures_state: Vec<ResultFuture<F, E>>,
26}
27
28impl<F: Future<Output = Result<(), E>> + Unpin, E: Unpin> MultiResultFuturePoller<F, E> {
29	pub fn new(futures_state: Vec<ResultFuture<F, E>>) -> Self {
30		Self { futures_state }
31	}
32}
33
34impl<F: Future<Output = Result<(), E>> + Unpin, E: Unpin> Future for MultiResultFuturePoller<F, E> {
35	type Output = Vec<Result<(), E>>;
36	fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Vec<Result<(), E>>> {
37		let mut have_pending_futures = false;
38		let futures_state = &mut self.get_mut().futures_state;
39		for state in futures_state.iter_mut() {
40			match state {
41				ResultFuture::Pending(ref mut fut) => match Pin::new(fut).poll(cx) {
42					Poll::Ready(res) => {
43						*state = ResultFuture::Ready(res);
44					},
45					Poll::Pending => {
46						have_pending_futures = true;
47					},
48				},
49				ResultFuture::Ready(_) => continue,
50			}
51		}
52
53		if have_pending_futures {
54			Poll::Pending
55		} else {
56			let results = futures_state
57				.drain(..)
58				.filter_map(|e| match e {
59					ResultFuture::Ready(res) => Some(res),
60					ResultFuture::Pending(_) => {
61						debug_assert!(
62							false,
63							"All futures are expected to be ready if none are pending"
64						);
65						None
66					},
67				})
68				.collect();
69			Poll::Ready(results)
70		}
71	}
72}
73
74// If we want to poll a future without an async context to figure out if it has completed or
75// not without awaiting, we need a Waker, which needs a vtable...we fill it with dummy values
76// but sadly there's a good bit of boilerplate here.
77//
78// Waker::noop() would be preferable, but requires an MSRV of 1.85.
79fn dummy_waker_clone(_: *const ()) -> RawWaker {
80	RawWaker::new(core::ptr::null(), &DUMMY_WAKER_VTABLE)
81}
82fn dummy_waker_action(_: *const ()) {}
83
84const DUMMY_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
85	dummy_waker_clone,
86	dummy_waker_action,
87	dummy_waker_action,
88	dummy_waker_action,
89);
90
91pub(crate) fn dummy_waker() -> Waker {
92	unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &DUMMY_WAKER_VTABLE)) }
93}
94
95#[cfg(feature = "std")]
96/// A type alias for a future that returns a result of type `T` or error `E`.
97///
98/// This is not exported to bindings users as async is only supported in Rust.
99pub type AsyncResult<'a, T, E> = Pin<Box<dyn Future<Output = Result<T, E>> + 'a + Send>>;
100#[cfg(not(feature = "std"))]
101/// A type alias for a future that returns a result of type `T` or error `E`.
102///
103/// This is not exported to bindings users as async is only supported in Rust.
104pub type AsyncResult<'a, T, E> = Pin<Box<dyn Future<Output = Result<T, E>> + 'a>>;
105
106/// Marker trait to optionally implement `Sync` under std.
107///
108/// This is not exported to bindings users as async is only supported in Rust.
109#[cfg(feature = "std")]
110pub use core::marker::Sync as MaybeSync;
111
112#[cfg(not(feature = "std"))]
113/// Marker trait to optionally implement `Sync` under std.
114///
115/// This is not exported to bindings users as async is only supported in Rust.
116pub trait MaybeSync {}
117#[cfg(not(feature = "std"))]
118impl<T> MaybeSync for T where T: ?Sized {}
119
120/// Marker trait to optionally implement `Send` under std.
121///
122/// This is not exported to bindings users as async is only supported in Rust.
123#[cfg(feature = "std")]
124pub use core::marker::Send as MaybeSend;
125
126#[cfg(not(feature = "std"))]
127/// Marker trait to optionally implement `Send` under std.
128///
129/// This is not exported to bindings users as async is only supported in Rust.
130pub trait MaybeSend {}
131#[cfg(not(feature = "std"))]
132impl<T> MaybeSend for T where T: ?Sized {}