1

I am trying to program an application that listens for requests on a socket and then adds them onto a queue to be processed. Part of my code goes as follows:

pub struct Middleware {
    listener: TcpListener,
    queue: Vec<String>,
    servers: Vec<String>,
}

impl Middleware {
    pub fn run(&mut self) {
        for stream in self.listener.incoming() {
            let mut stream = stream.unwrap();
            let mut buffer = vec![0u8; 512];
            stream.read(&mut buffer).unwrap();
            self.queue.push(String::from_utf8(buffer).unwrap());
        }
    }
}

Yet if I try to abstract some of the code in run() into a function (literally just copy/paste):

impl Middleware {
    pub fn run(&mut self) {
        for stream in self.listener.incoming() {
            let mut stream = stream.unwrap();
            self.handle_client(stream);
        }
    }

    fn handle_client(&mut self, mut stream: TcpStream) {
        let mut buffer = vec![0u8; 512];
        stream.read(&mut buffer).unwrap();
        self.queue.push(String::from_utf8(buffer).unwrap());
    }
}

I get the following error message:

cannot borrow `*self` as mutable because `self.listener` is also borrowed as immutable
--> src/lib.rs:21:13
   |
19 |         for stream in self.listener.incoming() {
   |                       ------------- immutable borrow occurs here
20 |             let mut stream = stream.unwrap();
21 |             self.handle_client(stream);
   |             ^^^^ mutable borrow occurs here
22 |         }
   |         - immutable borrow ends here

From what I understand, self.listener.incoming() actually borrows not only the listener "field" but the entire struct. And then, as we cannot have any mutable borrow simultaneously with an immutable borrow, the compiler complains. However, I have to make self mutable in handle_client(), otherwise I cannot push anything on its queue.

I have been thinking about how to structure the code differently to overcome this problem but can't seem to find a solution without changing my Middleware struct (as in removing some fields, etc).

Is it possible to somehow structure the code to use a function (like in my second code snippet)?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
j_beck
  • 64
  • 1
  • 5
  • On the contrary; it [forces you towards adding *more* abstraction](https://play.integer32.com/?gist=5b91833c40ae264927688af0d0ce3efe&version=stable). – Shepmaster Oct 23 '17 at 22:27
  • @Shepmaster So if I understand it correctly, in your code `handle_client()` borrows `self.queue` which is not a problem vs borrowing just `self` which was the problem in my code (because it is the "parent object" of borrowed `self.listener`? ) ? – j_beck Oct 23 '17 at 22:53
  • As discussed in the linked duplicates, Rust can only tell that you are performing disjoint borrows of a struct's member inside of a *single* method. The `run` method now sees that you are borrowing `self.listener` and `self.queue` and that those are disjoint — the call to `handle_client` cannot possibly modify `self.listener`. – Shepmaster Oct 24 '17 at 01:43
  • Ok I think I got it thank you so much – j_beck Oct 24 '17 at 07:10

0 Answers0