n0_future/
lib.rs

1//! Re-exports of abstractions and implementations deemed useful and good by number 0 engineers.
2//!
3//! Read up more on our challenges with rust's async: <https://www.iroh.computer/blog/async-rust-challenges-in-iroh>
4//!
5//! This library also allows importing a single [`task`] and [`time`] module that'll work
6//! in `wasm*-*-unknown` targets, using `wasm_bindgen` and `wasm_bindgen_futures`, but mirroring
7//! the `tokio` API with only minor differences.
8//!
9//! ## Feature flags
10//!
11//! * `serde`: Enables serde support for the [`time::SystemTime`] type when building for WebAssembly.
12
13#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
14#![cfg_attr(not(test), deny(clippy::unwrap_used))]
15#![cfg_attr(n0_future_docsrs, feature(doc_auto_cfg))]
16
17mod maybe_future;
18
19pub mod task;
20pub mod time;
21
22// futures-* re-exports
23
24pub use futures_buffered::*;
25pub use futures_lite::{io, pin, ready, stream, Future, FutureExt, Stream, StreamExt};
26pub use futures_util::{future::Either, Sink, SinkExt, TryFutureExt, TryStreamExt};
27pub use maybe_future::MaybeFuture;
28
29/// Implementation and types for splitting a `Stream + Sink`.
30/// See [`split::split`].
31pub mod split {
32    pub use futures_util::stream::{SplitSink, SplitStream};
33
34    use crate::{Sink, Stream};
35
36    /// Splits a `Stream + Sink` object into separate `Sink` and `Stream`
37    /// objects.
38    ///
39    /// This can be useful when you want to split ownership between tasks, or
40    /// allow direct interaction between the two objects (e.g. via
41    /// `Sink::send_all`).
42    pub fn split<S, SinkItem>(stream_sink: S) -> (SplitSink<S, SinkItem>, SplitStream<S>)
43    where
44        S: Stream + Sized + Sink<SinkItem>,
45    {
46        use futures_util::stream::StreamExt as _;
47        stream_sink.split()
48    }
49}
50
51/// Re-exports boxed versions of [`Future`] and [`Stream`] traits
52/// that are `Send` in non-wasm and `!Send` in wasm.
53///
54/// If you don't want this type of target-dependend `Send` and `!Send`,
55/// use [`stream::Boxed`]/[`stream::BoxedLocal`] and
56/// [`future::Boxed`]/[`future::BoxedLocal`].
57///
58/// [`Future`]: futures_lite::Future
59/// [`Stream`]: futures_lite::Stream
60/// [`stream::Boxed`]: crate::stream::Boxed
61/// [`stream::BoxedLocal`]: crate::stream::BoxedLocal
62/// [`future::Boxed`]: crate::future::Boxed
63/// [`future::BoxedLocal`]: crate::future::BoxedLocal
64pub mod boxed {
65    #[cfg(not(wasm_browser))]
66    pub use futures_lite::future::Boxed as BoxFuture;
67    #[cfg(wasm_browser)]
68    pub use futures_lite::future::BoxedLocal as BoxFuture;
69    #[cfg(not(wasm_browser))]
70    pub use futures_lite::stream::Boxed as BoxStream;
71    #[cfg(wasm_browser)]
72    pub use futures_lite::stream::BoxedLocal as BoxStream;
73}
74
75/// Combinators for the [`Future`] trait.
76pub mod future {
77    use std::task::Poll;
78
79    pub use futures_lite::future::*;
80
81    use super::pin;
82
83    /// Poll a future once and return the output if ready.
84    ///
85    /// Evaluates and consumes the future, returning the resulting output if the future is
86    /// ready after the first call to [`Future::poll`].
87    ///
88    /// If poll instead returns [`Poll::Pending`], `None` is returned.
89    ///
90    /// This method is useful in cases where immediacy is more important than waiting for a
91    /// result. It is also convenient for quickly obtaining the value of a future that is
92    /// known to always resolve immediately.
93    pub fn now_or_never<T, F: Future<Output = T>>(fut: F) -> Option<T> {
94        pin!(fut);
95        let waker = std::task::Waker::noop();
96        let mut cx = std::task::Context::from_waker(waker);
97        match fut.poll(&mut cx) {
98            Poll::Ready(res) => Some(res),
99            Poll::Pending => None,
100        }
101    }
102
103    #[cfg(test)]
104    mod tests {
105        use super::*;
106
107        #[test]
108        fn test_now_or_never_smoke() {
109            let fut = std::future::ready(0);
110            assert_eq!(now_or_never(fut), Some(0));
111
112            let fut = std::future::pending::<isize>();
113            assert_eq!(now_or_never(fut), None);
114        }
115    }
116}