How to pass a Vec of objects to closure?

Hello everyone, I am new to Rust and I've been following the Rust Book practicing for a while now.
After that I've decided that as training I would create a small HTTP web server inspired on Middleware approach same as Express.js (I am mostly a Node.js developer).

So in the same book there is a little tutorial on creating a Multithreaded Web Server, so I have been following that, and started to implement the middleware functionality, for this, I have this struct for my handlers:

pub struct Handler {
    method: RequestMethods,
    path: String,
    handler: Box<dyn FnOnce()>,
}

RequestMethods in this case is just an enum (GET, POST, PUT,...), and the handler is the closure that I want to execute when we are on a given path and with a given method
All of these handlers live inside a Vec which is inside a server struct:

pub struct Server {
    pub host: String,
    pub port: u16,
    pool_size: usize,
    handlers: Vec<Handler>,
}

Inside the Server struct I have a listen function which basically creates threads for every request, to a maximum amount of N threads:

pub fn listen<F>(&self, f: F) where F: FnOnce(&String) {
        let addr = &format!("{}{}{}", self.host, ":", self.port);
        let listener = TcpListener::bind(addr).unwrap();
        let pool = ThreadPool::new(self.pool_size);
        f(&addr);

        let handlers = Arc::new(Mutex::new(self.handlers));
        for stream in listener.incoming() {
            let clone = handlers.clone();
            pool.execute(|| { // (dyn std::ops::FnOnce() + 'static) cannot be sent between threads safely
                handler(stream.unwrap());
                println!("{:?}", handlers.lock().unwrap().len());
            });
        }
    }

Problem is that inside of the pool.execute closure I need to have access to the handlers, so I can call them depending on the condition (my handler function is not part of the server class), how can I do that? I tried to create an Arc<Mutex<self.handlers>> but It wont compile giving me the error

(dyn std::ops::FnOnce() + 'static) cannot be sent between threads safely

This is the pool.execute function:

pub fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
        let job = Box::new(f);
        self.sender.send(Message::NewJob(job)).unwrap();
}

I have tried with other datatypes like simple numbers or booleans and I can pass them to the closure, but I cannot do it if it is a Vec. How can I do this?

Thanks

Try adding the Send bound to your handler

handler: Box<dyn FnOnce() + Send>,

Thanks for the reply, now there is a different error

cannot move out of `self.handlers` which is behind a shared reference
move occurs because `self.handlers` has type `std::vec::Vec<server::Handler>`, which does not implement the `Copy` traitrustc(E0507)

and if I try to pass a reference to the Mutex to be &self.handlers I get the same original error

You need to change struct Server to hold Arc<Mutex<Vec<Handler>>>, or perhaps Mutex<Vec<Arc<Handler>>> if you'd like to pass individual handlers to threads etc.

Your listen method takes a temporary shared borrow of &self, but passing self.handlers (without &) means taking exclusive ownership of handlers. You can't take ownership of something you've borrowed - that's stealing!

Mutex::new(self.handlers) is trying to remove handlers from self struct, and this means that self has to be destroyed in the process, because you can't leave a handlers-shaped "hole" in it. A struct can't exist without one of its fields. Destroying self is not what you want, so make handlers themselves shareable from where they live in the struct.

1 Like

looking at this again, I also realize FnOnce is probably not the trait you want for a multithreaded webserver handler, as it can only be called once. You probably want dyn Fn + Send + Sync in this case, which can be called multiple times; and even simultaneously from multiple threads.

If your Vec of handlers is generated once at startup and not modified later, and uses Fn functions, you can just put it in an Arc directly (Arc<Vec<_>>) to share, (outside of any Mutex), as you will only ever need immutable/shared access to it.

1 Like

I guess I will go with handlers being Arc<Mutex<Vec<Handler>>> as kornel mentioned
I've also changed handlers to be Fn.

But I am still unable to access these handlers Vec inside the closure, what I understand about Mutex is that to get the value I can do like:
let mut handlers = *self.handlers.lock().unwrap()

But in this case I am getting new errors such as:
self has an anonymous lifetime '_ but it needs to satisfy a 'static lifetime requirement

I am so confused, but enjoying Rust anyways :slight_smile:

I've figured it out, turns out I had to clone the handlers twice, once for the loop and the other for the closure, so the final code looks like this

let handlers: Arc<Mutex<Vec<Handler>>> = Arc::clone(&self.handlers);
for stream in listener.incoming() {
       let clone = Arc::clone(&handlers);
       pool.execute(move || {
           handler(stream.unwrap(), clone);
       });
}
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.