Variable does not live long enough to send over channel

1.1k Views Asked by At

I am trying to send a message containing Cow<[u8]> over a channel. However, the lifetime rules do not allow me to pass it over.

use std::borrow::Cow;
use std::sync::mpsc;

#[derive(Debug, Default, PartialEq, Clone)]
pub struct PlayerAction<'a> {
    pub data: Cow<'a, [u8]>,
}

#[derive(Debug, Clone)]
pub enum NetworkMessage<'a> {
    PlayerActionMessage(PlayerAction<'a>),
}

pub struct ConnectionsManager<'a> {
    channel: mpsc::Sender<NetworkMessage<'a>>,
}

pub struct MessageHandler<'a> {
    pub connection_manager: ConnectionsManager<'a>,
}

fn read_message<'a>(bytes: &'a Vec<u8>) -> NetworkMessage {
    NetworkMessage::PlayerActionMessage(PlayerAction {
        data: Cow::Borrowed(&bytes),
    })
}

impl<'a> MessageHandler<'a> {
    fn on_message(&mut self, msg: Vec<u8>) {
        let readm = read_message(&msg);
        self.connection_manager.channel.send(readm);
    }
}

fn main() {}

Playground

error[E0597]: `msg` does not live long enough
  --> src/main.rs:30:35
   |
30 |         let readm = read_message(&msg);
   |                                   ^^^ borrowed value does not live long enough
31 |         self.connection_manager.channel.send(readm);
32 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 28:1...
  --> src/main.rs:28:1
   |
28 | impl<'a> MessageHandler<'a> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^

MessageHandler outlives Vec<u8>, but I have no idea how to pass it any other way.

Is there any way to pass Vec<u8> so that it can live longer than the on_message function?

1

There are 1 best solutions below

7
On BEST ANSWER

Here's a one-line change you can make to make this code correct:

fn on_message(&mut self, msg: &'a [u8])

Instead of taking a Vec<u8> by value, take a reference to a slice that is already guaranteed to live at least as long as 'a. This makes it the caller's responsibility to ensure that whatever you pass to on_message will live long enough to be sent over the channel.


But maybe you can't do that. Either the caller will have the same problem, and you can't push it up any farther, or the Vec<u8> is a required part of on_message's signature. If that's the case, you will have to change read_message. Here's one possibility:

fn read_message<'b>(bytes: Vec<u8>) -> NetworkMessage<'b> {
    NetworkMessage::PlayerActionMessage(PlayerAction {
        data: Cow::Owned(bytes),
    })
}

impl<'a> MessageHandler<'a> {
    fn on_message(&mut self, msg: Vec<u8>) {
        let readm = read_message(msg);
        self.connection_manager.channel.send(readm);
    }
}

Moving msg into read_message leaves the compiler free to pick any lifetime it wants for 'b. In on_message it can just pick 'a to make the code compile. The disadvantage of this approach is that you may have to .clone() the Vec if you need to use it again after sending it down the channel.