Qwark
Qwark

Reputation: 95

What is the correct way to loop while error occurs

I am quite new to Rust, and I'm still trying to be sure I understand principles doing a small project creating a server that uses a TcpStream. The server asks for a client for a code, which has to be 8 characters long. If it's not, it shall ask again for a new code. Here is what I have so far :


fn loby_matcher(stream: &mut TcpStream) -> std::io::Result<(String, usize), >{
    let mut game_code = String::new();
    let mut reader = BufReader::new(stream);
    let len : usize = reader.read_line(&mut game_code)?;
    match len {
        8 => len,
        _ => return Err(Error::new(ErrorKind::Other, "wrong game code")),
    };
    Ok((game_code, len))
}

pub fn create_game_matcher(mut stream: TcpStream) -> std::io::Result<()>{
    println!("Creating a new game! Waiting for the code.");
    let game_code: String;
    let len: usize;
    loop {
        (game_code, len) = match loby_matcher(&mut stream) {
            Ok(game_code) => break (game_code, len),
            Err(e) => {
                stream.write("Wrong code\n".as_bytes());
                (String::new(),0)
            }
        };
    };
    println!("Received : {} size {}", game_code, len);
    // println!("Closing connection now I guess?");
    Ok(())
}

fn start_server(address: &str, port: &str) -> std::io::Result<()>{
    let listener = TcpListener::bind(format!("{}:{}", address, port))?;

    for stream in listener.incoming() {
        // not using ? as we do not want to stop the server for wrong connection
        let stream = stream.unwrap(); 
        thread::spawn(move || {
            create_game_matcher(stream);
        });
    }
    Ok(())
}

The loop asking for a new code when an error occurs seems wrong, but I cannot figure out a way of doing that. Also, I know I should create a custom error in order to be able to make a difference between a wrong code and an I/O error on my TCPstream, which I will do later. What would be the right way of looping while a specific error occurs?

Edit

If you see anything wrong in the code, do not hesitate to tell me how I could improve it.

Upvotes: 5

Views: 3448

Answers (1)

vallentin
vallentin

Reputation: 26197

I'm assuming you're asking how to resolve the issue in create_game_matcher. If so, then you need to move your assignment further out.

To compare the error inside io::Error, can be cumbersome. You can check the kind using e.kind() == ErrorKind::Other. However, the actual error could be anything, and doesn't require implementing PartialEq for &str. The easiest is probably just to do e.to_string() == "wrong game code".

But like you mention, the most idiomatic approach would be to create a your own error type.

pub fn create_game_matcher(mut stream: TcpStream) -> std::io::Result<()> {
    println!("Creating a new game! Waiting for the code.");

    let (game_code, len) = loop {
        match loby_matcher(&mut stream) {
            Ok(game_code) => break game_code,
            // Err(e) if e.kind() == ErrorKind::Other && e.to_string() == "wrong game code" => {
            // or just (for ease of use)
            Err(e) if e.to_string() == "wrong game code" => {
                stream.write("Wrong code\n".as_bytes())?;
            }
            Err(e) => return Err(e),
        };
    };

    println!("Received : {} size {}", game_code, len);
    // println!("Closing connection now I guess?");
    Ok(())
}

Since you want to loop until loby_matcher succeeds, then (String::new(), 0) can be removed. You also forgot to check whether stream.write failed, so I've added an ?.


Alternatively, given that you always break after the assignment, you could also express it like this:

pub fn create_game_matcher(mut stream: TcpStream) -> std::io::Result<()> {
    println!("Creating a new game! Waiting for the code.");

    let game_code: String;
    let len: usize;
    loop {
        match loby_matcher(&mut stream) {
            Ok((game_code_, len_)) => {
                game_code = game_code_;
                len = len_;
                break;
            }
            Err(e) if e.to_string() == "wrong game code" => {
                stream.write("Wrong code\n".as_bytes())?;
            }
            Err(e) => return Err(e),
        };
    }

    println!("Received : {} size {}", game_code, len);
    // println!("Closing connection now I guess?");
    Ok(())
}

Upvotes: 4

Related Questions