Crates.io | tartan-bitfield |
lib.rs | tartan-bitfield |
version | 1.2.0 |
source | src |
created_at | 2022-08-14 21:12:42.11052 |
updated_at | 2022-12-11 22:19:00.132462 |
description | Define structures with accessors for particular bits or bit ranges |
homepage | |
repository | https://github.com/cimbul/tartan-bitfield |
max_upload_size | |
id | 645578 |
size | 79,247 |
This crate can be used to define structures with accessors for particular bits or bit ranges. Useful for dealing with registers and protocols.
#![no_std]
-compatible out of the box.#[repr(packed, C)]
, each field has explicit bit ranges, rather
than relying on the ordering and size of other fields within the struct. While
specifying bit numbers may seem tedious, it can eliminate surprises, and it
usually corresponds directly to the way registers and protocols are defined in
datasheets.Into
] and [From
] implementations.bitfield
]. A [bitfield_without_debug
] macro is also available if you
want to provide your own debugging output.bitfield_accessors
].bitfield! {
// The structure will be a wrapper for a u32 value.
pub struct Example(u32) {
// Accessors for field `a` will refer to the first four least significant
// bits of the wrapped value, bits 0, 1, 2, and 3.
//
// Note that like normal Rust ranges:
// * `[0..4]` does not include bit 4
// * `[0..=4]` includes bit 4
//
// The accessors will be public, and will take/return the four bits as a `u8`.
[0..4] pub a: u8,
// No accessors cover bits `4..6`. This is legal and can be used for reserved
// bits. However, these bits will still affect equality for the struct as a
// whole.
// Accessors for field `b` will refer to the twelve bits starting at bit 6,
// but they will not be public. They will take/return the 12 bits as a `u16`.
[6..=17] b: u16,
// Note that this bit range overlaps with `b`. This is allowed.
[16..20] pub c: u8,
// Accessors for field `d` will take/return a boolean and refer to a single
// bit. Note that the `bool` is implied and not specified after the name.
[25] pub d,
// This will cover the 6 most significant bits of the wrapped value, but
// the getters will take/return a `SubFields` struct instead of `u8`. This is
// useful for nested bitfields, but the `A as B` syntax works for any `B`
// which implements `Into<A>` and `From<A>`.
[26..32] pub e: u8 as SubFields,
}
}
bitfield! {
// All accessors on this field use booleans and refer to single bits
pub struct SubFields(u8) {
[0] pub zero,
[1] pub one,
[2] pub two,
[3] pub three,
[4] pub four,
[5] pub five,
}
}
// The struct can be initialized with a u32 value
let x = Example(0xfa84_9e1b);
assert_eq!(x.a(), 0xb_u8);
assert_eq!(x.b(), 0x278_u16); // Private, but still can be used within the module
assert_eq!(x.c(), 0x4_u8);
assert_eq!(x.d(), true);
assert_eq!(x.e(), SubFields(0x3e_u8));
assert_eq!(x.e().zero(), false);
assert_eq!(x.e().five(), true);
// It can also be converted Into and From its underlying representation
let n: u32 = x.into();
let y: Example = n.into();
assert_eq!(n, 0xfa84_9e1b);
assert_eq!(x, y);
// Setters are all prefixed with `set_`. They have the same visibility as the getters.
let mut z = Example::default();
z.set_a(0xb);
z.set_b(0x278);
z.set_c(0x4);
z.set_d(true);
z.set_e(SubFields(0x3e));
assert_eq!(z, Example(0xfa04_9e0b));
// Reserved ranges influence equality, and they are all zero on `z`.
assert_ne!(z, x);
// Alternatively, you can use the `with_` methods, which return a new value instead
// of mutating in place.
let mut w = x
.with_a(0x6)
.with_b(0x9f3)
.with_c(0xd)
.with_d(false)
.with_e(SubFields(0x2b));
assert_eq!(w, Example(0xac8d_7cd6));
assert_eq!(x, Example(0xfa84_9e1b));
For lots more examples, see the Tartan OS project that this crate was spun off from.
Each bitfield wraps an underlying integer type. In the example above, Example(u32)
wraps a u32
. Bit numbers within the macro refer to the bits of the logical value,
starting from the least significant bit = 0. They are not dependent on the order of
the bytes of the u32
representation in memory, a.k.a. endianness.
The endianness of the underlying value is platform dependent. This is no different than any other integer value, and the context determines whether you need to worry about it.
u8
, then byte order is irrelevant.u32::from_be_bytes
] and [u64::to_le_bytes
], or a crate like
byteorder.I have been using this in my personal OS project for a while, and it meets my needs better than other options. But you may be interested in a few other crates:
pack_struct
's PrimitiveEnum
, see the
tartan-c-enum
crate.Add to your Cargo.toml:
[dependencies]
tartan-bitfield = 1.2.0
This is a pretty standard Rust library using Cargo.
cargo test --all-targets
cargo bench
cargo fmt
cargo clippy --all-targets
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
This README was generated from doc comments. Use cargo readme
to refresh it.