1

I'm having troubles with a managed State with Rocket. This state holds a Database connection and a collection of Cursors on that Database. Each one of theses have a reference on the Database.

One of the operations on that state require to create a new cursor on the Database and keep it for later use. Unfortunatly, I am stuck with a lifetime problem. Usually, I have no problem dealing with thoses, but right now, I'm out of ideas...

I have recreated the problem bellow in a short example.

#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use]
extern crate rocket;

use rocket::State;

struct Database;

impl Database {
    fn create_cursor(&self) -> Cursor {
        Cursor { database: self }
    }
}

struct Cursor<'a> {
    database: &'a Database
}

struct Controller<'a> {
    database: Database,
    cursors: Vec<Cursor<'a>>,
}

impl<'a> Controller<'a> {
    fn do_work(&'a mut self) {
        let cursor = self.database.create_cursor();
        self.cursors.push(cursor)
    }
}

fn main() {
    let database = Database;
    let controller = Controller { database, cursors: Vec::new() };

    rocket::ignite()
        .manage(controller)
        .launch();
}

#[get("/")]
pub fn do_work_route(
    mut controller: State<'static, Controller<'static>>
) -> &'static str {
    controller.do_work();
    "Something..."
}
error[E0621]: explicit lifetime required in the type of `__req`
  --> src/main.rs:42:9
   |
40 | #[get("/")]
   | ----------- help: add explicit lifetime `'static` to the type of `__req`: `&'_b rocket::Request<'static>`
41 | pub fn do_work_route(
42 |     mut controller: State<'static, Controller<'static>>
   |         ^^^^^^^^^^ lifetime `'static` required

Any lead would be appreciated. Meanwhile, I'll continue digging.

Thanks a lot!

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366

1 Answers1

1

Your Controller struct as written is self-referential, which is not possible: https://users.rust-lang.org/t/how-to-write-software-without-self-referential-structs/13819

The reason is that when a Controller gets moved, the references to the database in its cursors member would become invalid, because the memory location of its database member changed.

The best way forward is probably to step back and think about a design that is not self-referential. A possible solution is to make the database a static variable, then your cursors could store &'static Database references.

If that fails, the link above mentions the rental crate, but it doesn't seem to be easy to use.

nnnmmm
  • 7,964
  • 4
  • 22
  • 41
  • That's the lead I wanted. I *kinda* knew something was wrong there, but now I have confirmation. Also, by knowing the problem name (Self-Referential Structs), I can do some more research. Thank you. – Benjamin Lemelin Mar 08 '20 at 13:35