Help me, Rustaceans, you're my only hope.
I'm using a couple of crates: one provides a session and listener concept, the other provides an event loop via a client-implemented perform()
trait. I'm trying to implement a simple perform()
which creates a listener during an early call, and uses that listener for all subsequent calls, but am having trouble reconciling the lifetimes of the objects involved. Here's the stripped-down version of the crates and my own code:
// ----- crate 1
struct Session;
impl Session {
pub fn listen(&mut self) -> Listener {
return Listener {session: self};
}
}
struct Listener<'session> {
session: &'session mut Session,
// other useful things
}
// ----- crate 2
trait Perform {
fn perform(&mut self);
}
struct Looper;
impl Looper {
pub fn main_loop<P: Perform>(&mut self, p: P) {
// calls p.perform() a bunch of times
}
}
// ----- self
struct MyPerform<'session> {
session: Session,
listener: Option<Listener<'session>>,
}
impl<'session> Perform for MyPerform<'session> {
fn perform(&mut self) {
match self.listener {
None => {
self.listener = Some(self.session.listen());
// the problem is here: ^~~~~~~~
}
Some(e) => {
// use self.listener, I no longer care about self.session
}
}
}
}
fn main() {
let session = Session;
let perform = MyPerform {session: session, listener: None};
let mut looper = Looper;
looper.main_loop(perform);
}
When I try to compile this (rustc 1.5.0), I get 43:43 43:51 error: cannot infer an appropriate lifetime for autoref due to conflicting requirements
. I think I understand what the problem is: the returned listener must simultaneously have (elided) lifetime 'a
and 'session
, which don't overlap in any predictable way. Maybe?
It seems like this should be possible, though: my struct has exclusive access to both session
and listener
, so it should be able to guarantee proper access to them. But every attempt to get this to work fails at compile time (which, I guess, is better than failing at runtime).
So, is what I'm trying to do possible, and if so, what's the best way? I'd prefer to use safe code, and not edit imported crates. I'm a Rust noob, so feel free to critique my design, if that's my problem.