Skip to content

Commit 3f2f0af

Browse files
committed
📝 Extend and simplify docs
1 parent 0a9129c commit 3f2f0af

File tree

3 files changed

+190
-67
lines changed

3 files changed

+190
-67
lines changed

README.md

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,63 @@ Add this to your `Cargo.toml`:
2323
bitfield-struct = "0.3"
2424
```
2525

26-
## Example
26+
## Basics
27+
28+
Let's begin with a simple example.
29+
Suppose we want to store multiple data inside a single Byte, as shown below:
30+
31+
<table>
32+
<tr>
33+
<td>7</td>
34+
<td>6</td>
35+
<td>5</td>
36+
<td>4</td>
37+
<td>3</td>
38+
<td>3</td>
39+
<td>1</td>
40+
<td>0</td>
41+
</tr>
42+
<tr>
43+
<td>P</td>
44+
<td colspan="2">Level</td>
45+
<td>S</td>
46+
<td colspan="4">Kind</td>
47+
</tr>
48+
</table>
49+
50+
This crate generates a nice wrapper type that makes it easy to do this:
2751

28-
The example below shows the main features of the macro and how to use them.
52+
```rust
53+
/// Define your type like this with the bitfield attribute
54+
#[bitfield(u8)]
55+
struct MyByte {
56+
/// The first field occupies the least significant bits
57+
#[bits(4)]
58+
kind: usize,
59+
/// Booleans are 1 bit large
60+
system: bool,
61+
/// The bits attribute specifies the bit size of this field
62+
#[bits(2)]
63+
level: usize,
64+
/// The last field spans over the most significant bits
65+
present: bool
66+
}
67+
// The macro creates three accessor functions for each field:
68+
// <name>, with_<name> and set_<name>
69+
let my_byte = MyByte::new()
70+
.with_kind(15)
71+
.with_system(false)
72+
.with_level(3)
73+
.with_present(true);
74+
75+
assert!(my_byte.present());
76+
```
77+
78+
## Features
79+
80+
Additionally, this crate has a few useful features, which are shown here in more detail.
81+
82+
The example below shows how attributes are carried over and how signed integers, padding, and custom types are handled.
2983

3084
```rust
3185
/// A test bitfield with documentation

