Traits, Generics and Lifetimes

Hello everybody,

I am currently working on the following issue. I have multiple message types which all implement the same trait. This trait has a lifetime specifier since the the pointer, which is passed to one of the defined functions shall be saved by the message, which implements the trait. I prepared a simplified example:

use std::marker::PhantomData;
use std::fmt::Debug;

trait MessageBaseTrait<'a>: Debug {
    fn from_raw(raw: &'a mut [u8]) -> Self where Self: Sized;
    fn to_raw(self: &Self) -> &[u8];
    fn get_len(self: &Self) -> usize;
}
#[derive(Debug)]
struct MessageType1<'a>
{
    raw_data: &'a mut [u8],
}

impl<'a> MessageBaseTrait<'a> for MessageType1<'a>{
    fn from_raw(raw: &'a mut [u8]) -> Self{
        if raw[0] != 0x0C{
            panic!("Wrong Message ID");
        }
        Self{raw_data: raw}
    }
    
    fn to_raw(self: &Self) -> &[u8]{
        self.raw_data
    }
    
    fn get_len(self: &Self) -> usize{
        self.raw_data.len()
    }
}

So far so good. Nothing special and all works well.
No I have a message handler. This message handler will try to send the message, but if that does not work it will save the raw bytes to a buffer and will try again later. Until saving the the buffer everything works fine as well. But when I want to parse the message again from the buffer I get a lifetime issue. Here is the example:

struct MessageHandler<'a, MessageType: MessageBaseTrait<'a>, const FRAME_SIZE: usize>{
    message_buffer: Vec::<[u8; FRAME_SIZE]>,
    phantom: PhantomData<&'a MessageType>,
}

impl<'a, MessageType: MessageBaseTrait<'a>, const FRAME_SIZE: usize> MessageHandler<'a, MessageType, FRAME_SIZE>{

    fn send_message(self: &Self, msg: &MessageType)->bool{
        let message_send_success = false;
        
        if message_send_success{
            println!("{:?}", msg);
            return true
        }
        else{
            return false
        }
    }
    
    pub fn handle_message(self: &mut Self, msg: &MessageType){
        if !self.send_message(msg){
            let mut raw_frame = [0u8; FRAME_SIZE];
            raw_frame[..msg.get_len()].copy_from_slice(msg.to_raw());
            self.message_buffer.push(raw_frame);
        }
    }
    
    pub fn run(self: &mut Self){
        if self.message_buffer.len() > 0{
            let mut raw_bytes =  self.message_buffer.pop().unwrap().clone();
            self.send_message(&MessageType::from_raw(&mut raw_bytes));
        }
    }
}

fn main() {
    let mut buffer1 = [0x0C, 0xad, 0xbe, 0xef];

    let val1 = MessageType1::from_raw(&mut buffer1);
    
    let mut msg_hndr1 = MessageHandler::<MessageType1, 4>{
        message_buffer: vec!(),
        phantom: PhantomData,
    };
        
    msg_hndr1.handle_message(&val1);
    msg_hndr1.run();
}

As you can see I provide the message type as a generic. Since it needs a lifetime I specify it together also for the MessageHandler. And there is the issue. Now, in my run method the data has to exist as long as the MessageHandler but I don't need that. I just can not figure out how I provide a generic type during the object definition without providing the lifetime directly, so that the lifetime can be assessed when the data is used.

I hope I could make my issue clear. Here is also a rust playground example: Rust Playground
In the playgroudn example I already also tried using for <'a> MessageBaseTrait<'a> but this has different issues.

Does anyone have a good tip on how to solve this issue? Obviously I dont understand lifetimes good enough.... I am so close to removing the lifetimes completely but think it should be possible to provide a generic type with a lifetime without this type having to have the same lifetime as the struct it is passed to.

Thanks for the help!

When you clone the value on line 83, it creates a value that will only lives for the scope of the function, so shorter than the lifetime of the object. What you want instead is to have a reference to the memory of the object, and you can use last_mut for this.
But then you will have to pop the value after you send the message.
I'm not 100% sure it complies with your objectives, but at least it compiles :smiley:

Here's one way forward.

I created this trait to represent "a family of some message type of any lifetime":

trait MessageConstructor {
    type Message<'a>: MessageBaseTrait<'a>;
    fn from_raw(raw: &mut [u8]) -> Self::Message<'_> {
        Self::Message::from_raw(raw)
    }
}

Every MessageTypeN also gets a marker type that implements this trait:

enum MessageConstructor1 {}
impl MessageConstructor for MessageConstructor1 {
    type Message<'a> = MessageType1<'a>;
}

The handler is then parameterized by the constructor type instead.

struct MessageHandler<Constructor, const FRAME_SIZE: usize>{
    message_buffer: Vec::<[u8; FRAME_SIZE]>,
    phantom: PhantomData<Constructor>,
}

impl<Constructor: MessageConstructor, const FRAME_SIZE: usize> MessageHandler<Constructor, FRAME_SIZE>{
    //                                vvvvvvvvvvvvvvvvvvvvvvvvv
    fn send_message(self: &Self, msg: &Constructor::Message<'_>)->bool{
        ...
    }

    pub fn run(self: &mut Self){
        if self.message_buffer.len() > 0{
            let mut raw_bytes =  self.message_buffer.pop().unwrap().clone();
            self.send_message(&Constructor::from_raw(&mut raw_bytes));
            //                 ^^^^^^^^^^^
        }
    }
}

Having written that up, it also occurs to me that the only part of MessageHandler<C, _> that is specific to C in this code is run. send_message and handle_message could take any generic M: MessageBaseTrait<'m> I believe (but I didn't try it).

Thank you for your answer.

I tried this here: Rust Playground

The issue that arises is that I cannot burrow mutable self more than once.

pub fn run(self: &'a mut Self){
        if self.message_buffer.len() > 0{
            let raw_bytes =  self.message_buffer.last_mut().unwrap(); //<<-- Here
            self.send_message(&MessageType::from_raw(raw_bytes)); //<<-- And Here
        }
    }

I thought about changing the send_message function to not use self and be used as Self::send_message but in the actual code I need to update message with some variables which are saved in self (e.g. a sequence number).

Thank you for your answer!

This works great! I will try this out in my actual code and mark this as the correct answer when I am done!

Regarding your comment at the end. I actually had it this way but since the same message has to be used though out the code, I simplified it.

I prepared a playground here: Rust Playground

The problem here is that this does not fix the lifetime issue since that arises only in the run function.

I honestly still think that it should be possible to provide generic traits which have lifetimes without having to provide the lifetime at the struct definition, but rather defining the lifetime when the trait is used. There might be simply a good reason why this is not allowed, which I am currently not thinking of, though. Something like this:

// This code is just an example of how I think it could/should work and is not a working solution to the problem.
struct MessageHandler<MessageType: MessageBaseTrait, const FRAME_SIZE: usize>{
    message_buffer: Vec::<[u8; FRAME_SIZE]>,
    phantom: PhantomData<&MessageType>,
}

impl<MessageType: MessageBaseTrait, const FRAME_SIZE: usize> MessageHandler<MessageType, FRAME_SIZE>{
  //...
    pub fn run<'m>(self: &mut Self){
        if self.message_buffer.len() > 0{
            let mut raw_bytes =  self.message_buffer.pop().unwrap().clone();
            self.send_message(&MessageType::<'m>::from_raw(&mut raw_bytes));
        }
    }
}