Remove `futures` dependency in `lightning-background-processor`
[rust-lightning] / lightning-background-processor / src / lib.rs
index e15458d54b22c101c63d5961d11cd6182515e398..884a7c2266420eb17f568f5da4cb65d513f6cae1 100644 (file)
@@ -7,7 +7,7 @@
 #![deny(private_intra_doc_links)]
 
 #![deny(missing_docs)]
-#![deny(unsafe_code)]
+#![cfg_attr(not(feature = "futures"), deny(unsafe_code))]
 
 #![cfg_attr(docsrs, feature(doc_auto_cfg))]
 
@@ -52,8 +52,6 @@ use std::thread::{self, JoinHandle};
 #[cfg(feature = "std")]
 use std::time::Instant;
 
-#[cfg(feature = "futures")]
-use futures_util::task;
 #[cfg(not(feature = "std"))]
 use alloc::vec::Vec;
 
@@ -385,38 +383,48 @@ macro_rules! define_run_body {
 }
 
 #[cfg(feature = "futures")]
-use core::future::Future;
-#[cfg(feature = "futures")]
-use core::task::Poll;
-#[cfg(feature = "futures")]
-use core::pin::Pin;
-#[cfg(feature = "futures")]
-use core::marker::Unpin;
-#[cfg(feature = "futures")]
-struct Selector<A: Future<Output=()> + Unpin, B: Future<Output=bool> + Unpin> {
-       a: A,
-       b: B,
-}
-#[cfg(feature = "futures")]
-enum SelectorOutput {
-       A, B(bool),
-}
+pub(crate) mod futures_util {
+       use core::future::Future;
+       use core::task::{Poll, Waker, RawWaker, RawWakerVTable};
+       use core::pin::Pin;
+       use core::marker::Unpin;
+       pub(crate) struct Selector<A: Future<Output=()> + Unpin, B: Future<Output=bool> + Unpin> {
+               pub a: A,
+               pub b: B,
+       }
+       pub(crate) enum SelectorOutput {
+               A, B(bool),
+       }
 
-#[cfg(feature = "futures")]
-impl<A: Future<Output=()> + Unpin, B: Future<Output=bool> + Unpin> Future for Selector<A, B> {
-       type Output = SelectorOutput;
-       fn poll(mut self: Pin<&mut Self>, ctx: &mut core::task::Context<'_>) -> Poll<SelectorOutput> {
-               match Pin::new(&mut self.a).poll(ctx) {
-                       Poll::Ready(()) => { return Poll::Ready(SelectorOutput::A); },
-                       Poll::Pending => {},
-               }
-               match Pin::new(&mut self.b).poll(ctx) {
-                       Poll::Ready(res) => { return Poll::Ready(SelectorOutput::B(res)); },
-                       Poll::Pending => {},
+       impl<A: Future<Output=()> + Unpin, B: Future<Output=bool> + Unpin> Future for Selector<A, B> {
+               type Output = SelectorOutput;
+               fn poll(mut self: Pin<&mut Self>, ctx: &mut core::task::Context<'_>) -> Poll<SelectorOutput> {
+                       match Pin::new(&mut self.a).poll(ctx) {
+                               Poll::Ready(()) => { return Poll::Ready(SelectorOutput::A); },
+                               Poll::Pending => {},
+                       }
+                       match Pin::new(&mut self.b).poll(ctx) {
+                               Poll::Ready(res) => { return Poll::Ready(SelectorOutput::B(res)); },
+                               Poll::Pending => {},
+                       }
+                       Poll::Pending
                }
-               Poll::Pending
        }
+
+       // If we want to poll a future without an async context to figure out if it has completed or
+       // not without awaiting, we need a Waker, which needs a vtable...we fill it with dummy values
+       // but sadly there's a good bit of boilerplate here.
+       fn dummy_waker_clone(_: *const ()) -> RawWaker { RawWaker::new(core::ptr::null(), &DUMMY_WAKER_VTABLE) }
+       fn dummy_waker_action(_: *const ()) { }
+
+       const DUMMY_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
+               dummy_waker_clone, dummy_waker_action, dummy_waker_action, dummy_waker_action);
+       pub(crate) fn dummy_waker() -> Waker { unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &DUMMY_WAKER_VTABLE)) } }
 }
+#[cfg(feature = "futures")]
+use futures_util::{Selector, SelectorOutput, dummy_waker};
+#[cfg(feature = "futures")]
+use core::task;
 
 /// Processes background events in a future.
 ///
@@ -517,7 +525,7 @@ where
                        }
                }, |t| sleeper(Duration::from_secs(t)),
                |fut: &mut SleepFuture, _| {
-                       let mut waker = task::noop_waker();
+                       let mut waker = dummy_waker();
                        let mut ctx = task::Context::from_waker(&mut waker);
                        core::pin::Pin::new(fut).poll(&mut ctx).is_ready()
                })