sharksforarms / deku

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

endian attribute breaks enum #444

Closed shradej1 closed 1 month ago

shradej1 commented 1 month ago
use deku::prelude::*;

#[derive(DekuRead, DekuWrite)]
#[deku(id_type = "u8")]
enum Bar {
    #[deku(id = "0x00")]
    B1,
    #[deku(id = "0x01")]
    B2,
}

#[derive(DekuRead, DekuWrite)]
#[deku(endian = "big")]
pub struct Foo {
    e: Bar,
    i: i32,
}

gives the following compilation error:

12  | #[derive(DekuRead, DekuWrite)]
    |          ^^^^^^^^
    |          |
    |          expected `()`, found `Endian`
    |          arguments to this function are incorrect

This appears to be due to the interaction between the endian attribute, and the use of an enum. Changing e: Bar to e: u8 works fine, as does moving the endian attribute to the i field.

I'd expect the endian attribute to be provided to and ignored by the enum parser.

I believe this is a bug, but please let me know if I'm simply doing something wrong.

wcampbell0x2a commented 1 month ago

This is because of ctxs such as Endian are passed into sub-types.

The following works:

use deku::prelude::*;

#[derive(DekuRead, DekuWrite)]
#[deku(id_type = "u8", endian = "endian", ctx = "endian: deku::ctx::Endian")]
enum Bar {
    #[deku(id = "0x00")]
    B1,
    #[deku(id = "0x01")]
    B2,
}

#[derive(DekuRead, DekuWrite)]
#[deku(endian = "big")]
pub struct Foo {
    e: Bar,
    i: i32,
}

fn main() {}

See https://docs.rs/deku/latest/deku/attributes/index.html#endian Note: The endian is passed as a context argument to sub-types example.

shradej1 commented 1 month ago

Ah, thank you for the clarification. I did see the note in the docs - it just wasn't apparent to me that the attributes were necessary. I figured, it's a u8, so why bother specifying the endian-ness.