GithubHelp home page GithubHelp logo

rust-bitfield's Introduction

rust-bitfield

This crate provides macros to generate bitfield-like struct.

This a complete rewrite of the bitfield crate. You can find the previous version in the rust-bitfield-legacy repository. This version works on the stable version of rustc and use a different syntax with different possibility.

Example

An IPv4 header could be described like that:

bitfield!{
    struct IpV4Header(MSB0 [u8]);
    u32;
    get_version, _: 3, 0;
    get_ihl, _: 7, 4;
    get_dscp, _: 13, 8;
    get_ecn, _: 15, 14;
    get_total_length, _: 31, 16;
    get_identification, _: 47, 31;
    get_df, _: 49;
    get_mf, _: 50;
    get_fragment_offset, _: 63, 51;
    get_time_to_live, _: 71, 64;
    get_protocol, _: 79, 72;
    get_header_checksum, _: 95, 79;
    get_source_address, _: 127, 96;
    get_destination_address, _: 159, 128;
}

In this example, all the fields are read-only, the _ as setter name signals to skip the setter method. The range at the end (e.g. 3, 0) defines the bit range where the information is encoded.

Documentation

The documentation of the released version is available on doc.rs.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

rust-bitfield's People

Contributors

arkivm avatar cramertj avatar dzamlo avatar ithinuel avatar pseitz avatar roblabla avatar sosthene-nitrokey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

rust-bitfield's Issues

Generate masks for the fields

Hi!

When dealing with bitfields we often also want to address the fields with bit masks.

I'm thinking of the following:

bitfield!{
  pub struct BitField1(u16);
  impl Debug;
  // The fields default to u16
  mask FIELD1_MASK, field1, set_field1: 5, 2;
  pub field2, _ : 12, 3;
}

would generate an associated constant for field1:

impl BitField1 {
     const FIELD1_MASK: u16 = 0b00000000_0111100;
}

attempt to shift right with overflow'

thread 'main' panicked at 'attempt to shift right with overflow', /home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/bitfield-0.14.0/src/lib.rs:681:1
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace

use bitfield::bitfield;

bitfield! {
    pub struct Movw(u32);
    u32;
    pub get_imm12, set_imm12: 0, 11;
    pub get_Rd, set_Rd: 12, 15;
    pub get_imm4, set_imm4: 16, 19;
    pub get_opcode, set_opcode: 20, 27;
    pub get_cond, set_cond: 28, 31;
}

fn encode_thumb2_movw(immediate: u16) -> u32 {
    println!("encode_thumb2_movw immediate = {immediate:x}");
    let mut movw = Movw(0);
    let imm4 = (immediate >> 12) & 0xF;
    let imm12 = immediate & 0xFFF;
    println!("imm4 = {imm4:x}");
    println!("imm12 = {imm12:x}");
    movw.set_imm4(imm4 as u32);
    movw.set_imm12(imm12 as u32);
    movw.set_Rd(3);
    movw.set_opcode(0b00110000);
    return movw.0;
}

fn main() {
    let instruction = encode_thumb2_movw(0x5678);
    println!("{:032b}", instruction); // This should match the given Instr Bytes
    println!("{:x}", instruction); // Hex representation
}

I'm sure I am doing something wrong....

Add something more generic than into

We should add a way to call arbitrary method on the value before returning it. For example to do endianness conversion.

I don't know yet how it would look like.

Feature request: Right-padded fields

Somewhat related to #36

I'm creating a RISC-V emulator and the instruction formats sometimes encode values in the instructions, called immediates.
Sometimes, the instruction only contains the upper few bits of the immediate value.
E.g.:
image
Here, only the upper 20 bits are included in the instruction, from bit 31 to 12. and the lower 12 bits of the immediate should be set to 0.
I imagine syntax similar to the one proposed in #36 but with literal values that should occupy some number of bits in the field; e.g.:

imm, _: [(31, 12), 12(0)];
// alternatively
imm, _: 31, 12, 12(0);

It does raise the question of how the setter works when the field has padding.
I imagine it should just mask away the padded section, or simply panic when there are non-zero bits in the padded section.

It shouldn't be too difficult to support internal padding, but I can't imagine a good use case for that.

I understand that this is probably reaching outside the scope of what this package is meant to do, but it would certainly make my code a lot cleaner :).

bitfield should create constructor methods

The bitfield method only creates getter and accessor methods. It would be great if it could create constructors too. For example,

bitfield! {
    struct Foo(u16);
    u8;
    a, _: 7, 0;
    b, _: 15, 8;
}

should have something like the following in its expansion:

impl Foo {
    fn new(a: u8, b: u8) -> Self {
        Foo(((b as u16) << 8) | (a as u16))
    }
}

