sharksforarms / deku

Declarative binary reading and writing: bit-level, symmetric, serialization/deserialization
Apache License 2.0
1.05k stars 54 forks source link

Help passing context around #397

Closed wcampbell0x2a closed 5 months ago

wcampbell0x2a commented 6 months ago

Discussed in https://github.com/sharksforarms/deku/discussions/396

Originally posted by **alexjbuck** January 2, 2024 I'm brand new to the Deku crate. Its really cool! I'm looking to parse some binary packet data with this crate. The general structure of packets is a Header/Payload structure. The header is an Identifier and a total packet length (as u32). My initial thought was to treat the payload section as an enum where the id is an external id passed from the header type through the context variable (referencing the [docs](https://docs.rs/deku/0.16.0/deku/attributes/index.html#id-top-level)) Below is a minimal implementation for one variant but I'm getting a proc-macro error that I don't understand. ```rust use deku::prelude::*; #[derive(Debug, PartialEq, DekuRead, DekuWrite)] struct Packet { header: Header, #[deku(ctx = "*header")] payload: Payload, } #[derive(Debug, PartialEq, DekuRead, DekuWrite)] struct Header { kind: PacketType, length: u32, } #[derive(Debug, PartialEq, DekuRead, DekuWrite)] #[deku(type = "[u8;4]", endian="big")] enum PacketType { #[deku(id = b"INFO")] InfoType, } #[derive(Debug, PartialEq, DekuRead, DekuWrite)] #[deku(ctx = "header: Header", id = "header.kind")] enum Payload { #[deku(id = "PacketType::InfoType")] Info { #[deku(count = "header.length-8")] data: Vec }, } fn main() { // let data: Vec = vec![0x54, 0x49, 0x4D, 0x45,0x00,0x00,0x00,0x0C, 0x00,0x00,0x00,0x10, 0x53, 0x46, 0x4F, 0x52, 0x00, 0x00, 0x00, 0xA0]; let data : Vec = vec![0x49, 0x4E, 0x46, 0x4F, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x10]; let mut rest = (data.as_ref(),0 as usize); let (_rest,val) = Packet::from_bytes(rest).unwrap(); dbg!(val); dbg!(rest); } ``` These are the errors: ```rust error: proc-macro derive panicked --> src\main.rs:26:28 | 26 | #[derive(Debug, PartialEq, DekuRead, DekuWrite)] | ^^^^^^^^ | = help: message: called `Result::unwrap()` on an `Err` value: Error("expected `,`") error[E0277]: the trait bound `Payload: deku::DekuRead<'_, _>` is not satisfied --> src\main.rs:7:14 | 7 | payload: Payload, | ^^^^^^^ the trait `deku::DekuRead<'_, _>` is not implemented for `Payload` | = help: the following other types implement trait `deku::DekuRead<'a, Ctx>`: > > > > > > > > and 155 others For more information about this error, try `rustc --explain E0277`. error: could not compile `test-rs` (bin "test-rs") due to 3 previous errors ``` I'd appreciate any pointers to what I may be doing wrong here.
alexjbuck commented 6 months ago

398 appears to have fixed the issue! My case compiles and runs successfully. I did have to fix two issues: first I was moving the header via context instead of passing a reference, and second, the byte array input I gave encoded the u32 length as big-endian but the struct didn't tell Deku that, so it was trying to decode the length as little-endian (system default), so it didn't think there were enough bytes to fill the vec (technically true!), but once I fixed that it was all good.