I managed yet again to run into a lifetime issue that I seem to be unable to solve on my own.
I have this trait
pub trait MiddlewareHandler: Clone {
fn invoke (&self, req: &Request, res: &mut Response) -> bool {
true
}
// we need this because otherwise clone() would be ambiguous
fn clone_box(&self) -> Box<MiddlewareHandler> {
box self.clone() as Box<MiddlewareHandler>
}
}
impl MiddlewareHandler for fn (req: &Request, res: &mut Response) -> bool {
fn invoke(&self, req: &Request, res: &mut Response) -> bool{
(*self).invoke(req, res)
}
}
impl Clone for Box<MiddlewareHandler> {
fn clone(&self) -> Box<MiddlewareHandler> {
self.clone_box()
}
}
That I implement for fn (req: &Request, res: &mut Response) -> bool
in order to be able to use accept lightweight functions and more heavy weight MiddlewareHandler
implementors at the same time.
I store them as Vec<Box<MiddlewareHandler>>
pub struct Middleware {
handlers: Vec<Box<MiddlewareHandler>>
}
Now, the problem is, the compiler is yelling at me right here:
pub fn add<T: MiddlewareHandler> (&mut self, handler: T) {
self.handlers.push(box handler);
}
It says:
error: value may contain references; add `'static` bound to `T`
self.handlers.push(box handler);
The implementation should be pretty similar to the one used here:
https://github.com/iron/iron/blob/master/src/chain/stackchain.rs#L67
However, I seem to be unable to see the difference :-/
If anyone would like to give me a hand, I pushed the code to github into the static
branch:
The problem here is that, in order to safely create a boxed trait object, the original object cannot have any lifetime parameters (besides static
), or the object itself also needs to respect that lifetime, which isn't possible in general. To fix it:
pub fn add<T: MiddlewareHandler + 'static> (&mut self, handler: T) {
self.handlers.push(box handler);
}
Reads a bit weird, but it's saying "T
needs to implement MiddlewareHandler
and it cannot contain any references that do not have the static
lifetime". This only works for static
.