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!