Bitfield Struct
Procedural macro for declarative defining bitfields similar to structs.
As this library provides a procedural macro, it has no runtime dependencies and works for no-std
.
- Supports bool flags, raw integers, and every custom type convertible into integers (structs/enums)
- Ideal for driver/OS/embedded development (defining HW registers/structures)
- Generates minimalistic, pure, safe rust functions
- Compile-time checks for type and field sizes
- Rust-analyzer friendly (carries over documentation to accessor functions)
- Exports field offsets and sizes as constants (useful for const asserts)
- Generation of
fmt::Debug
Usage
Add this to your Cargo.toml
:
[]
= "0.5"
Basics
Let's begin with a simple example. Suppose we want to store multiple data inside a single Byte, as shown below:
This crate generates a nice wrapper type that makes it easy to do this:
/// Define your type like this with the bitfield attribute
// The macro creates three accessor functions for each field:
// <name>, with_<name> and set_<name>
let my_byte = new
.with_kind
.with_system
.with_level
.with_present;
assert!;
Features
Additionally, this crate has a few useful features, which are shown here in more detail.
The example below shows how attributes are carried over and how signed integers, padding, and custom types are handled.
/// A test bitfield with documentation
// <- Attributes after `bitfield` are carried over
/// A custom enum
// Usage:
let mut val = new
.with_int
.with_tiny
.with_negative
.with_custom
.with_public;
println!;
let raw: u64 = val.into;
println!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
// const members
assert_eq!;
assert_eq!;
val.set_negative;
assert_eq!;
The macro generates three accessor functions for each field. Each accessor also inherits the documentation of its field.
The signatures for int
are:
// generated struct
;
// generated trait implementations
Hint: You can use the rust-analyzer "Expand macro recursively" action to view the generated code.
fmt::Debug
This macro automatically creates a suitable fmt::Debug
implementation
similar to the ones created for normal structs by #[derive(Debug)]
.
You can disable it with the extra debug argument.
let val = new.with_data;
println!