Skip to content

Derive macro calculates incorrect bit size when using a non-inclusive bytes="x..y" field attribute #107

Description

@c-to-the-l

Consider the following code and the two almost identical structs. One uses 0..=1 while the other uses 0..2. For the first case, the code works as expected. For the second case, it calculates the field size to be 8 bits instead of 16 bits.

use packed_struct::prelude::*;

#[derive(Debug, Clone, PackedStruct)]
#[packed_struct(endian="lsb", bit_numbering="msb0", size_bytes="2")]
pub struct StructA {
    /// works okay
    #[packed_field(bytes="0..=1", size_bytes="2")]
    field_a: u16,
}

#[derive(Debug, Clone, PackedStruct)]
#[packed_struct(endian="lsb", bit_numbering="msb0", size_bytes="2")]
pub struct StructB {
    /// doesn't work
    #[packed_field(bytes="0..2", size_bytes="2")]
    field_b: u16,
}

I would expect that 0..2 would behave identically to 0..=1, however they result in different code (and actually the 0..2 case causes a compiler error).

Compare the generated implementation of unpack for the two structs:

Generated StructA implementation, good, generates Bits<16>:

    #[inline]
    #[allow(unused_imports, unused_parens)]
    fn unpack(
        src: &Self::ByteArray,
    ) -> ::std::result::Result<StructA, ::packed_struct::PackingError> {
        use ::packed_struct::*;
        let field_a = {
            let bytes = {
                let mut b = [0; (2usize - 0usize)];
                b[..].copy_from_slice(&src[0usize..2usize]);
                b
            };
            use ::packed_struct::types::*;
            use ::packed_struct::types::bits::*;
            let res: ::std::result::Result<
                LsbInteger<_, _, Integer<u16, Bits<16>>>,
                PackingError,
            > = <LsbInteger<_, _, _>>::unpack(&bytes);
            let unpacked = res?;
            **unpacked
        };
        Ok(StructA { field_a })
    }

Generated StructB implementation - bad, uses Bits<8>:

    fn unpack(
        src: &Self::ByteArray,
    ) -> ::std::result::Result<StructB, ::packed_struct::PackingError> {
        use ::packed_struct::*;
        let field_b = {
            let bytes = {
                let mut b = [0; (1usize - 0usize)];
                b[..].copy_from_slice(&src[0usize..1usize]);
                b
            };
            use ::packed_struct::types::*;
            use ::packed_struct::types::bits::*;
            let res: ::std::result::Result<
                MsbInteger<_, _, Integer<u16, Bits<8>>>,
                PackingError,
            > = <MsbInteger<_, _, _>>::unpack(&bytes);
            let unpacked = res?;
            **unpacked
        };
        Ok(StructB { field_b })
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions