sharksforarms / deku

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

`id_pat` with external `id` #305

Closed shirok1 closed 6 hours ago

shirok1 commented 1 year ago

Hello, it's me again.

When using an Enum type with external id (from context) and an id_pat on any Enum variant, the read method (::deku::DekuRead) implement for that variant will incorrectly try to read the id receiver field again.

#[deku_derive(DekuRead, DekuWrite)]
#[derive(Debug)]
#[deku(ctx = "content_id: u16, content_size: u16", id = "content_id")]
pub enum SomeDataTypeEnum {
    // #[deku(id = "0x0200")]
    // ThisWorks {
    //     #[deku(bytes_read = "content_size")]
    //     content: Vec<u8>,
    // },
    #[deku(id_pat = "0x0201..=0x02FF")]
    ThisWontWork {
        content_id: u16,
        #[deku(bytes_read = "content_size")]
        content: Vec<u8>,
    },
}

...expands to this:

0x0201..=0x02FF => {
    let __deku_id = {
        let (__deku_new_rest, __deku_value) = <u16 as ::deku::DekuRead<
            '_,
            _,
        >>::read(__deku_rest, ())?;
        let __deku_value: u16 = Result::<
            _,
            ::deku::DekuError,
        >::Ok(__deku_value)?;
        __deku_rest = __deku_new_rest;
        __deku_value
    };
    let content_id = &__deku_id;

I suggest adding an explicit attribute for specifying the id receiver.

sharksforarms commented 1 year ago

thanks for the report.

In the meantime, can you confirm this is a valid work-around?

#[deku(skip, default = "content_id")]
content_id: u16,
shirok1 commented 1 year ago

Can you confirm this is a valid work-around?

#[deku(skip, default = "content_id")]
content_id: u16,

Yes, it works. :rofl: Pretty strange.

wcampbell0x2a commented 6 hours ago

This appears to be fixed:

use deku::prelude::*;

#[deku_derive(DekuRead, DekuWrite)]
#[derive(Debug)]
#[deku(ctx = "content_id: u16, content_size: u16", id = "content_id")]
pub enum SomeDataTypeEnum {
    // #[deku(id = "0x0200")]
    // ThisWorks {
    //     #[deku(bytes_read = "content_size")]
    //     content: Vec<u8>,
    // },
    #[deku(id_pat = "0x0201..=0x02FF")]
    ThisWontWork {
        #[deku(bytes_read = "content_size")]
        content: Vec<u8>,
    },
}

fn main() {
    let bytes = &[0x01, 0x02];
    let mut c = std::io::Cursor::new(bytes);
    let mut r = Reader::new(&mut c);
    let s = SomeDataTypeEnum::from_reader_with_ctx(&mut r, (0x0201, 2));
    println!("{s:02x?}")
}
> cargo run --example 305
Ok(ThisWontWork { content: [01, 02] })

re-open if you disagree!