Trying to use it for my library but cannot compile.

Hi!
I am writing some helper library where I need to use bit fields to process some structures.

I started with the example code and simple test to see if I can write some tests, but unfortunately something is not working fine.
I tried first example/bits_position.rs and it compiles/runs.
Now when I am trying to rewrite example to be a test it fails to recognize BitsLocations and BitsLocationsMsb0.

My src/lib.rs is

#[macro_use]
extern crate bitfield;

use bitfield::BitMut;
use bitfield::BitRangeMut;

bitfield! {
        struct BitsLocations([u8]);
}

bitfield! {
        struct BitsLocationsMsb0(MSB0 [u8]);
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        let mut bits_locations = BitsLocations([0; 3]);
        let mut bits_locations_msb0 = BitsLocationsMsb0([0; 3]);

        assert_eq!(2 + 2, 4);
    }
}

This code is causing compilation error:

error[E0425]: cannot find function, tuple struct or tuple variant `BitsLocations` in this scope
  --> src/lib.rs:20:34
   |
20 |         let mut bits_locations = BitsLocations([0; 3]);
   |                                  ^^^^^^^^^^^^^ not found in this scope
   |
help: consider importing this tuple struct
   |
18 |     use crate::BitsLocations;
   |

error[E0425]: cannot find function, tuple struct or tuple variant `BitsLocationsMsb0` in this scope
  --> src/lib.rs:21:39
   |
21 |         let mut bits_locations_msb0 = BitsLocationsMsb0([0; 3]);
   |                                       ^^^^^^^^^^^^^^^^^ not found in this scope
   |
help: consider importing this tuple struct
   |
18 |     use crate::BitsLocationsMsb0;
   |

Appreciate any help or tips what I am doing wrong...

Requires AsMut and AsRef with buffers > 32 bytes

I think this is similar to the issue #21:

Assume the following code:

extern crate bitfield;
use bitfield::bitfield;

pub const SIZE: usize = 33;

bitfield! {
    pub struct Foo(MSB0[u8]);
    impl Debug;

    pub u8, foo, _ : 0;
}

fn main() {
    let buffer = [0u8; SIZE];
    Foo(buffer).foo();
}

This will result in:

error[E0599]: no method named `foo` found for struct `Foo<[u8; 33]>` in the current scope
  --> src/main.rs:16:17
   |
7  | / bitfield! {
8  | |     pub struct Foo(MSB0[u8]);
9  | |     impl Debug;
10 | |
11 | |     pub u8, foo, _ : 0;
12 | | }
   | |_- method `foo` not found for this
...
16 |       Foo(buffer).foo();
   |                   ^^^ method not found in `Foo<[u8; 33]>`
   |
   = note: the method `foo` exists but the following trait bounds were not satisfied:
           `[u8; 33]: std::convert::AsRef<[u8]>`
           `[u8; 33]: std::convert::AsMut<[u8]>`

If you lower the size to "32" (or less), it works.

Support `defmt`

This depends on the level of support we want:

  • We could simply support #[derive(Format)] but we will not get all the fields in the debug output only .0
  • We could port the bitfield_debug to defmt and get all the fields in the output, but this seems like a lot of effort

(ping @brandonros)

Add design notes

Could you please add an overview of the design to the documentation? I can't get an idea for how efficiently this crate is implemented without reading the source, and macro source is hard to read.

Unable to "Debug" for types that are backed by an array >32bytes

Having a structure which is backed by an array of bytes that is greater than 32 bytes fails:

error[E0277]: arrays only have std trait implementations for lengths 0..=32
  --> examples/simple.rs:70:38
   |
70 |     log::info!("Calibration: {:#?}", cal);
   |                                      ^^^ the trait `core::array::LengthAtMost32` is not implemented for `[u8; 41]`
   |
   = note: required because of the requirements on the impl of `core::convert::AsRef<[u8]>` for `[u8; 41]`
   = note: required because of the requirements on the impl of `core::fmt::Debug` for `drogue_bme680::Coefficients<[u8; 41]>`
   = note: required by `core::fmt::Debug::fmt`
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

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

I think there should be a way to prevent the automatic Debug generation to debug self.0, which should do the trick.

Please document the `index: usize` and `value: $from` arguments that getters and setters require

Trying to call getters without any parameters from a constructor elsewhere in my project results in a myriad of error[E0061]: this function takes 1 argument but 0 arguments were supplied errors when on the nightly-2020-07-12-unknown-linux-gnu target (host OS is Gentoo; target is an OS I’m writing from scratch).

Why, therefore, is this parameter that getters require according to the compiler undocumented? There’s absolutely nothing in the documentation that says anything about parameters for getters and/or setters. As a result, I had to snoop through the code to find out where the getters and setters are defined, and found the answer:

