sharksforarms / deku

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

The trait `deku::DekuRead<'_, Endian>` is not implemented for enums #183

Closed zsx closed 3 years ago

zsx commented 3 years ago

The follow code doesn't compile:

use deku::prelude::*;

#[derive(DekuRead, DekuWrite)]
#[deku(type = "u16")]
pub enum EnumA {
    ItemA = 0x01,
}

#[derive(DekuRead, DekuWrite)]
#[deku(endian = "little")]
pub struct StrcutA {
    pub field_a: EnumA,
}

The error is:

error[E0277]: the trait bound `EnumA: deku::DekuRead<'_, Endian>` is not satisfied
  --> src\lib.rs:12:10
   |
12 | #[derive(DekuRead, DekuWrite)]
   |          ^^^^^^^^ the trait `deku::DekuRead<'_, Endian>` is not implemented for `EnumA`
   |
   = help: the following implementations were found:
             <EnumA as deku::DekuRead<'_>>
   = note: required by `deku::DekuRead::read`
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
  --> src\lib.rs:12:20
   |
12 | #[derive(DekuRead, DekuWrite)]
   |                    ^^^^^^^^^ expected `()`, found enum `Endian`
   |
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.

It compiles fine if I remove #[deku(endian = "little")] for StructA

sharksforarms commented 3 years ago

Unfortunately this is a very confusing error message. And is really not obvious what needs to be done to fix this...

See the documentation for endian attribute here

The second example should help you out.

endian is passed to the child struct via ctx (context) attribute

#[derive(DekuRead, DekuWrite)]
#[deku(type = "u16", endian = "endian", ctx = "endian: deku::ctx::Endian")]
pub enum EnumA {
    ItemA = 0x01,
}

#[derive(DekuRead, DekuWrite)]
#[deku(endian = "little")]
pub struct StructA {
    pub field_a: EnumA,
}

Again, sorry for the mis-leading error message. Related issue: https://github.com/sharksforarms/deku/issues/107

mmmfarrell commented 2 years ago

@sharksforarms - I am having trouble getting this working when I want to be able to serialize / deserialize both the struct and the enum. Any help would be much appreciated! Example:

use deku::prelude::*;

#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
#[deku(endian = "endian", ctx = "endian: deku::ctx::Endian")]
struct DekuBase {
    field_a: u8,
    field_b: u8,
}

#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
#[deku(endian = "little")]
struct DekuTest {
    base: DekuBase,
    field_b: u8,
    field_c: u8,
}

fn main() {
    let data: Vec<u8> = vec![0xAB, 0xAC, 0xBE, 0xEF];
    let (_rest, mut val) = DekuTest::from_bytes((data.as_ref(), 0)).unwrap();
    assert_eq!(DekuTest {
        base: DekuBase { field_a: 0xAB, field_b: 0xAC },
        field_b: 0xBE,
        field_c: 0xEF,
    }, val);

    val.field_c = 0xFF;

    let data_out = val.to_bytes().unwrap();
    assert_eq!(vec![0xAB, 0xAC, 0xBE, 0xFF], data_out);

    let data_base: Vec<u8> = vec![0xBE, 0xEF];
    let (_rest, mut val) = DekuBase::from_bytes((data_base.as_ref(), 0)).unwrap();
    assert_eq!(DekuBase {
        field_a: 0xBE,
        field_b: 0xEF,
    }, val);

    println!("pass\n");
}

produces the following error:

error[E0599]: no function or associated item named `from_bytes` found for struct `DekuBase` in the current scope
  --> src/main.rs:33:38
   |
5  | struct DekuBase {
   | --------------- function or associated item `from_bytes` not found for this
...
33 |     let (_rest, mut val) = DekuBase::from_bytes((data_base.as_ref(), 0)).unwrap();
   |                                      ^^^^^^^^^^ function or associated item not found in `DekuBase`
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following traits define an item `from_bytes`, perhaps you need to implement one of them:
           candidate #1: `OsStrExt`
           candidate #2: `deku::DekuContainerRead`

For more information about this error, try `rustc --explain E0599`.

Or if I change the DekuBase class to have the following macros

#[derive(Debug, PartialEq, DekuRead, DekuWrite)]
#[deku(endian = "little")]
struct DekuBase {
    field_a: u8,
    field_b: u8,
}

I get the following errors:

error[E0277]: the trait bound `DekuBase: deku::DekuRead<'_, Endian>` is not satisfied
  --> src/main.rs:12:28
   |
12 | #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
   |                            ^^^^^^^^ the trait `deku::DekuRead<'_, Endian>` is not implemented for `DekuBase`
   |
   = help: the trait `deku::DekuRead<'_>` is implemented for `DekuBase`
   = note: this error originates in the derive macro `DekuRead` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
   --> src/main.rs:12:38
    |
12  | #[derive(Debug, PartialEq, DekuRead, DekuWrite)]
    |                                      ^^^^^^^^^
    |                                      |
    |                                      expected `()`, found enum `Endian`
    |                                      arguments to this function are incorrect
    |
note: associated function defined here
   --> /home/vibhav/.cargo/registry/src/github.com-1ecc6299db9ec823/deku-0.12.6/src/lib.rs:321:8
    |
321 |     fn write(
    |        ^^^^^
    = note: this error originates in the derive macro `DekuWrite` (in Nightly builds, run with -Z macro-backtrace for more info)

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.