base16
Fast, no_std-friendly hexadecimal (base16) encoding and decoding for Rust
Repository Health
Technical Analysis
base16 is a Rust library for encoding and decoding hexadecimal (base16) data, written with an emphasis on performance. It provides a small, focused API covering both allocating helpers that return a fresh String or Vec, and allocation-free functions that write directly into caller-provided buffers.
The crate is fully no_std compatible through opt-in alloc and std feature flags, so it can be used everywhere from embedded firmware to server code, with configurable upper- or lowercase output.
What You Get
- Encoding functions for both uppercase and lowercase hex output
- Decoding back to raw bytes with descriptive error reporting
- Allocation-free slice APIs (encode_config_slice / decode_slice) for hot paths
- no_std support via opt-in alloc and std feature flags
Common Use Cases
- Rendering binary hashes, keys, or identifiers as readable hex strings
- Parsing hex-encoded input back into byte buffers
- Encoding/decoding in embedded or no_std environments without a global allocator
Under The Hood
Architecture - The entire crate lives in a single src/lib.rs (~700 lines) organized around a small set of public functions plus internal helpers like encode_slice_raw and encoded_size. Encoding uses a lookup table (HEX_LOWER/HEX_UPPER) and writes into MaybeUninit buffers to avoid redundant zeroing, then transmutes to an initialized Vec/String only after fully writing output.
Tech Stack - Pure Rust with edition 2021 and rust-version 1.60. It has zero runtime dependencies; the only optional surface is the alloc crate, gated behind the alloc feature, and std behind the std feature. A benchmarks and fuzz crate live in the Cargo workspace.
Code Quality - The code denies missing docs, documents each function’s allocation and feature requirements in a table, and carefully isolates unsafe blocks (MaybeUninit handling, from_utf8_unchecked) with safety comments. A dedicated tests/ directory plus a fuzz target back the implementation.
API Design - The public surface is intentionally tiny and predictable: encode_lower/encode_upper for the common case, and encode_config/encode_config_slice/decode_slice for control over allocation. Naming is consistent and the README’s usage examples get a caller productive in a few lines.