How to handle Stdin hanging when there is no input

tokio already comes with impl AsyncRead for Stdin, so you should be able to do something like

async fn read_from_stdin_timeout(timeout: Duration) -> io::Result<String> {
    let mut buf = String::new();
    tokio::time::timeout(timeout, tokio::io::stdin().read_to_string(&mut buf)).await??;
    Ok(buf)
}

Unfortunately, the Playground seems to close stdin immediately, so I couldn't actually test it – I get back an empty string successfully instead of a timeout error.