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