mongodbrustiron

Trouble to pass Iron handlers with closure in the router declaration


I'm trying to declare my routes with closures:

use mongodb::Client;

pub fn get_user_routes(client: Client) -> Router {
    let controller = controller::UserController::new(client);
    let handler = handlers::UserHandler::new(controller);

    router!(
         index:  get    "/"    => move |r: &mut Request| handler.index(r),
         show:   get    "/:id" => move |r: &mut Request| handler.show(r),
    )
}

I get this error and I can't implement the Copy trait for my UserController because the mongodb::Client doesn't implement it (it's an Arc).

error[E0382]: capture of moved value: `handler`
      --> src/api/users/mod.rs:17:57
       |
    16 |         index:  get    "/"    => move |r: &mut Request| handler.index(r),
       |                                  ---------------------- value moved (into closure) here
    17 |         show:   get    "/:id" => move |r: &mut Request| handler.show(r),
       |                                                         ^^^^^^^ value captured here after move
       |
       = note: move occurs because `handler` has type `api::users::handlers::UserHandler`, which does not implement the `Copy` trait

My UserHandler just has a UserController and the UserController, a mongodb::Client.


Solution

  • The router get method takes a handler by value. In Rust, passing by value implies giving up ownership.

    By definition, you cannot give up ownership of something twice: it's no longer yours after you gave it up the first time! The only exception to the rule is Copy types, but those are restricted to things like integers and non-mutating references (and references are out because Handler: 'static).

    Thus, you need to call .clone() on the handler to be passed. Every time.

    A very simple way is to use a block-expression:

    let h  = handler;
    router!(
        index: get "/"    => { let h = h.clone(); move |r: &mut Request| h.index(r) },
        show:  get "/:id" => { let h = h.clone(); move |r: &mut Request| h.show(r) },
    )
    

    this way, you do not have to declare all the clones beforehand.