multi-trait
Common traits for multiformats types in Rust. The crate gives encoding,
decoding, and null value traits with zero-copy decoding and no_std support.
Features
- Varint encoding with minimal allocations.
- Zero-copy decoding.
TryDecodeFromreturns the remaining bytes. - Zero-allocation encoding.
EncodeIntoBufferreuses an existing buffer. - Stack-based encoding.
EncodeIntoArrayforno_stdand embedded systems. no_stdsupport withalloc.- Validated newtype.
EncodedBytesgives type-level guarantees. #![deny(unsafe_code)]set at the crate root.- All types are
Send + Sync. - 155 tests: unit, property-based, security, concurrency, and round-trip.
Install
Add this to your Cargo.toml:
[]
= "1.1"
For no_std environments:
[]
= { = "1.1", = false }
MSRV: Rust 1.85 (Edition 2024).
Quick Start
use ;
// Encode a value to varint bytes
let value = 42u32;
let encoded = value.encode_into;
println!;
// Decode the bytes back to the value
let = u32try_decode_from.unwrap;
assert_eq!;
assert!;
Core Traits
Encoding Traits
EncodeInto
Encode a value into a varint Vec<u8>. Use this for one-off encoding.
use EncodeInto;
let value = 1000u16;
let bytes = value.encode_into; // Allocates a new Vec<u8>
EncodeIntoBuffer
Encode values into an existing buffer with no allocation. Use this in hot paths or when you encode multiple values.
use EncodeIntoBuffer;
let mut buffer = Vecwith_capacity;
42u8.encode_into_buffer;
1000u16.encode_into_buffer;
100_000u32.encode_into_buffer;
println!;
EncodeIntoArray
Encode a value into a stack-allocated array. Use this in no_std or
real-time systems.
use EncodeIntoArray;
let = 42u8.encode_into_array;
assert_eq!;
assert_eq!;
Decoding Trait
TryDecodeFrom
Decode a value from a byte slice. Returns the value and the remaining bytes. No allocation occurs.
use TryDecodeFrom;
let bytes = vec!; // Varint encoding of 65535
let = u16try_decode_from.unwrap;
assert_eq!;
assert!;
// Decode multiple values from one buffer
let bytes = vec!;
let = u8try_decode_from.unwrap;
let = u8try_decode_from.unwrap;
let = u8try_decode_from.unwrap;
assert_eq!;
Null Value Traits
Null
Define and check for a null or sentinel value.
use Null;
;
let null_id = null;
assert!;
let valid_id = MyId;
assert!;
TryNull
Fallible version of Null. Use it for types that need validation.
use TryNull;
;
Validated Types
EncodedBytes
A validated newtype for varint-encoded byte sequences. Construction checks that the bytes are a valid encoding.
use EncodedBytes;
let valid = vec!;
let encoded = try_from.unwrap;
let invalid = vec!; // Truncated varint
assert!;
Error Handling
All decode operations return Result with a structured Error type:
use ;
let truncated = vec!; // Incomplete varint
match u16try_decode_from
Error Types
The Error enum is #[non_exhaustive]. It has these variants:
UnsignedVarintDecode: Varint decoding failed. The cause can be truncated data or an invalid encoding.InsufficientData: The input slice does not have enough bytes to decode the requested type.InvalidEncoding: The data is structurally invalid. This variant is for future use and custom validation.
All errors give source chains for debugging. Backtraces are available when
the std feature is on.
Performance Guide
Encoding Performance
Pick the encoding strategy for your use case:
EncodeInto— One allocation per call. Use this for one-off encodings.EncodeIntoBuffer— Zero allocations when the buffer has capacity. Use this in hot paths or when you encode multiple values.EncodeIntoArray— Zero heap allocations. Use this inno_stdor real-time systems.
Decoding Performance
- Zero allocations. Returns slice references to the input data.
- No data copy during decode.
- Efficient varint format checking.
Encoded Sizes
Varint encoding uses 1 to 10 bytes for integers. The size depends on the value.
- Values 0 to 127: 1 byte.
- Values 128 to 16,383: 2 bytes.
- Values 16,384 to 2,097,151: 3 bytes.
Maximum encoded sizes by type:
u8,bool: 2 bytes.u16: 3 bytes.u32: 5 bytes.u64,usize(64-bit): 10 bytes.u128: 19 bytes.
Thread Safety
All traits and types in this crate are Send + Sync. You can use them in
concurrent contexts.
All operations are lock-free. No mutable state is shared.
no_std Support
The crate works in no_std environments with alloc:
[]
= { = "1.1", = false }
Use EncodeIntoArray for heap-free encoding in embedded systems:
extern crate alloc;
use Vec;
use EncodeIntoArray;
let = 42u8.encode_into_array;
let vec = Vecfrom;
Feature Flags
std(default). Enables standard library support. It enablesstd::error::Errorimplementation and backtrace support in errors. Disable it forno_stdwithdefault-features = false. The crate needsallocwhenstdis off.
Supported Types
All traits are implemented for:
bool: Encoded as 0 (false) or 1 (true).u8,u16,u32,u64,u128: Variable-length varint encoding.usize: Platform-dependent (32-bit or 64-bit).[u8; N]: Fixed-length byte arrays.EncodeIntoencodes the raw bytes without a varint prefix.TryDecodeFromreads exactly N bytes. Use this for BLS share identifiers and other fixed-size binary data.
EncodeIntoBuffer and EncodeIntoArray are implemented for bool,
u8, u16, u32, u64, u128, and usize. They do not support
[u8; N].
Examples
See the examples/ directory for complete examples:
basic.rs— Basic encoding and decoding.error_handling.rs— Error handling patterns.custom_type.rs— Implement the traits for custom types.no_std.rs— Use the crate inno_stdenvironments.
Run an example:
Testing
The crate has 155 tests: unit, property-based, concurrency, security, and edge case tests.
Run all tests:
Documentation
Generate and view the API documentation:
License
Licensed under Apache-2.0. See LICENSE for details.
Contributing
Contributions are welcome. Before you submit a change, make sure:
- All tests pass (
cargo test). - The code is formatted (
cargo fmt). - No clippy warnings (
cargo clippy). - New features include tests and documentation.