bitframe
Describe your packet's bit fields in a struct. Get zero-copy parsing for free.
use *;
let = parse?;
assert_eq!;
That's it. You describe the layout. bitframe does the bit math.
Status: v0.1.0 — parsing is implemented. Writers and mutable views are planned for future releases.
The Problem
Bit-packed protocols are everywhere: satellite telemetry, CAN bus, ADS-B, sensor data. Parsing them by hand means shift/mask code that's hard to review and produces silent corruption — not crashes, just quietly wrong values.
// Can you spot the bug? Neither can your reviewer.
let apid = | bytes as u16;
// Is the mask 0x07 or 0x0F? Is this bits 5-15 or 4-15?
// You won't know until the wrong satellite gets a command.
The Solution
The struct is the spec. If you can read the struct, you understand the protocol.
// Total: 48 bits = 6 bytes, verified at compile time
Parsing gives you a zero-copy view — a thin wrapper around &[u8] that reads fields on demand:
// Parse: zero allocation, zero copying
let = parse?;
// Read fields — they read like English
if header.is_telecommand // "is this header telecommand?"
if header.has_secondary // "does this header have a secondary?"
// Compare directly with numbers — no .value() needed
assert_eq!;
assert_eq!;
// If the buffer is too short, you get a clear error — not garbage
// Err(Error::TooShort { needed_bytes: 6, have_bytes: 2 })
Start Fast
Create src/main.rs:
use *;
# tag=10, flags=5, length=10
How It Works
Raw bytes: [0xA0, 0x1F, 0xC0, 0x42, 0x00, 0x0A]
Byte 0 Byte 1 Byte 2 Byte 3 Byte 4-5
+-----------+---+-----------+----+----------+-------------------+
| ver 3b |T|S| APID 11b |SF 2|seq_ct 14b| pkt_len 16b |
+-----------+---+-----------+----+----------+-------------------+
CcsdsPrimaryHeaderRef::parse(&bytes) gives you:
.version() -> 5 reads bits 0..3
.is_telecommand() -> false reads bit 3
.has_secondary() -> false reads bit 4
.apid() -> 31 reads bits 5..16
.seq_flags() -> 3 reads bits 16..18
.seq_count() -> 66 reads bits 18..32
.pkt_len() -> 10 reads bits 32..48
No heap allocation. No struct copying. The view borrows your &[u8] — like &str borrows a String.
Features
| Flag | Enables | Requires |
|---|---|---|
std (default) |
std::error::Error on errors |
std |
| (none) | Everything else — views, parsing, errors | core only |
When to Use bitframe
| If you need... | Use |
|---|---|
| Parse variable-length formats (JSON, protobuf, custom TLVs) | serde, binrw, nom |
| In-memory bitfields (register getters/setters on an integer) | bilge, modular-bitfield, bitfield-struct |
| Byte-aligned zero-copy views | zerocopy, binary-layout |
Bit-level fixed-size headers parsed from &[u8] as a borrowed view |
bitframe |
Real-World Use Cases
Space telemetry (CCSDS) — Every satellite uses 6-byte headers with fields at 3, 1, 1, 11, 2, 14, and 16 bits.
Automotive (CAN bus) — CAN signals live at arbitrary bit positions within 8-byte frames. Manual parsing is a constant source of bugs.
Aviation (ADS-B/ARINC 429) — Aircraft transponder messages are 56 or 112 bits with fields at 5-bit, 3-bit, and 24-bit boundaries. ARINC 429 words pack reversed-bit labels, SDI, data, and parity into 32 bits.
Embedded sensors — ADC readings packed as 12-bit values, status codes as 4-bit nibbles. Self-documenting with bitframe.
Industrial (EtherCAT) — Process Data Images map device I/O to arbitrary bit offsets within shared memory buffers.
What You Can and Cannot Do
Can:
- Declare fixed-size bit-packed layouts as plain Rust structs
- Parse zero-copy views from
&[u8]with on-demand field access - Use on
no_std/no_alloctargets (embedded, WASM) - Compare bit-sized types directly with integers (
u11 == u16)
Roadmap:
- Encode fields into
&mut [u8]with range validation (v0.2) - Mutate individual fields in-place via
FooRefMut(v0.3) - Nest one
#[bitframe]struct inside another (v0.3)
Cannot:
- Parse variable-length or self-describing formats (use
deku,binrw, ornom) - Replace in-memory register bitfields (use
bilgeorbitfield-struct) - Handle runtime-defined layouts or reflection (fixed at compile time)
- Parse from streams — bitframe operates on
&[u8]slices
Why Rely On It
#![forbid(unsafe_code)]on all crates — no unsafe anywhere- Zero runtime dependencies — only proc-macro compile-time deps
- Clippy pedantic + nursery enabled
cargo denyenforced — no unmaintained deps, no license issues- Tests use behave BDD framework — specs read like protocol documentation
- Reference implementation test vectors from spacepackets (CCSDS), The 1090MHz Riddle (ADS-B), and SocketCAN (CAN/J1939)
- MSRV 1.75 tested in CI
- Dual feature-set CI:
--all-featuresand--no-default-features - Roadmap includes Kani formal verification and property-based testing
Documentation
- Vision — Why this exists
- Design — Planned API shape
- Developer Experience — DX standards
- Roadmap — Release plan v0.1 -> v1.0
- Landscape — Ecosystem positioning
- Audit — Quality gates and acceptance criteria
- Release — How to publish a new version
- Contributing — How to contribute
Security
See SECURITY.md for vulnerability reporting.
License
Licensed under the Apache License, Version 2.0. See LICENSE.