How to reference to the part of self?

Let we have the server that processes various messages. The code is

struct Server {
    clients: HashMap<u32, ClientData>
}

impl Server {
    fn handle(client_id: u32, msg: Message) {
        // Check that client exists
        let mut client = &mut self.clients.get_mut(&id).unwrap_or_else(||{
            panic!("Non-existing client id: {}!", id);
        });

        match msg {
            msg1 => {
                client.info = "got msg 1".into();
                // -- snip -- (inform other clients about new message)
            },
        }
    }
}

Since there are a lot of message types, I want to extract type processing into a function:

fn handle(&mut self, client_id: u32, msg: Message) {
    // Check that client exists
    let mut client = &mut self.clients.get_mut(&id).unwrap_or_else(||{
        panic!("Non-existing client id: {}!", id);
    });

    match msg {
        msg1 => self.handle_msg1(&mut client)
    }
}

fn handle_msg1(&self, client: mut& ClientData) {
    client.info = "got msg 1".into();
    // -- snip -- (inform other clients about new message)
}

However I got borrow checker error since I make reference to self twice: when refer to client and when call using "self.".

How to make this code works?

As you understand, I do not want to duplicate client check in every handling function. I also do not want to use unwrap() in production code. How can I modify the code above to make this code good?

  1. Refactor your code to move the method and all dependencies to a new type and call self.new_type.method(...) instead of self.method().
  2. Move the code to a function instead of a method and pass all the variables needed instead of using self.

See also:

To get the best help, I encourage you to provide valid Rust code. Ideally, provide a minimal, reproducible example that demonstrates your problem. People are more likely to fix your code for you in that case.

2 Likes

Thank you for the answer and references - they look almost as my case!

However, I guess variant 1 is impossible because I refer to the part of HashMap - I cannot separate one entry from the others.

Variant 2 fails for the same reason. When server get a message from some client it usually must inform other clients or change their state. So I need mutable reference to HashMap with clients and so I cannot reference specific client.

I guess I'll pass u32 id and use plain unwrap() until some genius idea will come.

P.S. This code will be online game server. So client's message will be like FireTo(target). And, if client successfully landed a hit, I need to increase its kill counter and to reduce target's hit points.

You might be interested in [game programming pattern] (https://gameprogrammingpatterns.com/), especially the observer or event queue chapter.

1 Like