The book's guessing game, but with a timelimit

Hi there,

I wanted to play around with threads a little bit and had the idea to implement a time limit on the number guessing game from the rust book.
The following code spawns two threads. One plays the regular guessing game and sends the enum Won to the main thread. The other one sleeps for 30s and sends the enum Timeout to the main thread. The main thread takes the first result and matches it to some output. Is this a "good" way to implement a time limit for input or is there a better more elegant way to do it?

use std::io;
use std::thread;
use std::sync::mpsc;
use std::cmp::Ordering;
use std::time::Duration;
use rand::Rng;

enum GameResult {

fn guessing_game() {
    println!("Guess the number!");
    let secret_number = rand::thread_rng().gen_range(1..101);
    loop {
        println!("Please enter your guess.");
        let mut guess = String::new();
        io::stdin().read_line(&mut guess)
            .expect("Failed to read line.");
        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => continue
        println!("You guessed: {guess}");
        match guess.cmp(&secret_number) {
            Ordering::Less => println!("Too small"),
            Ordering::Greater => println!("Too big"),
            Ordering::Equal => {

fn main() {
    const MAX_TIME_S:u64 = 30; 
    println!("You have {MAX_TIME_S}s!");
    let (tgame, rstate) = mpsc::channel();
    let ttimer = tgame.clone();
    thread::spawn(move || {
    thread::spawn(move || {

    let recvstate = rstate.recv().unwrap();
    match recvstate {
        GameResult::Won => println!("You Win!"),
        GameResult::Timeout => println!("You are too slow!")

Lets consider another case like the user gets asked to enter some value, or the default is chosen within some time limit. It feels like total overkill to use separate threads and communication for this sort of thing.

Thank you for reviewing my code.

It's easier to make a timeout happen using an async IO framework, e.g. tokio::time::timeout. But you can call that “overkill” too (lots of code under the hood to make that work) — it's just easy to invoke and doesn't require you to express the underlying concurrency yourself.

There are other ways (such as those that tokio uses underneath) but they'll all involve extra work with system calls. You're not missing a trivial std-only way to do what you are looking for.