lightning/util/
native_async.rs

1// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
2// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
4// You may not use this file except in accordance with one or both of these
5// licenses.
6
7//! This module contains a few public utility which are used to run LDK in a native Rust async
8//! environment.
9
10#[cfg(all(test, feature = "std"))]
11use crate::sync::Mutex;
12use crate::util::async_poll::{MaybeSend, MaybeSync};
13
14#[cfg(all(test, not(feature = "std")))]
15use core::cell::RefCell;
16use core::future::Future;
17#[cfg(test)]
18use core::pin::Pin;
19
20/// A generic trait which is able to spawn futures in the background.
21///
22/// This is not exported to bindings users as async is only supported in Rust.
23pub trait FutureSpawner: MaybeSend + MaybeSync + 'static {
24	/// Spawns the given future as a background task.
25	///
26	/// This method MUST NOT block on the given future immediately.
27	fn spawn<T: Future<Output = ()> + MaybeSend + 'static>(&self, future: T);
28}
29
30#[cfg(test)]
31trait MaybeSendableFuture: Future<Output = ()> + MaybeSend + 'static {}
32#[cfg(test)]
33impl<F: Future<Output = ()> + MaybeSend + 'static> MaybeSendableFuture for F {}
34
35/// A simple [`FutureSpawner`] which holds [`Future`]s until they are manually polled via
36/// [`Self::poll_futures`].
37#[cfg(all(test, feature = "std"))]
38pub(crate) struct FutureQueue(Mutex<Vec<Pin<Box<dyn MaybeSendableFuture>>>>);
39#[cfg(all(test, not(feature = "std")))]
40pub(crate) struct FutureQueue(RefCell<Vec<Pin<Box<dyn MaybeSendableFuture>>>>);
41
42#[cfg(test)]
43impl FutureQueue {
44	pub(crate) fn new() -> Self {
45		#[cfg(feature = "std")]
46		{
47			FutureQueue(Mutex::new(Vec::new()))
48		}
49		#[cfg(not(feature = "std"))]
50		{
51			FutureQueue(RefCell::new(Vec::new()))
52		}
53	}
54
55	pub(crate) fn pending_futures(&self) -> usize {
56		#[cfg(feature = "std")]
57		{
58			self.0.lock().unwrap().len()
59		}
60		#[cfg(not(feature = "std"))]
61		{
62			self.0.borrow().len()
63		}
64	}
65
66	pub(crate) fn poll_futures(&self) {
67		let mut futures;
68		#[cfg(feature = "std")]
69		{
70			futures = self.0.lock().unwrap();
71		}
72		#[cfg(not(feature = "std"))]
73		{
74			futures = self.0.borrow_mut();
75		}
76		futures.retain_mut(|fut| {
77			use core::task::{Context, Poll};
78			let waker = crate::util::async_poll::dummy_waker();
79			match fut.as_mut().poll(&mut Context::from_waker(&waker)) {
80				Poll::Ready(()) => false,
81				Poll::Pending => true,
82			}
83		});
84	}
85}
86
87#[cfg(test)]
88impl FutureSpawner for FutureQueue {
89	fn spawn<T: Future<Output = ()> + MaybeSend + 'static>(&self, future: T) {
90		#[cfg(feature = "std")]
91		{
92			self.0.lock().unwrap().push(Box::pin(future));
93		}
94		#[cfg(not(feature = "std"))]
95		{
96			self.0.borrow_mut().push(Box::pin(future));
97		}
98	}
99}
100
101#[cfg(test)]
102impl<D: core::ops::Deref<Target = FutureQueue> + MaybeSend + MaybeSync + 'static> FutureSpawner
103	for D
104{
105	fn spawn<T: Future<Output = ()> + MaybeSend + 'static>(&self, future: T) {
106		#[cfg(feature = "std")]
107		{
108			self.0.lock().unwrap().push(Box::pin(future));
109		}
110		#[cfg(not(feature = "std"))]
111		{
112			self.0.borrow_mut().push(Box::pin(future));
113		}
114	}
115}