I'm doing an exercise about lifetimes and I thought of a trait Decoder
. Here's a struct for simplicity, but let's say I want to design a trait for video decoders. Video decoders can either
- copy the decoded data into a
'static
packet - provide a reference to the data
- provide a pointer to the data in GPU, that can be passed to OpenGL, no frame is copied to RAM ever
I think the list above covers all possible cases for video decoders, which is important for a trait.
Here's my attempt
use std::sync::Arc;
/// Here would go: `fn get_data(&self) -> &[u8]`, `fn get_width(&self) -> usize`, etc
pub trait DecodedPacket<'a> {}
pub struct ConcretePacket {}
pub struct SlicePacket<'a>{
pub slice: &'a [u8]
}
impl<'a> DecodedPacket<'a> for ConcretePacket {}
impl<'a> DecodedPacket<'a> for SlicePacket<'a> {}
pub struct Decoder<'c> {
pub slice: &'c [u8]
}
impl<'c> Decoder<'c> {
/// This can return packets that either contain references
pub fn receive_ref(
&self,
on_packet: Arc<dyn for<'a, 'b> Fn(Box<dyn DecodedPacket<'a>>)>,
) {
// case 1: slice lifetime is made inside this function
let slice:&[u8] = &[1,2,3];
let packet: Box<dyn DecodedPacket<'_>> = Box::new(SlicePacket{slice: slice});
on_packet(packet);
// case 2: slice lifetime is from outside the function
let packet: Box<dyn DecodedPacket<'_>> = Box::new(SlicePacket{slice: slice});
on_packet(packet);
}
/// This can return packets that are created without any references
/// Advantages: I can move to another thread, and I can downcast
/// Why downcasting is needed? Well, there are packets that hold no
/// data but a pointer to data on GPU, but also packets that might need very
/// specific treatment because they are very different
pub fn receive(
&self,
on_packet: Arc<dyn Fn(Box<dyn DecodedPacket<'static>>)>,
) {
let packet: Box<dyn DecodedPacket<'_>> = Box::new(ConcretePacket{});
on_packet(packet);
}
}
fn main() {
let slice = &[1,2,3];
let decoder = Decoder{
slice: slice
};
let on_packet = Arc::new(|_packet: Box<dyn DecodedPacket<'static>>|{
println!("packet received");
});
decoder.receive(on_packet);
let on_packet = Arc::new(|_packet: Box<dyn DecodedPacket>|{
println!("packet received");
});
decoder.receive_ref(on_packet);
}
I tried to conciliate both the 'static
case and reference case in the same function but I couldn't. I couldn't make the caller determine if the data should be static or reference. Do you guys think I did exaggerate? Or is this a good trait?