bitrange 0.2.0

Simple plugin to map bits in integer values to fields
docs.rs failed to build bitrange-0.2.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: bitrange-0.3.0

bitrange

getting started

To get started, add this to your Cargo.toml:

bitrange = "0.1.0"

Then add the following code to your main.rs or lib.rs

#![feature(proc_macro)]
#[macro_use]
extern crate bitrange;

bitrange needs a nightly version of the compiler because it uses the feature proc_macro which is not stabilized yet

The last field may not have a trailing comma at this point in time

examples

Bitrange helps you map bit fields to proper getters and setters.

Say you're trying to make an IP parser. The rfc will give you this:

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Version|  IHL  |Type of Service|          Total Length         |

If you wanted to parse this in Rust, you'd have to make the following mapping:

  • the first 4 bits are mapped to version
  • The next 4 bits are mapped to ihl
  • The next 8 bits are mapped to type_of_service
  • The last 16 bits are mapped to total_length

With bitrange, you can easily map bytes to fields. To parse this part of the protocol, simply write

#![feature(proc_macro)]
#[macro_use]
extern crate bitrange;

bitrange! {
    IpHeader: u32,                           // struct name
    [aaaa_bbbb_cccccccc_dddddddddddddddd],   // pattern that we're matching against
    a: version,                              // map character 'a' to field 'version'
    b: ihl,                                  // map character 'b' to field 'ihl'
    c: type_of_service,                      // map character 'c' to field 'type_of_service'
    d: total_length                          // map character 'd' to field 'total_length'
}

fn main() {
    let header = IpHeader::from(0b0001_0010_00000011_0000000000000100);
    assert_eq!(header.version(), 0b0001);
    assert_eq!(header.ihl(), 0b0010);
    assert_eq!(header.type_of_service(), 0b0011);
    assert_eq!(header.total_length(), 0b0100);
}

If you wanted to make a field mutable, simply add a second ident to the field mapping, e.g.:


bitrange! {
    IpHeader: u32,                           // struct name
    [aaaa_bbbb_cccccccc_dddddddddddddddd],   // pattern that we're matching against
    a: version set_version,                  // map character 'a' to field 'version', and create setter 'set_version'
    b: ihl,                                  // map character 'b' to field 'ihl'
    c: type_of_service,                      // map character 'c' to field 'type_of_service'
    d: total_length                          // map character 'd' to field 'total_length'
}

fn main() {
    let mut header = IpHeader::from(0b0001_0010_00000011_0000000000000100);
    assert_eq!(header.version(), 0b0001);
    assert_eq!(header.ihl(), 0b0010);
    assert_eq!(header.type_of_service(), 0b0011);
    assert_eq!(header.total_length(), 0b0100);

    header.set_version(0b0100);
    assert_eq!(header.version(), 0b0100);
}

In addition, you can define constraints to bits that have to always be 0 or 1


bitrange! {
    Test: u8,
    // from left (highest) to right (lowest)
    // first 3 bits are mapped to a
    // the next bit is always 1
    // the next bit is always 0
    // the last 3 bits are mapped to b
    [aaa1_0bbb],
    a: first,
    b: second
}

fn main() {
    // This panics at runtime
    // Because the 4th highest bit should always be 1
    // Test::from(0);

    // The enum also implements Default, so you can simply do:
    let _test = Test::default();
}

Compile-time checks

bitrange will also check fields at compile time to see if they exist

bitrange! { 
    Test: u8,
    [aaa1_0bbb],
    a: first,
    b: second,
    c: third // this will panic with
             // Token 'c' is not found in pattern "aaa10bbb"
}

However, this does not work for unmapped fields

bitrange! {
    Test: u8,
    [aaa1_0bbb],
    a: first,
    // b is not mapped
    // Does not give a warning
}