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.