Ah. I didn't understand that "self" in a trait was automatically "dyn". That makes sense, though; that's the whole point of traits.
Anyway, here's a short version of what I ended up with, now including all the lifetime annotations. What's going on here is un-marshalling structs from a big slice of bytes, as a library. So different users need to call into this message decoder with a slice of bytes b, and get a decoded message back as a tree of temporary structs. Hence the callback. Some decoded structs have references to the slice of bytes b, because it contains blobs that need to be passed back to the callback and shouldn't be copied unnecessarily. The goal is to un-marshall without heap allocation.
Comments?
//
// Trait practice
//
/// DecoderUser is the common trait for all users of the decoder system.
/// Callers must implement DecoderUser for their type so that they
/// will get a callback.
///
trait DecoderUser {
// Call this to decode.
fn decode(&mut self, msgnum: u32, b: &[u8], offset: &mut usize) -> Result<(), &'static str> {
decodeswitch(self, msgnum, b, offset) // fan out on msgnum
}
// Be called back via this.
fn decodedresult(&mut self, ms: &AllMessages) -> Result<(), &'static str>; // The callback
}
pub struct TestMessage{ test0: u32 }
pub struct PacketAck<'a>{ pub name: &'a [u8] }
pub enum AllMessages<'a> {
MsgTestMessage(TestMessage),
MsgPacketAck(PacketAck<'a>)
}
/// Switch which calls all decoders based on message number.
fn decodeswitch<'a,'b>(decoderuser: &mut (impl DecoderUser + ?Sized + 'b), msgnum: u32, b: &'a[u8], offset: &mut usize) -> Result<(), &'static str> {
match msgnum { // fan out on message number and call appropriate decoder.
0xffff0001 => decode_test_message(decoderuser, b, offset),
0xfffffffb => decode_packet_ack(decoderuser, b, offset),
_ => Err("Unimplemented msg number")
}
}
fn decode_test_message<'a>(decoderuser: &mut (impl DecoderUser + ?Sized), b: &'a [u8], offset: &mut usize) -> Result<(), &'static str> {
let result = AllMessages::MsgTestMessage(TestMessage{test0: 1} );
*offset = *offset + 1;
decoderuser.decodedresult(&result) // do callback, return its result
}
fn decode_packet_ack<'a>(decoderuser: &mut (impl DecoderUser + ?Sized), b: &'a [u8], offset: &mut usize) -> Result<(), &'static str> {
let result = AllMessages::MsgPacketAck(PacketAck{name: &b});
*offset = *offset + 1;
decoderuser.decodedresult(&result) // do callback, return its result
}
struct PacketLogDecoder {}
// Implement trait Message Decoder for Packet Log Decoder to allow callback.
impl<'a> DecoderUser for PacketLogDecoder {
fn decodedresult(&mut self, ms: &AllMessages) -> Result<(), &'static str> {
println!("In DecoderUser for PacketLogDecoder");
Ok(())
}
}
#[test]
fn testdecoder()
{
let mut testobj1 = PacketLogDecoder{};
let testdata = [1u8, 2u8]; // junk test data
let msgnum = 0xffff0001;
let mut offset: usize = 0;
let result = testobj1.decode(msgnum, &testdata, &mut offset);
}