src/lib.rs

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,72 @@
33
//! Procedural macro for bitfields that allows specifying bitfields as structs.
44
//! As this library provides a procedural-macro it has no runtime dependencies and works for `no-std`.
55
//!
6-
//! ## Example
6+
//! - Supports bool flags, raw integers, and every custom type convertible into integers (structs/enums)
7+
//! - Ideal for driver/OS/embedded development (defining HW registers/structures)
8+
//! - Generates minimalistic, pure, safe rust functions
9+
//! - Compile-time checks for type and field sizes
10+
//! - Rust-analyzer friendly (carries over documentation to accessor functions)
11+
//! - Exports field offsets and sizes as constants (useful for const asserts)
12+
//! - Generation of `fmt::Debug`
713
//!
8-
//! The example below shows the main features of the macro and how to use them.
14+
//! ## Basics
15+
//!
16+
//! Let's begin with a simple example.</br>
17+
//! Suppose we want to store multiple data inside a single Byte, as shown below:
18+
//!
19+
//! <table>
20+
//! <tr>
21+
//! <td>7</td>
22+
//! <td>6</td>
23+
//! <td>5</td>
24+
//! <td>4</td>
25+
//! <td>3</td>
26+
//! <td>3</td>
27+
//! <td>1</td>
28+
//! <td>0</td>
29+
//! </tr>
30+
//! <tr>
31+
//! <td>P</td>
32+
//! <td colspan="2">Level</td>
33+
//! <td>S</td>
34+
//! <td colspan="4">Kind</td>
35+
//! </tr>
36+
//! </table>
37+
//!
38+
//! This crate is able to generate a nice wrapper type that makes it easy to do this:
39+
//!
40+
//! ```
41+
//! # use bitfield_struct::bitfield;
42+
//! /// Define your type like this with the bitfield attribute
43+
//! #[bitfield(u8)]
44+
//! struct MyByte {
45+
//! /// The first field occupies the least significant bits
46+
//! #[bits(4)]
47+
//! kind: usize,
48+
//! /// Booleans are 1 bit large
49+
//! system: bool,
50+
//! /// The bits attribute specifies the bit size of this field
51+
//! #[bits(2)]
52+
//! level: usize,
53+
//! /// The last field spans over the most significant bits
54+
//! present: bool
55+
//! }
56+
//! // The macro creates three accessor functions for each field:
57+
//! // <name>, with_<name> and set_<name>
58+
//! let my_byte = MyByte::new()
59+
//! .with_kind(15)
60+
//! .with_system(false)
61+
//! .with_level(3)
62+
//! .with_present(true);
63+
//!
64+
//! assert!(my_byte.present());
65+
//! ```
66+
//!
67+
//! ## Features
68+
//!
69+
//! Additionally, this crate has a few useful features, which are shown here in more detail.
70+
//!
71+
//! The example below shows how attributes are carried over and how signed integers, padding, and custom types are handled.
972
//!
1073
//! ```
1174
//! # use bitfield_struct::bitfield;
@@ -439,7 +502,7 @@ fn bits(attrs: &[syn::Attribute], ty: &syn::Type) -> syn::Result<(TypeClass, usi
439502
if bits <= size {
440503
Ok((class, bits))
441504
} else {
442-
Err(syn::Error::new(tokens.span(), "overflowing member type"))
505+
Err(syn::Error::new(tokens.span(), "overflowing field type"))
443506
}
444507
} else {
445508
Ok((TypeClass::Other, bits))

tests/test.rs

Lines changed: 68 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,71 +2,58 @@ use std::fmt;
22

33
use bitfield_struct::bitfield;
44

5-
/// A test bitfield with documentation
6-
#[bitfield(u64)]
7-
struct MyBitfield {
8-
/// defaults to 16 bits for u16
9-
int: u16,
10-
/// interpreted as 1 bit flag
11-
flag: bool,
12-
/// custom bit size
13-
#[bits(1)]
14-
tiny: u8,
15-
/// sign extend for signed integers
16-
#[bits(13)]
17-
negative: i16,
18-
/// supports any type that implements `From<u64>` and `Into<u64>`
19-
#[bits(16)]
20-
custom: CustomEnum,
21-
/// public field -> public accessor functions
22-
#[bits(12)]
23-
pub public: usize,
24-
/// padding
25-
#[bits(5)]
26-
_p: u8,
27-
/// zero-sized members are ignored
28-
#[bits(0)]
29-
_completely_ignored: String,
30-
}
5+
#[test]
6+
fn members() {
7+
/// A test bitfield with documentation
8+
#[bitfield(u64)]
9+
struct MyBitfield {
10+
/// defaults to 16 bits for u16
11+
int: u16,
12+
/// interpreted as 1 bit flag
13+
flag: bool,
14+
/// custom bit size
15+
#[bits(1)]
16+
tiny: u8,
17+
/// sign extend for signed integers
18+
#[bits(13)]
19+
negative: i16,
20+
/// supports any type that implements `From<u64>` and `Into<u64>`
21+
#[bits(16)]
22+
custom: CustomEnum,
23+
/// public field -> public accessor functions
24+
#[bits(12)]
25+
pub public: usize,
26+
/// padding
27+
#[bits(5)]
28+
_p: u8,
29+
/// zero-sized members are ignored
30+
#[bits(0)]
31+
_completely_ignored: String,
32+
}
3133

32-
/// A custom enum
33-
#[derive(Debug, PartialEq, Eq)]
34-
#[repr(u64)]
35-
enum CustomEnum {
36-
A = 0,
37-
B = 1,
38-
C = 2,
39-
}
40-
impl From<u64> for CustomEnum {
41-
fn from(value: u64) -> Self {
42-
match value {
43-
0 => Self::A,
44-
1 => Self::B,
45-
_ => Self::C,
46-
}
34+
/// A custom enum
35+
#[derive(Debug, PartialEq, Eq)]
36+
#[repr(u64)]
37+
enum CustomEnum {
38+
A = 0,
39+
B = 1,
40+
C = 2,
4741
}
48-
}
49-
impl From<CustomEnum> for u64 {
50-
fn from(value: CustomEnum) -> Self {
51-
value as _
42+
impl From<u64> for CustomEnum {
43+
fn from(value: u64) -> Self {
44+
match value {
45+
0 => Self::A,
46+
1 => Self::B,
47+
_ => Self::C,
48+
}
49+
}
5250
}
53-
}
54-
55-
/// We have a custom debug implementation -> opt out
56-
#[bitfield(u64, debug = false)]
57-
#[derive(PartialEq, Eq, Default)]
58-
struct Full {
59-
data: u64,
60-
}
61-
62-
impl fmt::Debug for Full {
63-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64-
write!(f, "0x{:x}", self.data())
51+
impl From<CustomEnum> for u64 {
52+
fn from(value: CustomEnum) -> Self {
53+
value as _
54+
}
6555
}
66-
}
6756

68-
#[test]
69-
fn members() {
7057
let mut val = MyBitfield::new()
7158
.with_int(3 << 15)
7259
.with_flag(true)
@@ -100,8 +87,15 @@ fn members() {
10087

10188
#[test]
10289
fn attrs() {
90+
/// We have a custom debug implementation -> opt out
91+
#[bitfield(u64)]
92+
#[derive(PartialEq, Eq, Default)]
93+
struct Full {
94+
data: u64,
95+
}
96+
10397
let full = Full::default();
104-
assert_eq!(full, Full::new());
98+
assert_eq!(full.0, Full::new().0);
10599

106100
let full = Full::new().with_data(u64::MAX);
107101
assert_eq!(full.data(), u64::MAX);
@@ -110,6 +104,18 @@ fn attrs() {
110104

111105
#[test]
112106
fn debug() {
113-
let full = Full::default();
107+
/// We have a custom debug implementation -> opt out
108+
#[bitfield(u64, debug = false)]
109+
struct Full {
110+
data: u64,
111+
}
112+
113+
impl fmt::Debug for Full {
114+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115+
write!(f, "0x{:x}", self.data())
116+
}
117+
}
118+
119+
let full = Full::new().with_data(123);
114120
println!("{full:?}");
115121
}

0 commit comments

Comments
 (0)