Crates.io | bitf |
lib.rs | bitf |
version | 1.3.0 |
source | src |
created_at | 2022-01-01 11:03:05.74813 |
updated_at | 2022-01-19 13:43:23.216634 |
description | This crate provides a procedural macro to easily create a bitfield out of a struct |
homepage | |
repository | https://github.com/hrafnskogr/bitf |
max_upload_size | |
id | 506093 |
size | 48,169 |
Rust procedural macro to quickly generate bitfield from a structure.
Features:
Any size from 8 to 128 bits
Auto implementation of getters and setters, and Default.
Supports the use of other attribute on the structure
Declaration of fields either from the Least Significant Bit or the Most Significant Bit
Supports custom return types (primitives and custom types)
Supports custom visibility for each field
Skip implementation of fields marked as reserved
Implementation of a Pretty Print associated function: pprint()
By default:
starts declaration of fields from the Least Significant Bit;
declares all fields as public;
does not implement the pretty print function;
The macro can be used as following:
#[bitf(size, opt_arg1, opt_arg2, opt_arg3)]
Where size can be:
u8
u16
u32
u64
u128
There are 3 optional parameters:
Order: can be 'lsb' or 'msb'
Visibility: 'no_pub'
Pretty Print: 'pp'
The size
parameter will constrain the total size of the bitfield.
The order
parameter is optional and will alter the order in which the fields are declared.
By default this parameter is set to lsb
.
When setting the order parameter to msb
, the first declared field of the struct will be set on the most significant bit, and the other way around when using the lsb mode.
The visibility
parameter is optional and will alter the visibility of the declared field. It can be set only to no_pub
.
By default, all fields are declared as public, using the flag no_pub
will deactivate this behaviour and rely on the visibility declared by the user.
Hence, the size and position of the field is based on the field declaration :
use bitf::bitf;
#[bitf(u8, lsb, pp)]
struct Example
{
any_case_name_2: (), // () is used to specify to use the raw type defined in the attribute (here is u8)
_reserved_4: (), // This field will not be implemented as the name is _reserved
name_B_2: u16, // Return type override. The `get` method implemented will return a u16
// Custom types can be used, be will need to implement the From trait
// Please see the test file in "test/attribute_macro.rs" for an example
}
// The internal, full value of the field can be accessed as :
let e = Example::default();
println!("{}", e.raw);
// and the representation of the bitfield can be accessed via
e.pprint();
When combined to other attributes, make sure to implement it BEFORE any #[derive(..)]
attribute, or the expansion order might (will) fail.
use bitf::bitf;
#[repr(C)]
#[allow(dead_code)]
#[bitf(u8)]
#[derive(Debug)]
struct MyStruct
{
fieldA_4: (),
fieldB_4: (),
}
The Pretty Print
parameter is set throught the pp
switch.
This switch will implement an associated set of functions on the structure, accessible through pprint()
.
This function will produce the following output (for a 128 bits bitfield):
64 60 59 57 56 40 35 27 23 21 18 17 7 6 3 2 0
┌──────┬───┬────┬───┬──────────────────┬───────┬──────────┬──────┬────┬─────┬───┬────────────┬───┬─────┬───┬────┐
│ 1111 │ 1 │ 01 │ 0 │ rrrrrrrrrrrrrrrr │ 01101 │ 11110101 │ 0110 │ 00 │ 010 │ 0 │ 1000110101 │ 0 │ 110 │ 0 │ 10 │
└──────┴───┴────┴───┴──────────────────┴───────┴──────────┴──────┴────┴─────┴───┴────────────┴───┴─────┴───┴────┘
The field noted as "rrrrrrrr..." symbolizes a reserved field. Such fields are defined when declared with the name _reserved_usize
Please note that there is not any mechanism of paging or any clever system to adapt the output to the shell size. Hence, it will probably fail if you try to print a bitfield of 128 1-byte wide fields, unless you have an exceptionnaly wide screen
You can use the following syntax when declaring a field to skip its implementation.
_reserved_intSize
In the previous example, the field _reserved_4
will not have its 4 bits implemented.
No accessor will be generated for this field.
Considering the following bitfield:
7 0
0 0 0 0 0 0 0 0
| | | | | | | |_ field_a - Size 1
| | | | | | |___ fieldB - Size 1
| | | | | |_____ fieldC - Size 1
| | \|/________ reserved - Size 3
\ /_____________ field_D - Size 2
It can be achieved with the following declaration and macro usage
use bitf::bitf;
#[bitf(u8)]
struct MyStruct
{
field_a_1: (),
fieldB_1: (),
FieldC_1: (),
_reserved_3: (),
Field_D_2: (),
}
This will generate the following structure and associated methods
struct MyStruct
{
pub raw: u8,
}
impl MyStruct
{
pub fn field_a(self: &Self) -> u8 { /* bitwise logic */ 0 }
pub fn set_field_a(self: &Self, val: u8) { /* bitwise logic */ }
pub fn fieldB(self: &Self) -> u8 { /* bitwise logic */ 0 }
pub fn set_fieldB(self: &Self, val: u8) { /* bitwise logic */ }
/*
* And so on...
*/
}
impl Default for MyStruct
{
fn default() -> Self
{
MyStruct { raw: 0x0 }
}
}
//So you can easily set and read values of each defined bitfield:
let mut bf = MyStruct::default();
bf.set_field_a(1);
bf.set_fieldB(1);
println!("{:#010b}", bf.field_a());
_reserved_intSize