varing 0.14.0

Protobuf's varint encoding/decoding for LEB128 friendly types with full const context operations supports.
Documentation

Protobuf's varint encoding/decoding for LEB128 friendly types with full const context operations supports.

Installation

[dependencies]
varing = "0.14"

no_std is supported by disabling the default std feature:

[dependencies]
varing = { version = "0.14", default-features = false }

Quick Start

Encode and decode primitive integers as varints:

use varing::Varint;

// Encode
let mut buf = [0u8; u32::MAX_ENCODED_LEN.get()];
let len = 300u32.encode(&mut buf).unwrap();

// Decode
let (bytes_read, decoded) = u32::decode(&buf).unwrap();
assert_eq!(decoded, 300u32);
assert_eq!(bytes_read, len);

Signed integers use zigzag encoding, so small absolute values stay compact:

use varing::Varint;

let mut buf = [0u8; i64::MAX_ENCODED_LEN.get()];
let len = (-1i64).encode(&mut buf).unwrap();
assert_eq!(len.get(), 1); // -1 encodes to a single byte

Encode/decode sequences:

use varing::{Varint, encode_sequence, decode_sequence, encoded_sequence_len};

let values: Vec<u64> = (0..1024).collect();
let encoded_len = encoded_sequence_len(values.iter());
let mut buf = vec![0; encoded_len];

encode_sequence(values.iter(), &mut buf).unwrap();
let (_bytes_read, decoded) = decode_sequence::<u64, Vec<u64>>(&buf).unwrap();
assert_eq!(decoded, values);

All encoding and decoding functions are available in const context as free functions:

use varing::{encode_u32_varint, decode_u32_varint, encoded_u32_varint_len};

const ENCODED: varing::utils::Buffer<6> = encode_u32_varint(300);

const VALUE: u32 = {
    let Ok((_len, val)) = decode_u32_varint(ENCODED.as_slice()) else { panic!() };
    val
};

assert_eq!(VALUE, 300);
assert_eq!(ENCODED.len(), encoded_u32_varint_len(300).get());

Optional Features

The following feature flags enable varint support for types from third-party crates. Multiple versions of the same crate can be enabled simultaneously.

Feature Crate Notes
arbitrary-int (= v2) arbitrary-int v1 Unsigned types + signed types (u1..u127, i1..i127)
arbitrary-int_1 arbitrary-int v1 Unsigned (u1..u127)
bnum (= v0.13) bnum
chrono (= v0.4) chrono Not fully const-compatible
chrono-tz (= v0.10) chrono-tz
ethereum-types (= v0.16) ethereum-types
ethereum-types_0_16 ethereum-types v0.16
ethereum-types_0_15 ethereum-types v0.15
float8 (= v0.4) float8
half (= v2) half
num-complex (= v0.4) num-complex
num-rational (= v0.4) num-rational
primitive-types (= v0.14) primitive-types
primitive-types_0_14 primitive-types v0.14
primitive-types_0_13 primitive-types v0.13
ruint (= v1) ruint Not const-compatible
time (= v0.3) time

Benchmarks

varing's varint encode/decode is competitive with the fastest Rust varint crates and at parity with prost — protobuf's own varint implementation.

The tables below show single-value and bulk (1000-value sweep) timings for u64 (all protobuf varints are u64), lower is better. Figures are the median of one cargo bench run on Apple Silicon (aarch64) and are only meaningful relative to each other on the same machine — reproduce with cargo bench.

Encode u64

value varing prost integer-encoding unsigned-varint leb128
1 byte 527 ps 1.20 ns 542 ps 874 ps 429 ps
10 bytes 2.16 ns 6.00 ns 2.14 ns 2.34 ns 2.14 ns
mixed ×1000 2.44 µs 2.29 µs 2.51 µs 3.91 µs 9.13 µs

Decode u64

value varing prost integer-encoding unsigned-varint leb128
1 byte 386 ps 749 ps 775 ps 573 ps 524 ps
10 bytes 1.96 ns 1.71 ns 2.76 ns 2.28 ns 5.35 ns
mixed ×1000 2.06 µs 2.29 µs 1.86 µs 2.04 µs 3.44 µs

On the bulk sweep varing is within ~10% of prost in both directions (faster on decode, slightly slower on encode); on single values it is substantially faster than prost, whose figures include its bytes::BufMut API overhead. prost appears only in the u64 groups because that is the only varint width it exposes; leb128 is u64-only for unsigned values and uses a different signed format, so it is excluded from the signed groups. The full suite in benches/varint.rs also covers u16, u32, u128, and zigzag i64.

Testing

  • Property-based testing with quickcheck for all types (including optional features).
  • Fuzz testing with cargo fuzz for all types.

License

varing is under the terms of both the MIT license and the Apache License (Version 2.0).

See LICENSE-APACHE, LICENSE-MIT for details.

Copyright (c) 2026 Al Liu.