0

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 {
   |      ^^^
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Brice Lechatellier
  • 653
  • 2
  • 7
  • 9
  • *I want to be able to re-use the controller on different routes* — and do you want the persistent data to be globally shared across all of these routes, or does each route have its own unique persistent data? – Shepmaster May 07 '19 at 01:29
  • I want the persistent data to be globally shared across all of these routes. – Brice Lechatellier May 07 '19 at 05:49

2 Answers2

1

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:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • what does the more complicated solution would look like if I wanted to have a reference to the controller? – Brice Lechatellier May 07 '19 at 06:22
  • 1
    @BriceLechatellier sorry for the ambiguous wording — there is *no* way to implement `Key` for a reference, unless the reference is `'static` (a.k.a. a global), so there is no "complicated" solution. I mean that the provided solution is the simplest working solution, starting from your proposed structure. I've linked to alternate Q&A that show how to have such a global. – Shepmaster May 07 '19 at 19:55
-1

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.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
AdminXVII
  • 1,319
  • 11
  • 22