Search code examples
rustdereferencerust-dieselrust-rocket

How does dereferencing a Rocket #[database] connection work?


I have the following code:

#[database("pg_db")]
struct PgDbConn(diesel::PgConnection);

fn main() {
    rocket::ignite()
        .attach(PgDbConn::fairing())
        .mount("/", routes![find_one, find_all])
        .launch();
}

#[get("/<id>", format = "json")]
fn find_one(conn: PgDbConn, id: i32) -> Result<Json<Person>, NotFound<String>> {
    let one: QueryResult<Person> = person.find(id).first(&*conn);
    ...

I would like to know how my PgDbConn struct ends up as a connection. My question is about the referencing and dereferencing in &*conn. Can someone please explain the mechanism in detail?


Solution

  • Let's have a look at (part of) the implementation of the database attribute macro:

    Ok(quote! {
        //...
        impl ::std::ops::Deref for #guard_type {
            type Target = #conn_type;
    
            #[inline(always)]
            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }
    
        impl ::std::ops::DerefMut for #guard_type {
            #[inline(always)]
            fn deref_mut(&mut self) -> &mut Self::Target {
                &mut self.0
            }
        }
    })
    

    #guard_type is PgDbConn and #conn_type is diesel::PgConnection in your example, so the produced code looks like this:

    impl ::std::ops::Deref for PgDbConn {
        type Target = diesel::PgConnection;
    
        #[inline(always)]
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }
    
    impl ::std::ops::DerefMut for PgDbConn {
        #[inline(always)]
        fn deref_mut(&mut self) -> &mut Self::Target {
            &mut self.0
        }
    }
    

    With Deref and DerefMut, you can implement dereference for your own types, in this case PgDbConn. Now, you can write *conn to get a diesel::PgConnection from your PgDbConn. However, you want a reference to diesel::PgConnection. To get a reference, you have to again reference the dereferenced PgDbConn, so the end result is &*conn.