Borrowing from a Future/Stream in poll/poll_next

This is a contrived example to illustrate the problem I am having:

struct Foo<'a, T> {
    value: T,
    _phantom: PhantomData<&'a ()>,
}

impl<'a, T: 'static> Future for Foo<'a, T> {
    type Output = &'a T;

    fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
        // Error: lifetime may not live long enough
associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
        Poll::Ready(&self.value)
    }
}

Is there any way that poll (Future) or poll_next (Stream) can return a reference to a field within Self? I've tried all sorts of things with pin projection etc. to no avail.

(Note: the "real world" application for this is a stream combinator akin to ReactiveX 'CombineLatest' which returns the last seen values from 2 or more streams. I want to be able to return a shared reference to the last seen values rather than having to clone(). Since the last seen values will be saved on the struct itself between calls to poll_next(), I need to be able to return a reference to afield within the struct.)

If I understand correctly, that's impossible due to the same reason it's impossible for iterator to return references to itself: these references must be usable after the iterator itself is gone (e.g. after collect). For futures, this essentially means that, once it returned Poll::Ready, the runtime is free to drop the future, but the reference is handed out to the caller.

If your future has to return the reference, it must itself contain the reference to the external owner.

4 Likes

When a lifetime is annotated on a struct, then you are saying that the struct must be destroyed before the end of that lifetime. This is incompatible with having references of that lifetime point inside the struct.

3 Likes