Variable length ID, e.g. 1 bytes and sometimes 3 bytes
I'm working on Bluetooth packets, easiest way to parse would be to match the packets with variable length IDs such as:
- LeMeta packets with 3 bytes (the id, length and sub id)
- Normal packets with 2 bytes (the id and length)
However I can't figure out how to make such a ID type that could be used for this.
I've tried &'static [u8] but it complains:
no function or associated item named
from_reader_with_ctxfound for reference&'static [u8]in the current scope function or associated item not found in&[u8]
use deku::prelude::*;
// This fails because DekuRead is not implemented for `&'static [u8]`
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite)]
#[deku(id_type = "&'static [u8]")]
pub enum HciEventMsg {
#[deku(id = "&[0x03, 0x13, 0x01]")]
LeConnectionComplete {
status: HciStatus,
connection_handle: u16,
role: Role,
peer_address_type: AddressType,
peer_address: [u8; 6],
connection_interval: u16,
peripheral_latency: u16,
supervision_timeout: u16,
central_clock_accuracy: ClockAccuracy,
},
#[deku(id = "&[0x0E, 0x04]")]
CommandComplete {
num_hci_command_packets: u8,
command_opcode: u16,
status: HciStatus,
},
#[deku(id = "&[0x0F, 0x04]")]
CommandStatus {
status: HciStatus,
num_hci_command_packets: u8,
command_opcode: u16,
},
// Other messages...
}
~~Try id_type = [u8; 3].~~ Nevermind you have variable length. I think you'd have to put the SubId in a Enum of its own.
That being said, it would be nice to reference the bytes as you do in the above example.
@wcampbell0x2a it makes the structure odd looking, because I want to use the lengths as well, e.g.
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite)]
#[deku(id_type = "u8")]
pub enum LeMeta {
#[deku(id = "0x01")]
LeConnectionComplete {
status: HciStatus,
connection_handle: u16,
role: Role,
peer_address_type: AddressType,
peer_address: [u8; 6],
connection_interval: u16,
peripheral_latency: u16,
supervision_timeout: u16,
central_clock_accuracy: ClockAccuracy,
},
// Other messages
}
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite)]
#[deku(id_type = "u8")]
pub enum HciEventMsg {
#[deku(id = "0x03")]
LeMeta {
len: u8, // This is always 0x13 IF LeConnectionComplete
le_meta: LeMeta
},
#[deku(id = "0x0E")]
CommandComplete {
len: u8, // This is always 0x04
num_hci_command_packets: u8,
command_opcode: u16,
status: HciStatus,
},
#[deku(id = "0x0F")]
CommandStatus {
len: u8, // This is always 0x04
status: HciStatus,
num_hci_command_packets: u8,
command_opcode: u16,
},
// Other messages...
}
This works, but now the lengths that was easily defined with 0x04 and 0x13 doesn't look great.
I'd like to use the pattern from my original post, it's clearer, these static length values are hard to deal with.
Maybe I can create a wrapper struct:
#[derive(Debug, Clone, PartialEq, Eq, DekuWrite, Hash)]
struct Bytes(&'static [u8]);
impl<'a, Ctx: Copy> DekuReader<'a, Ctx> for Bytes
// where
// u8: DekuReader<'a, Ctx>,
{
fn from_reader_with_ctx<R: Read + Seek>(
reader: &mut Reader<R>,
inner_ctx: Ctx,
) -> Result<Self, DekuError>
where
Self: Sized,
{
todo!()
}
}
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite)]
#[deku(id_type = "Bytes")]
pub enum HciEventMsg {
#[deku(id = "Bytes(&[0x03, 0x13, 0x01])")]
LeConnectionComplete {
status: HciStatus,
connection_handle: u16,
role: Role,
peer_address_type: AddressType,
peer_address: [u8; 6],
connection_interval: u16,
peripheral_latency: u16,
supervision_timeout: u16,
central_clock_accuracy: ClockAccuracy,
},
#[deku(id = "Bytes(&[0x0E, 0x04])")]
CommandComplete {
num_hci_command_packets: u8,
command_opcode: u16,
status: HciStatus,
},
#[deku(id = "Bytes(&[0x0F, 0x04])")]
CommandStatus {
status: HciStatus,
num_hci_command_packets: u8,
command_opcode: u16,
},
// Other messages...
}
Not sure yet how to implement the DekuReader the types are kind of wonky.