Lifetime issue when assigning Box::pin(future) to struct field

Greetings everyone,

I stumbled upon a lifetime issue that I can't reason about.
I defined an enum to implement Hyper's Body trait like this:

type SendFuture = Box<dyn Future<Output = Result<(), SendError<(RangeType, ChunkSender)>>> + Send>;
pub enum ProxyBody {
    Cached {
        hook_sender: HookSender,
        progress: u64,
        range: (u64, u64),
        step: u64,
        chunk_receiver: Option<ChunkReceiver>,
        send_task: Option<std::pin::Pin<SendFuture>>,
    },
    Text {
        message: String,
        sent: bool,
    },
}
pub type ChunkSender = tokio::sync::oneshot::Sender<CacheChunk>;
pub type ChunkReceiver = tokio::sync::oneshot::Receiver<CacheChunk>;
pub type HookSender = tokio::sync::mpsc::Sender<(RangeType, ChunkSender)>;
pub type HookReceiver = tokio::sync::mpsc::Receiver<(RangeType, ChunkSender)>;

to call the send() function of tokio::sync::mpsc::Sender in the poll_frame() trait function, I need to store the future, hence the send_task Option field. But I'm getting "lifetime may not live long enough", when assigning the boxed future to *send_task. It says the &mut Self reference as in self: std::pin::Pin<&mut Self> doesn't live long enough:


fn poll_frame(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>,) 
        -> std::task::Poll<Option<Result<hyper::body::Frame<Self::Data>, Self::Error>>> {
    match self.get_mut() {
        ProxyBody::Text { message, sent } => {
            let msg_bytes = Bytes::copy_from_slice(message.as_bytes());
            let frame = hyper::body::Frame::data(msg_bytes);
            *sent = true;
            Poll::Ready(Some(Ok(frame)))
        }
        ProxyBody::Cached {
            hook_sender,
            progress,
            range,
            step,
            send_task,
            chunk_receiver,
        } => {
            // some other code omitted
            let start = range.0 + *progress;
            let end = if range.1 < range.0 + *progress + *step {
                range.1
            } else {
                range.0 + *progress + *step
            };
            let range_req = RangeType::Body { start, end };
            let (sender, mut receiver) = tokio::sync::oneshot::channel();
            let task = hook_sender.send((range_req, sender));
            let mut pin_task = Box::pin(task);
            *send_task = Some(pin_task);
            Poll::Pending
        } 
    }
}

I'd think that the boxed future is 'static, and the send_task would take ownership of the future after assigning to it, and if the body doesn't live long enough and is dropped, then the future would be dropped too. I have no idea what the problem is here.

It's not. async fns such as this capture all input lifetimes, so task is not 'static.

(Excuse the brevity; on mobile.)

Thank you. You are right, it's the hook_sender reference that belongs to part of the future and is not 'static. But it took me days to realize hook_sender itself is also one of the arguments to send(), it just hid in plain sight from me. The following finally compiles:

let hook_sender = hook_sender.clone();
let send_future = async move { hook_sender.send((range_req, sender)).await };
let send_future = Box::pin(send_future);
*send_task = Some(send_future);

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.