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}