Iron persistent state with struct reference

207 views Asked by At

I'm struggling with getting a persistent reference working with Iron, not sure how to set an appropriate lifetime. I want to be able to re-use the controller on different routes.

Example:

use iron::prelude::*;
use iron::typemap::Key;
use persistent::Read;
use router::Router;

pub struct Controller;

pub struct Rest {
    controller: Controller,
}

impl Key for &Controller {
    type Value = Self;
}

impl Rest {
    pub fn run(&self) {
        let router = Router::new();
        let mut chain = Chain::new(router);
        chain.link(Read::<&Controller>::both(&self.controller));
        Iron::new(chain).http(format!("0.0.0.0:1234")).ok();
    }
}

fn main() {
    Rest {
        controller: Controller,
    }
    .run();
}
[dependencies]
iron = "0.6.*"
router = "0.6.*"
persistent = "0.4.0"

Gist of example

error[E0478]: lifetime bound not satisfied
  --> src/main.rs:12:6
   |
12 | impl Key for &Controller {
   |      ^^^
   |
note: lifetime parameter instantiated with the lifetime '_ as defined on the impl at 12:14
  --> src/main.rs:12:14
   |
12 | impl Key for &Controller {
   |              ^
   = note: but lifetime parameter must outlive the static lifetime

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'_` due to conflicting requirements
  --> src/main.rs:12:6
   |
12 | impl Key for &Controller {
   |      ^^^
   |
note: first, the lifetime cannot outlive the lifetime '_ as defined on the impl at 12:14...
  --> src/main.rs:12:14
   |
12 | impl Key for &Controller {
   |              ^
   = note: ...so that the types are compatible:
           expected typemap::Key
              found typemap::Key
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `&Controller` will meet its required lifetime bounds
  --> src/main.rs:12:6
   |
12 | impl Key for &Controller {
   |      ^^^
2

There are 2 answers

2
Shepmaster On BEST ANSWER

As the error message states:

but lifetime parameter must outlive the static lifetime

This is because Key uses Any as a supertrait, which requires 'static:

pub trait Any: 'static {
    fn type_id(&self) -> TypeId;
}

The simplest solution is to implement Key for a value and then give the value to Read::both:

impl Key for Controller {
    type Value = Self;
}

impl Rest {
    pub fn run(self) {
        let router = Router::new();
        let mut chain = Chain::new(router);
        chain.link(Read::<Controller>::both(self.controller));
        Iron::new(chain).http(format!("0.0.0.0:1234")).ok();
    }
}

I want the persistent data to be globally shared across all of these routes

In that case, I'd eschew using the persistent crate completely and just create a singleton:

1
AdminXVII On

You need to add an explicit lifetime bound to your impl block. Otherwise the compiler has no clue on the reference validity of the controller reference.

This should work, though I have not tested it

pub struct Rest {
    controller: controller::Controller,
}

impl<'a> Key for &'a controller::Controller {
    type Value = Self;
}

impl Rest {
    pub fn run(&self) {
        let mut router = Router::new();
        let mut chain = Chain::new(router);
        chain.link(Read::<&controller::Controller>::both(&self.controller));
        Iron::new(chain).http(format!("0.0.0.0:1234"))
    }
}

On a side note, I don't think you need to specify the type on the Read call, the compiler should be able to determine it from the context.