Reputation: 585
Futures in Rust can be polled without blocking to check if the future is ready (and do some work in the process). With that in mind, is it possible to "check" if a future is ready, without consuming its output?
stdin
would be polled if there is any data, and take action on the input (playground):
async fn read_input_if_available() {
use tokio::io::AsyncReadExt;
let mut stdin = tokio::io::stdin();
// if !stdin.ready() {
// return;
// }
let mut input = String::new();
let mut buffer = [0_u8; 1024];
while let Ok(bytes) = stdin.read(&mut buffer).await {
if let Ok(string) = std::str::from_utf8(&buffer[..bytes]) {
input.push_str(string);
}
}
// Take action on `input` here
}
When the code hits the await
, it will not proceed until there is something on stdin, even if just waiting for an EOF
.
I used tokio::io::Stdin
because it is simpler for a self-contained example, but the question is about Rust futures in general.
Upvotes: 6
Views: 5630
Reputation: 431669
No, not directly. Like iterators, futures and streams are one-shot: you can only get the result of poll
or poll_next
once.
Iterators have the peekable
method and futures and streams have analogs:
In some cases, you may be able to use FutureExt::now_or_never
combined with the implementation of Future
for a mutable reference:
use futures::FutureExt; // 0.3.13
use std::time::Duration;
use tokio::time; // 1.3.0
#[tokio::main]
async fn main() {
let mut f = something_else().boxed();
if let Some(v) = (&mut f).now_or_never() {
eprintln!("it was ready and it was {}", v);
} else {
time::sleep(Duration::from_millis(500)).await;
let v = f.await;
eprintln!("now it's ready and it was {}", v);
}
}
async fn something_else() -> i32 {
//time::sleep(Duration::from_millis(1000)).await;
42
}
You do need to ensure that the future implements Unpin
(done here via FutureExt::boxed
and you must not .await
a future after it has already finished.
Upvotes: 7