bitkit
High-performance, width-aware bit manipulation around a single
Bits<T>newtype.
Common bit-twiddling idioms get a typed, named, checked equivalent:
// before // after
& ! up?
& 0b1111 new.extract?
& 1 == 1 new.has_bit?
x & x.wrapping_neg new.isolate_lowest_set_bit
| encode_2d
unsafe new.gather
Why bitkit
- Safer. No panics on out-of-range bit indexes, no silent
truncation. Every fallible operation returns
Result<_, BitError>, so you can?-propagate naturally. - Faster on modern hardware. On x86-64 with BMI2 (Intel Haswell or
newer, AMD Zen 3 or newer),
gatherandscattercompile down to a single instruction (PEXT/PDEP); on other targets they fall back to a portable, safe loop. Performance is measured at parity with rawunsafeBMI2 wrappers — see BENCHMARKS.md. - Easier to read in review. Names like
isolate_lowest_set_bitdescribe what the trick does instead of obscuring it asx & -x. - Embedded-friendly.
#![no_std], zero runtime dependencies, MSRV Rust 1.74. The onlyunsafein the crate lives in one isolated internal module that uses BMI2 intrinsics. - Built-in spatial indexing. The
bitkit::mortonmodule ships Morton (Z-order) curve encode and decode for quadtrees, GPU textures, and range queries — 83× faster than themorton-encodingcrate on BMI2 hardware and 8.4× faster on portable SWAR.
Install
[]
= "3"
For no_std:
= { = "3", = false }
What it looks like
Bit fields
Extract, insert, or replace a contiguous run of bits using a Rust
Range (or a (start, end) tuple):
use *;
let header = new;
let version = header.extract?; // -> Bits::<u8>::new(0b0100)
let ihl = header.extract?; // -> Bits::<u8>::new(0b0101)
let packed = new
.insert?
.insert?; // -> 0b0100_0101
Iterators
Walk the set bits, the zero bits, or every subset of a mask:
let mask = new;
let indexes: = mask.set_bits.collect; // [0, 1, 3]
// Every subset of a bitmask, in 2^popcount(mask) steps:
for subset in mask.submasks
Binary protocol parsing
bitkit::bytes reads endian-aware integers from a &[u8]; Bits::extract
peels off the fields:
let buf = ;
let len = read_u16_be?; // 0x1234
let flags = new.extract?; // top 3 bits
Hardware-accelerated bit gather
Pull a non-contiguous set of bits out of a word and pack them together, in one instruction on capable hardware:
let v = new;
let mask = new;
let packed = v.gather; // -> Bits::<u32>::new(0b1111)
Morton (Z-order) curves
Interleave the bits of two or three coordinates into a single integer key — the standard trick behind quadtrees and Z-order indexing:
let z = encode_2d; // -> 37247404
assert_eq!;
Flag sets
A lightweight wrapper for ad-hoc flag manipulation where the bit positions come from data rather than from a fixed name list:
const READ: u32 = 1 << 0;
const WRITE: u32 = 1 << 1;
let mut f = empty;
f.enable;
assert!;
What this crate is not
- Not
bitvec. It does not store arbitrary-length bit sequences or expose bit-precise references. - Not
bitflags.Flags<T>is for ad-hoc manipulation where bit positions are data; for fixed named sets, usebitflags. - Not a serialization framework. For declarative binary parsing, use
dekuon top.
Modules
| module | purpose |
|---|---|
[Bits<T>] |
The primary type: bit queries, masks, fields, popcount, gather/scatter. |
[Flags<T>] |
Generic flag-set newtype. |
[align] |
Power-of-two alignment over usize. |
[bytes] |
Read/write integers from &[u8] with explicit endianness. |
[morton] |
Z-order curve encode / decode (2D, 3D). |
[mod@format] |
Allocation-free grouped-binary Display. |
[explain] (feature) |
Educational metadata for common bit hacks. |
Feature flags
| flag | default | purpose |
|---|---|---|
std |
yes | std::error::Error for BitError. |
alloc |
yes | Allocation-backed helpers in optional modules. |
explain |
no | Educational metadata for common bit hacks. |
runtime-detect |
no | Use is_x86_feature_detected! at runtime to pick the BMI2 path. |
Examples
Performance
| benchmark | x86 BMI2 | ARM SWAR |
|---|---|---|
Bits::gather / scatter vs bitintr (raw unsafe) |
tied | 1.6× faster |
bitkit::morton::encode_2d vs morton-encoding |
83× faster | 8.4× faster |
Bits::extract, Bits::count_ones vs inline |
tied | tied |
Bits::set_bit vs bitvec::set |
2.0× faster | 1.6× faster |
Full table, methodology, and reproduction recipe in BENCHMARKS.md.
License
MIT — see LICENSE or https://opensource.org/licenses/MIT.