Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/duskmoon314/dmbf
Duskmoon's bitfield: yet another bitfield in rust
https://github.com/duskmoon314/dmbf
bitfield proc-macro rust
Last synced: 8 days ago
JSON representation
Duskmoon's bitfield: yet another bitfield in rust
- Host: GitHub
- URL: https://github.com/duskmoon314/dmbf
- Owner: duskmoon314
- License: mit
- Created: 2023-12-27T14:04:03.000Z (12 months ago)
- Default Branch: main
- Last Pushed: 2024-04-03T03:56:24.000Z (9 months ago)
- Last Synced: 2024-04-03T04:38:47.989Z (9 months ago)
- Topics: bitfield, proc-macro, rust
- Language: Rust
- Homepage:
- Size: 16.6 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# dmbf (Duskmoon's bitfield)
Yet another bitfield in Rust inspired by `svd2rust`'s generated code. I made
this because other crates not very suitable for my use case and I like making
(maybe uesless) wheels.You may find other crates more suitable for your use case:
- [bitfield](https://crates.io/crates/bitfield)
- [modular-bitfield](https://crates.io/crates/modular-bitfield)
- [bitfield-struct](https://crates.io/crates/bitfield-struct)## Usage
### An example of IPv4 header
Here's an example of representing IPv4 header:
```rust
#[bitfield]
pub struct Ipv4 {
#[bitfield(bits = 4)]
version: u8,
#[bitfield(bits = 4)]
ihl: u8,
#[bitfield(bits = 6)]
dscp: u8,
#[bitfield(bits = 2)]
ecn: u8,
#[bitfield(from = |v: u16| u16::from_be(v), into = |v: u16| u16::to_be(v))]
total_length: u16,
identification: u16,
#[bitfield(bits = 3, from_into, from = |v: u16| v as u8)]
flags: u8,
#[bitfield(bits = 13)]
fragment_offset: u16,
ttl: u8,
protocol: u8,
checksum: u16,#[bitfield(bits = 32, from = |v: u32| Ipv4Addr::from(u32::from_be(v)), into = |v: Ipv4Addr| u32::to_be(v.into()))]
src: Ipv4Addr,
#[bitfield(bits = 32, from = |v: u32| Ipv4Addr::from(u32::from_be(v)), into = |v: Ipv4Addr| u32::to_be(v.into()))]
dst: Ipv4Addr,
}
```Then you can use it like this:
```rust
let data: [u8; 20] = [
0x45, 0x00, 0x00, 0x28, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11,
0xb8, 0x0e, 0xc0, 0xa8, 0x00, 0x01, 0xc0, 0xa8, 0x00, 0xc7,
];let mut ipv4 = Ipv4::from(&data);
assert_eq!(ipv4.version().get(), 4);
ipv4.version_mut().set(5);
assert_eq!(ipv4.version().get(), 5);assert_eq!(ipv4.total_length().get(), 40);
assert_eq!(ipv4.src().get(), Ipv4Addr::new(192, 168, 0, 1));
assert_eq!(ipv4.dst().get(), Ipv4Addr::new(192, 168, 0, 199));
```### How it works
The `bitfield` attribute macro constructs a `FieldBlock` struct, adhering to
the following rules:- Each field is a `Field` where `T` must implement `FieldSpec` trait.
- `FieldSpec` has two associated types: `Ux` for the underlying integer type
and `Target` for the type we want to use.
- `FieldSpec` also has three associated constants:
- `DEFAULT` for resetting the field to default value.
- `MASK` for masking the field. This is useful in a hybrid field.
- `SHIFT` for shifting the field. This is useful in a hybrid field.
- The type `T` is constructed by:
- If `bits` is not specified, `T` is almost the same as the provided type.
- If `bits` is specified and is a multiple of 8, `Ux` is a `u8`, `u16`, `u32`
or `u64` depending on the number of bits.
- If `bits` is specified and is not a multiple of 8, a hybrid field will be
created by composing more than one fields into a `union`.It also constructs a struct like this:
```rust
struct Ipv4<'a> {
pub data: &'a [u8],
}impl<'a> core::ops::Deref for Ipv4<'a> {
type Target = FieldBlock;
fn deref(&self) -> &Self::Target {
unsafe { &*(self.data.as_ptr() as *const Self::Target) }
}
}impl<'a> core::ops::DerefMut for Ipv4<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(self.data.as_ptr() as *mut Self::Target) }
}
}
```Yes, I use `unsafe` to cast a `&[u8]` to a `&FieldBlock` and it allows me to
access the fields without implementing complex parsing logic.### attribute arguments
- `bits`: Number of bits to use for the field. If not specified, `::Ux` is used.
- `default`: Default value of the field. If not specified, `0` is used.
- `from_into: bool`: Whether to use `From` and `Into` to convert the field.
- `from` and `into`: Custom `From` and `Into` implementations