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 allows you to skip tedious, error-prone bit operations, instead providing a simple, terse, and readable template format for specifying which bits correspond to which fields.

Splitbits is intended for cases where bitfield is too heavy-weight: when you don’t want to explicitly declare a new struct for data that you won’t use as a return value or argument. Splitbits also provides some features that are arguably out of scope for bitfield.

§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.)
  • 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 the 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

There are currently two settings that can be passed to change the behavior of the various macros:

  • 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§

  • Combine bits of multiple variables into a single variable as defined by a template.
  • Same as combinebits! except the template uses hexadecimal digits rather than binary digits.
  • Replace the bits in an integer with bits from other variables, as specified by a template.
  • Same as replacebits!, except the digits in the template are hexadecimal rather than binary.
  • Extract bit fields from an integer data type by matching against a template, storing them as fields in a generated struct.
  • 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.
  • 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.
  • 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.
  • 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.
  • Extract bits from multiple input integers by matching against input templates, then combine those bits into to an integer matching the output template.
  • Same as splitbits!, except that the widths of the generated fields are precise to-the-bit. A dependency on the ux crate is required.
  • Same as splitbits!, except that the template characters represent hexadecimal digits.
  • Same as splitbits_named! except with hexadecimal digits in the template.
  • 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.
  • Same as splithex_named_into!, except the widths of the generated fields are precise to-the-bit.
  • 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.
  • Same as splitbits_then_combine!, except with hexadecimal digits in the template.
  • Same as splithex!, except that the widths of the generated fields are precise to-the-bit. A dependency on the ux crate is required.