rustiron

Iron::new()::http() intercepts stdin


I'am trying to implement educational client-server application using Rust and Iron. I've encountered the behaviour that I can't understand. Here is the code:

fn main() {
    Iron::new(hello_world).http("localhost:3000").unwrap();

    let mut input = String::new();
    io::stdin().read_line(&mut input)
        .expect("Failed to read line");

    println!("You entered: {}", &input)
}


fn hello_world(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Hello World!")))
}

When I run it and try to enter something from the keyboard, the line You entered: Some text is not appearing.

But after I changed this line:

Iron::new(hello_world).http("localhost:3000").unwrap();

With this:

let listener = Iron::new(hello_world).http("localhost:3000").unwrap();

I got string You entered: Some text on my console. So it seems to work. But now I have warning about unused variable. This behaviour is confusing.

Can anyone explain why this actually happens?


Solution

  • In the first version of your code, the first line will block waiting for incoming connections. This is because of the following:

    1. Iron::new(hello_world).http("localhost:3000").unwrap() produces an object of type Listening, which will start listening to http requests in a separate thread.
    2. The Listening struct implements the Drop trait, i.e. any objects of type Listening will run a drop function when they fall out of scope. Said drop function will join the listening thread, blocking further execution of your program.
    3. By not assigning the Listening object to a variable, it falls out of scope immediately. This means that the drop function is run right after the object's creation.

    Alternative explanation in code

    The first version of your program:

    fn main() {
        Iron::new(hello_world).http("localhost:3000").unwrap();
        // The listening thread is joined here, so the program blocks
        // The instructions below will never be executed
    
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .expect("Failed to read line");
    
        println!("You entered: {}", &input)
    }
    

    The results of introducing a variable:

    fn main() {
        let listener = Iron::new(hello_world).http("localhost:3000").unwrap();
    
        let mut input = String::new();
        io::stdin().read_line(&mut input)
            .expect("Failed to read line");
    
        println!("You entered: {}", &input)
    
        // The listening thread is joined here, so the program blocks
        // As you can see, the program will not exit
    }