dzamlo / rust-bitfield

This crate provides macros to generate bitfield-like struct.
Apache License 2.0
157 stars 19 forks source link

How to properly embedded bitfield structure inside other one? #32

Closed gotoco closed 2 years ago

gotoco commented 2 years ago

Hi I am trying to create more advanced structure where I embedded bitfield struct inside regular struct but I am struggling with structure creation.

To illustrate my problem I provide example code: I have two bitfields: Header and DW1. Header is 8 bits, DoubleWorld is 32 bits. Both structures create Request structure, which under the hood use them.

use std::ops::Index;
#[macro_use]
extern crate bitfield;

bitfield! {
        struct Header(MSB0 [u8]);
        impl Debug;
        u8;
        get_format, _: 2, 0;
        get_type,   _: 7, 3;
}

bitfield! {
        struct DW1(MSB0 [u8]);
        impl Debug;
        u32;
        get_id,    _: 15, 0;
        get_tag,   _: 23, 16;
        get_addr,  _: 31, 24;
}

#[derive(Debug)]
pub struct Request<T: AsRef<[u8]>> {
    header: Header<T>,
    body: DW1<T>,
}

impl<T: AsRef<[u8]>> Request<T>
where
T: Index<std::ops::Range<usize>, Output = T>,
T: Copy,
{
    pub fn new(bytes: T) -> Request<T> {
        Request {
            header: Header(bytes[0..1]),
            body: DW1(bytes[1..5]),
        }
    }
}

fn main() {
    let header = Header([0x0]);
    println!("header: {:?}", header);   // Works fine!

    let dw1 = DW1([0xFF, 0xEE, 0xDD, 0xCC]);
    println!("DW1: {:?}", dw1);                     // Works fine!

    let bytes: [u8; 5] = [0x00, 0xFF, 0xEE, 0xDD, 0xCC]; // create array [u8; 5] for request
    let request = Request::new(bytes);  // expected array `[u8; 5]`, found slice?
    println!("Request: {:?}", request);
}

When I try to use that I got followed error:

error[E0271]: type mismatch resolving `<[u8; 5] as Index<std::ops::Range<usize>>>::Output == [u8; 5]`
  --> src/main.rs:55:16
   |
38 |     pub fn new(bytes: T) -> Request<T> {
   |     ---------------------------------- required by `Request::<T>::new`
...
55 |     let request = Request::new(bytes);  // expected array `[u8; 5]`, found slice?
   |                   ^^^^^^^^^^^^ expected array `[u8; 5]`, found slice
   |
   = note: expected array `[u8; 5]`
              found slice `[u8]`

error: aborting due to previous error; 1 warning emitted

Compiler suggest that I am providing wrong argument to the Request::new() method (It expects array but Slice is provided). I am not entirely sure if that is just a matter of provided argument.
Bytes is [u8; 5] array not a slice. I also tried few things like using slice_as_array create but any changes to Request::new method is causing issue with Generic passed to the other bitfields.

At that point I am thinking that probably I am designing my code in bad way, so was curious if there are any examples or tips how to create structures based on other bitfields based structures? Appreciate any help!