88         $($vis)* fn $setter(&mut self, index: usize, value: $from) {
…
117        $($vis)* fn $getter(&self, index: usize) -> $into {
…

I therefore ask @dzamlo to update the documentation to specify that the setters and getters both require the index parameter. Thank you in advance.

Feature request: Fields constructed of multiple ranges of bits

I'm working on a RISC-V emulator and I use this crate to easily extract fields from RISC-V formatted instructions.
It's pretty nifty.
RISC-V instructions sometimes have values encoded inside of them that should be used in computations, called immediates.
For some instruction formats, these immediates are split into parts to fit around other fields.
E.g.:

image

Here, the immediate is split into two parts with the upper 7 bits in the range 31, 25 and the next 5 bits in the range 11, 7.

With the current implementation, I have these as separate fields imm_11_5 and imm_4_0 and I construct the immediate by a shift and bitwise OR.

It would be really nifty if I could specify fields that were composed of ranges of bits like:

imm, _: [(31, 25), (11, 7)];

Preferably with some syntax that doesn't break compatibility.
I'm not very proficient with writing macros, but I could probably look to implement this myself if it's not something you can be bothered with.

If so, what should the syntax look like?
I think the array of tuples looks pretty good, but I'm not sure if it would collide with some other syntax.

`const fn` getters

I'm using bitfield combined with varlen, which allows const expressions over fields to be used to compute lengths of arrays. Would it be possible to generate const fn getters for bit fields so I can use those in my computation?

About endianness

Hi!

Thank you for your fantastic crate 😃
I have a question: is this crate agnostic to endianness? Say if I map a field to bits 0 to 7 of a u32 value, will I get the same result if my CPU is little-endian or big-endian?

I was thinking that if you implemented this crate methods using bitwise operators and those operators are endianness agnostic in Rust (like in C AFAIK) then maybe your crate is as well?

I started by implementing two bitfields structure one for little-endian and one for big-endian and selecting the good one with cfg but maybe that is useless 😀

Add `Into` support for booleans

So that we can use enums even if the field is only 1 bit wide.

It can currently be worked around by using into Type, field1, _: 2, 2;
But it looks wrong and it still requires Type to implement From/Into.

Document attributes

It looks like the bitfield macro supports placing pretty much any compiler attribute on the struct or on any field. This is very useful, especially for doing things like #[derive(Clone)]. But it's not documented anywhere. Ideally it should be documented in the API docs and in the examples.

Is there any difference between master and tagged version?

I used this repository for developing TLP parsing library.

During development, I used it in my cargo.toml as

[dependencies]
bitfield = { git = "https://github.com/dzamlo/rust-bitfield" }

Now I wanted to create my own create, and I had to switch to a particular tagged version so I did change

[dependencies]
# bitfield = { git = "https://github.com/dzamlo/rust-bitfield" }  << Removed this
bitfield = "0.13.2"   ## << Changed to this

That change in version caused code related to bitfields to not compile any longer with an error:

error[E0599]: the method `get_address32` exists for reference `&MemRequest3DW<T>`, but its trait bounds were not satisfied
   --> src/lib.rs:290:14
    |
290 |         self.get_address32().into()
    |              ^^^^^^^^^^^^^ method cannot be called on `&MemRequest3DW<T>` due to unsatisfied trait bounds
    |
    = note: the following trait bounds were not satisfied:
            `T: AsMut<[u8]>`

If I swap back dependency bitfield to GitHub repo it compiles and passes tests.

Is there any difference in usage of this library between directly using the master branch vs crate version??

Add `u128`/`i128` support

They should be stable in then next rustc version(1.26.0).

When this is the case, they should be usable in bitfield like the other inter type.

How to properly embedded bitfield structure inside other one?

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!

feature: API to set a range of bits using offset and length

I recently used bitfield in a project where I found the API passing MSB and LSB a bit cumbersome: https://github.com/gfroerli/firmware/pull/82/files#diff-8ba2aa3932cb35175d51de283952144c82bcf45eef54f18f72f199650929ee80R24

It would have been more intuitive for me to pass a bit_offset and a bit_length: Like that:
output.set_bit_range(*bit_index, Self::SIZE, self.0);

Would you consider adding such an API to this crate or do you think the idea is rubbish? 😉

Make getters work with immutable Data

I'd like to be able to work with immutable data. e.g.:

impl<T> IpV4Header<T> {
    pub fn validate<T>(bytes: T) -> Result<()>
    where
        T: AsRef<[u8]>,
    { ...

Unfortunately, the accessor functions (e.g. get_protocol) that are generated require the AsMut<[u8]> trait. Is there something I'm not doing correctly?

Thanks in advance.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.