Crate splitbits

Source
Expand description

github

Concise macros for extracting bits from integers and combining bits into integers. No scary syntax. Minimal magic.

use splitbits::splitbits;

// Parse the template provided ("aaabbbbb"), apply it to the input, then generate a struct
// populated with the bit field values.
let fields = splitbits!(0b11110000, "aaabbbbb");
// Single-letter field names, generated from the unique letters in the template above.
assert_eq!(fields.a, 0b111);
assert_eq!(fields.b, 0b10000);

§Why use splitbits?

Splitbits replaces tedious, error-prone bit operations with a simple template format, making it easy to extract bits into variables.

Every operation than can be executed at compile time is. Generated code should be as efficient as hand-written bit operations.

Splitbits is intended for cases where bitfield is too heavy-weight syntactically: when you don’t want to explicitly declare a new struct for data that you won’t use as a return value or argument.

§The four base macros

For additional examples, see each macro’s page.

  • splitbits! - Extract bit fields out of an integer, storing them as fields of a struct. (See example above.) By default, each field will be stored in the smallest unsigned integer type possible.
  • combinebits! - Combine bits of multiple integers into a single integer.
    use splitbits::combinebits;
    
    let b: u8 = 0b1010_1010;
    let m: u8 = 0b1111;
    let e: u8 = 0b0000;
    let result = combinebits!("bbbb bbbb mmmm eeee");
    assert_eq!(result,       0b1010_1010_1111_0000);
  • splitbits_then_combine! - Extract bit fields from multiple integers then combine them into a single integer.
    use splitbits::splitbits_then_combine;
    
    let output = splitbits_then_combine!(
        0b1111_0000, "aaaa ..bb", // input 0, input template 0,
        0b1011_1111, "cc.. ....", // input 1, input template 1
                     "aaaa bbcc", // output template
    );
    assert_eq!(output, 0b1111_0010);
  • replacebits! - Replace some of the bits of an integer with bits from other integers.
    use splitbits::replacebits;
    
    let a: u16 = 0b101;
    let b: u8 = 0b01;
    // Placeholder periods in the template are the bits that will not be replaced.
    let result = replacebits!(0b10000001, "aaa..bb.");
    assert_eq!(result,                   0b10100011);

§Macro variants

The four base macros cover all the basic functionality that this crate offers and should be sufficient for most use-cases. However, in many situations better ergonomics can be achieved by using these more specialized macro variants.

§Hexadecimal

All four base macros have equivalents that use hexadecimal digits for their templates rather than bits (binary digits). The variants are splithex!, combinehex!, splithex_then_combine!, and replacehex!.

§Splitbits variants

splitbits! itself has many variants which are intended for better ergonomics for the generated variables. The basic variants are:

  • splitbits_named! - Used when single-letter variable names aren’t descriptive enough. This variant returns a tuple (instead of a struct) of the resulting fields, allowing the caller to assign individual long field names in the let binding.
  • splitbits_named_into! - Same as splitbits_named! except that the caller specifies the types of the resulting fields, not just their names. into() is called on each tuple field before it reaches the caller. This is useful for when the default type (the smallest integer type that will fit the field) is a smaller type than the caller would like to use, or if the caller has a newtype that they would like to use instead.
  • splitbits_ux! - Used when exact-width integers (e.g. u4, u7, u20) are needed, instead of just the standard types (u8, u16, u32, u64, u128, and bool). Requires the ux crate.

§Template syntax

Templates are a string of characters that represent the names and bit-placements of fields within an integer.

Example: "..aa bccc dddd 1010"

The possible elements of a template are:

  • Names - a single letter that indicates the name of a field. (Currently only ASCII allowed.)
  • Placeholders - a period that indicates a digit that will be ignored.
  • Literals - a literal digit of the numeric base of the template (e.g. binary or hexadecimal).
  • Whitespaces - an empty space character used to make formatting more human-friendly, paralleling how underscores can be added to integer literals.

The bits of a field are usually contiguous within a template, but they don’t have to be: "aabbbbaa". This template will interpret a as a single field, with no bits present between the halves.

§Restrictions
  • Templates (currently) must have a standard integer width (8, 16, 32, 64, or 128 bits).
  • Placeholders cannot be used in the template for combinebits!, nor in the output template of splitbits_then_combine!. They are not meaningful in those contexts.
  • Literals (currently) cannot be used in the template for splitbits! nor the input templates of splitbits_then_combine!. In the future, literals could be used in these contexts for input validation.

§Settings

Settings can be passed as the first argument to a macro to change some behaviors from the default. Their syntax is similar to named arguments in Python: setting_type=setting_value.

There are currently two setting types:

  • min - sets the minimum size of variable that can be produced by the splitbits! family of macros. Must be set if you don’t want booleans generated for 1-bit fields.
    • For standard (non-ux) macros, the valid setting values are bool (the default), u8, u16, u32, u64, and u128. See examples at splitbits!.
    • For ux macros, the valid setting values are bool (the default) or uX, where X is between 1 and 128 (both inclusive). See examples at splitbits_ux!.
  • overflow - sets the behavior to use if the value of an input variable is larger than the corresponding slot in the template. Used in combinebits! and replacebits!. Valid setting values are truncate (the default), panic, corrupt, or saturate.

Macros§

combinebits
Combine bits of multiple variables into a single variable as defined by a template.
combinehex
Same as combinebits! except the template uses hexadecimal digits rather than binary digits.
replacebits
Replace some of the bits in an integer with bits from other variables, as specified by a template. Placeholders (periods) mark bits that will not be replaced.
replacehex
Same as replacebits!, except the digits in the template are hexadecimal rather than binary.
splitbits
Extract bit fields from an integer data type by matching against a template, storing them as fields in a generated struct.
splitbits_named
Same as splitbits!, except that full-length variable names can be used. Returns a tuple instead of a generated struct. If there is only a single field specified in the template, returns a single variable instead (not a 1-tuple). Fields are returned in the order that they first appear in the template, and the single character template names are discarded.
splitbits_named_into
Same as splitbits_named!, except the caller can provide the field types, rather than the macro inferring them. The custom types must implement From for the relevant integer types.
splitbits_named_into_ux
Same as splitbits_named_into!, except that the widths of the generated fields are precise to-the-bit. A dependency on the ux crate is required.
splitbits_named_ux
Same as splitbits_named!, except that the widths of the generated fields are precise to-the-bit. A dependency on the ux crate is required.
splitbits_then_combine
Extract bits from multiple input integers by matching against input templates, then combine those bits into to an integer matching the output template.
splitbits_ux
Same as splitbits!, except that the widths of the generated fields are precise to-the-bit. A dependency on the ux crate is required.
splithex
Same as splitbits!, except that the template characters represent hexadecimal digits.
splithex_named
Same as splitbits_named! except with hexadecimal digits in the template.
splithex_named_into
Same as splithex_named!, except the caller can provide the field types, rather than the macro inferring them. The custom types must implement From/Into for the relevant integer types.
splithex_named_into_ux
Same as splithex_named_into!, except the widths of the generated fields are precise to-the-bit.
splithex_named_ux
Same as splithex_named!, except that the widths of the generated fields are precise to-the-bit. A dependency on the ux crate is required.
splithex_then_combine
Same as splitbits_then_combine!, except with hexadecimal digits in the template.
splithex_ux
Same as splithex!, except that the widths of the generated fields are precise to-the-bit. A dependency on the ux crate is required.