viraptor
viraptor

Reputation: 34145

Trait type and lifetime issues

I'm trying to write an Iron plugin middleware, but I'm running into an issue when trying to define a typemap key:

The minimal example with simple type works without issues:

pub struct Database;
impl Key for Database {
    type Value = isize;
}

But as soon as lifetime is involved, I cannot compile the library:

pub struct Database<'a> {
    pool: &'a Arc<Pool<PostgresConnectionManager>>
}

impl<'a> Key for Database<'a> {
    type Value = PooledConnection<'a, PostgresConnectionManager>;
}

What's happening here? I get the errors:

src/lib.rs:33:1: 35:2 note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 33:0...
src/lib.rs:33 impl<'a> Key for Database<'a> {
src/lib.rs:34     type Value = PooledConnection<'a, PostgresConnectionManager>;
src/lib.rs:35 }
src/lib.rs:33:1: 35:2 note: ...so that trait type parameters matches those specified on the impl (expected `typemap::Key`, found `typemap::Key`)
src/lib.rs:33 impl<'a> Key for Database<'a> {
src/lib.rs:34     type Value = PooledConnection<'a, PostgresConnectionManager>;
src/lib.rs:35 }
note: but, the lifetime must be valid for the static lifetime...
src/lib.rs:33:1: 35:2 note: ...so that the type `r2d2::PooledConnection<'_, r2d2_postgres::PostgresConnectionManager>` will meet its required lifetime bounds
src/lib.rs:33 impl<'a> Key for Database<'a> {
src/lib.rs:34     type Value = PooledConnection<'a, PostgresConnectionManager>;
src/lib.rs:35 }

But that doesn't make sense to me - the PooledConnection cannot outlive the manager and the Arc<Pool<...Manager>> is given that lifetime to ensure this. What am I missing here?

(documentation for Pool)

Upvotes: 1

Views: 365

Answers (1)

Vladimir Matveev
Vladimir Matveev

Reputation: 127751

Here is the definition of Key:

pub trait Key: Any {
    type Value: Any;
}

That is, it extends trait Any:

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

This means that any type which implements Key must also implement Any, and any Value associated type instantiation must also implement Any. However, Any is only defined for types which are 'static, that is, which do not contain non-static references.

Types which are parameterized with lifetime parameters, like your Database, usually do contain such references (and indeed, your type contains &'a field), so they are not 'static and so they cannot implement Any. Therefore such types can't implement Key. And this is in fact what your error is about, even if this is not really obvious:

note: but, the lifetime must be valid for the static lifetime...

Anyway, the core reason of this error is that Rust currently does not support reflection with Any for non-static types - as far as I remember, there were some kind of soundness issues around lifetimes here. So currently your only option is to refactor your program so you won't need to store non-'static types in TypeMap.

Upvotes: 3

Related Questions