# ubits [![crates.io](https://img.shields.io/crates/v/ubits.svg)](https://crates.io/crates/ubits) [![Downloads](https://img.shields.io/crates/d/ubits.svg)](https://crates.io/crates/ubits) [![Build](https://github.com/manoadamro/ubits/actions/workflows/rust.yml/badge.svg)](https://github.com/manoadamro/ubits/actions/workflows/rust.yml) [![Docs](https://img.shields.io/docsrs/ubits)](https://manoadamro.github.io/ubits/doc/ubits/) [![Licence](https://img.shields.io/github/license/manoadamro/ubits)](https://github.com/manoadamro/ubits/blob/main/LICENSE) Bit fields and masks for rust! Provides a macro for generating [`bit field`](https://en.wikipedia.org/wiki/Bit_field) types complete with flags and some helpful trait implementations. Supports field widths of `8`, `16`, `32`, `64` and `128` bits. - [`bitfield`] - macro documentation. - [`examples`] - examples of the output generated by the [`bitfield`] macro. __Note: the example module is only complied with documentation builds and is not available for importing in the wild.__ ## Usage Generate a bitfield struct with a flag enum... (The following examples all use this as a definition.) ```rust use ubits::bitfield; bitfield! { pub u8 ExampleField ExampleFlags { 0 : Flag0, 1 : Flag1, 2 : Flag2, 3 : Flag3, 4 : Flag4, 5 : Flag5, 6 : Flag6, 7 : Flag7, } } ``` ### Instances From integer: ```rust let from_integer = ExampleField(123); assert_eq!(ExampleField(123), from_integer); ``` From a binary string: ```rust let from_binary = ExampleField::from_binary_str("01111011"); assert_eq!(ExampleField(123), from_binary) ``` From ones: ```rust let from_ones = ExampleField::ones(); assert_eq!("11111111", from_ones.as_binary()); assert_eq!(255, from_ones.as_integer()); ``` From zeros: ```rust let from_zeros = ExampleField::zeros(); assert_eq!("00000000", from_zeros.as_binary()); assert_eq!(0, from_zeros.as_integer()); ``` #### Field Access Get bit value by field: ```rust let field = ExampleField::from_binary_str("01010101"); assert!(field.get(ExampleFlags::Flag0)); assert!(!field.get(ExampleFlags::Flag1)); ``` Get bit value by index: ```rust let field = ExampleField::from_binary_str("01010101"); assert!(field.get_index(0)); assert!(!field.get_index(1)); ``` Set bit value by field: ```rust let mut field = ExampleField::from_binary_str("01010101"); field.set(ExampleFlags::Flag1); field.set(ExampleFlags::Flag3); assert_eq!("01011111", field.as_binary()); ``` Set bit value by index: ```rust let mut field = ExampleField::from_binary_str("01010101"); field.set_index(1); field.set_index(3); assert_eq!("01011111", field.as_binary()); ``` Clear bit value by field: ```rust let mut field = ExampleField::from_binary_str("01010101"); field.clear(ExampleFlags::Flag0); field.clear(ExampleFlags::Flag2); assert_eq!("01010000", field.as_binary()); ``` Clear bit value by index: ```rust let mut field = ExampleField::from_binary_str("01010101"); field.clear_index(0); field.clear_index(2); assert_eq!("01010000", field.as_binary()); ``` Toggle bit value by field: ```rust let mut field = ExampleField::from_binary_str("01010101"); field.toggle(ExampleFlags::Flag0); assert_eq!("01010100", field.as_binary()); field.toggle(ExampleFlags::Flag0); assert_eq!("01010101", field.as_binary()); ``` Toggle bit value by index: ```rust let mut field = ExampleField::from_binary_str("01010101"); field.toggle_index(0); assert_eq!("01010100", field.as_binary()); field.toggle_index(0); assert_eq!("01010101", field.as_binary()); ``` #### Named Getters and Setters Ubits can generate getter and setter methods for zero or more fields, if a name is provided. ```rust use ubits::bitfield; bitfield! { pub u8 ExampleField ExampleFlags { 0 : Flag0 : (field_0), // is_field_0 & set_field_0 & clear_field_0 & toggle_field_0 1 : Flag1 : (field_1), // is_field_1 & set_field_1 & clear_field_1 & toggle_field_1 2 : Flag2, 3 : Flag3, 4 : Flag4, 5 : Flag5, 6 : Flag6, 7 : Flag7, } } let mut field = ExampleField::from_binary_str("01010101"); assert_eq!(true, field.is_field_0()); assert_eq!(false, field.is_field_1()); field.set_field_1(); assert_eq!(true, field.is_field_1()); field.clear_field_1(); assert_eq!(false, field.is_field_1()); field.toggle_field_1(); assert_eq!(true, field.is_field_1()); ``` #### Combinations Combine bit fields:
(use `into_combined` to consume self) ```rust let mut a = ExampleField::from_binary_str("01010101"); let b = ExampleField::from_binary_str("10101010"); assert_eq!("11111111", a.combine(b).as_binary()); ``` Get the intersection of two bitfields:
(use `into_intersection` to consume self) ```rust let mut a = ExampleField::from_binary_str("11000011"); let b = ExampleField::from_binary_str("01111110"); assert_eq!("01000010", a.intersect(b).as_binary()); ``` Get the diff of two bitfields:
(use `into_diff` to consume self) ```rust let mut a = ExampleField::from_binary_str("11000011"); let b = ExampleField::from_binary_str("01100110"); assert_eq!("10100101", a.diff(b).as_binary()); ``` #### Bitwise Both bit field instances and flags use bitwise operators to change bit values. ```rust let mut from_zeros = ExampleField::zeros(); assert_eq!("00000000", from_zeros.as_binary()); // set bit to 1 from_zeros |= ExampleFlags::Flag1; assert_eq!("00000010", from_zeros.as_binary()); // set bit back to 0 from_zeros &= ExampleFlags::Flag1; assert_eq!("00000000", from_zeros.as_binary()); // toggle a bit from_zeros ^= ExampleFlags::Flag1; assert_eq!("00000010", from_zeros.as_binary()); from_zeros ^= ExampleFlags::Flag1; assert_eq!("00000000", from_zeros.as_binary()); ``` Operations can also be chained together: ```rust let mut from_zeros = ExampleField::zeros() | ExampleFlags::Flag1 | ExampleFlags::Flag3; assert_eq!("00001010", from_zeros.as_binary()); ``` Bitfield instances can also be created from combining flags: ```rust let mut from_zeros = ExampleFlags::Flag1 | ExampleFlags::Flag3; assert_eq!("00001010", from_zeros.as_binary()); ``` ### Fields named with flags The generated flags enum allows you to access bits by name. The flag has an associated [`u8`] value, which determines the index its target bit. (See [`bitfield`] for more info) With the following input... ```no_compile 1 0 1 0 0 1 1 0 ``` and the following flags... ```no_compile 0 : f1 1 : f1 2 : f2 3 : f3 4 : f4 5 : f5 6 : f6 7 : f7 ``` we end up with this layout. | name | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0 | |-----------|----|----|----|----|----|----|----|----| | bit value | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | | index | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | With the same input and only the first few flags: ```no_compile 0 : f0 1 : f1 2 : f2 ``` we end up with this layout. | name | | | | | | f2 | f1 | f0 | |-----------|----|----|----|----|----|----|----|----| | bit value | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | | index | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | Using the same input, but with dispersed flags: ```no_compile 1 : f0 3 : f1 6 : f2 ``` we end up with this layout. | name | | f2 | | | f1 | | f0 | | |-----------|----|----|----|----|----|----|----|----| | bit value | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | | index | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |