Multitrait
A lightweight, high-performance Rust library providing common traits for implementing multiformats types with zero-copy decoding and flexible encoding strategies.
Features
- ๐ High Performance: Optimized varint encoding with minimal allocations
- ๐ฆ Zero-Copy Decoding: Parse data without unnecessary copying
- ๐ฏ Type Safety: Validated newtypes for compile-time guarantees
- ๐ง Flexible Encoding: Three encoding strategies for different use cases
- ๐ no_std Support: Works in embedded and constrained environments
- ๐งต Thread-Safe: All traits are
Send + Syncsafe - ๐ Well-Documented: Comprehensive documentation with examples
- โ Thoroughly Tested: 150+ tests including property-based and concurrency tests
Installation
Add this to your Cargo.toml:
[]
= "1.0"
For no_std environments:
[]
= { = "1.0", = false }
Quick Start
use ;
// Encoding: Convert a value to compact varint bytes
let value = 42u32;
let encoded = value.encode_into;
println!;
// Decoding: Parse bytes back to original value
let = u32try_decode_from.unwrap;
assert_eq!;
assert!;
Core Traits
Encoding Traits
EncodeInto
Encode values into a compact varint Vec<u8>. Best for one-off encoding operations.
use EncodeInto;
let value = 1000u16;
let bytes = value.encode_into; // Allocates new Vec<u8>
EncodeIntoBuffer
Zero-allocation encoding into an existing buffer. Best for encoding multiple values or hot paths.
use EncodeIntoBuffer;
let mut buffer = Vecwith_capacity;
// Encode multiple values with minimal allocations
42u8.encode_into_buffer;
1000u16.encode_into_buffer;
100000u32.encode_into_buffer;
println!;
EncodeIntoArray
Stack-based encoding for no_std environments. Returns a fixed-size array with the actual length.
use EncodeIntoArray;
let = 42u8.encode_into_array;
assert_eq!;
// Maximum sizes known at compile time
assert_eq!;
Decoding Trait
TryDecodeFrom
Fallibly decode values from byte slices with zero-copy semantics. Returns the decoded value and remaining unconsumed bytes.
use TryDecodeFrom;
let bytes = vec!; // Varint encoding of 65535
let = u16try_decode_from.unwrap;
assert_eq!;
assert!;
// Sequential decoding 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 null/sentinel values.
use Null;
;
let null_id = null;
assert!;
let valid_id = MyId;
assert!;
TryNull
Fallible version of Null for types requiring validation.
use TryNull;
;
Validated Types
EncodedBytes
A validated newtype for varint-encoded byte sequences. Provides compile-time guarantees that bytes represent valid encodings.
use EncodedBytes;
// Validation happens at construction
let valid = vec!;
let encoded = try_from.unwrap;
// Invalid data is rejected
let invalid = vec!; // Truncated varint
assert!;
// Type system ensures valid data
Error Handling
All decode operations return a Result with a structured Error type:
use ;
let truncated = vec!; // Incomplete varint
match u16try_decode_from
Error Types
Error::UnsignedVarintDecode: Varint decoding failed (truncated data, invalid encoding, etc.)
All errors include source chains for debugging and support backtraces when the std feature is enabled.
Performance Guide
Encoding Performance
Choose the right encoding strategy for your use case:
-
EncodeInto- Good for one-off encodings- Single allocation per call
- Simple API
- Use when encoding individual values
-
EncodeIntoBuffer- Best for multiple values- Zero allocations when buffer has capacity
- Reusable buffer
- Use in hot paths or when encoding multiple values
-
EncodeIntoArray- Best for embedded systems- Zero heap allocations (stack only)
- Deterministic performance
- Use in
no_stdor real-time systems
Decoding Performance
- Zero allocations: Returns slice references to existing data
- Zero copying: No data duplication during decode
- Constant-time validation: Efficient varint format checking
Benchmark Results
Varint encoding is highly efficient:
- Values 0-127: 1 byte
- Values 128-16,383: 2 bytes
- Values 16,384-2,097,151: 3 bytes
- And so on...
Maximum encoded sizes:
u8,bool: 2 bytes maxu16: 3 bytes maxu32: 5 bytes maxu64,usize(64-bit): 10 bytes maxu128: 19 bytes max
Thread Safety
All traits and types in this crate are Send + Sync, making them safe to use in concurrent contexts.
Concurrency Patterns
All these patterns work safely:
use Arc;
use thread;
use ;
// Parallel encoding
let handles: =
.map
.collect;
// Shared read access
let data = new;
let handles: =
.map
.collect;
All operations are lock-free with no shared mutable state.
no_std Support
This crate works in no_std environments with alloc:
[]
= { = "1.0", = false }
Use EncodeIntoArray for heap-free encoding in embedded systems:
extern crate alloc;
use Vec;
use EncodeIntoArray;
// Stack-only encoding (no heap required for encoding)
let = 42u8.encode_into_array;
// Only allocate if you need to store it
let vec = Vecfrom;
Feature Flags
std(default): Enables standard library support- Enables
std::error::Errorimplementation - Enables backtrace support in errors
- Disable for
no_std:default-features = false
- Enables
Supported Types
All traits are implemented for:
bool: Encoded as 0 (false) or 1 (true)u8,u16,u32,u64,u128: Variable-length encodingusize: Platform-dependent (32-bit or 64-bit)
Examples
See the examples/ directory for complete examples:
basic.rs- Basic encoding and decodingerror_handling.rs- Error handling patternscustom_type.rs- Implementing traits for custom typesno_std.rs- Using the crate in no_std environments
Run examples with:
Testing
The crate includes 150+ tests:
- Unit tests for all trait implementations
- Property-based tests with proptest
- Concurrency tests for thread safety
- Security tests for malicious inputs
- Edge case tests
Run tests with:
Documentation
Generate and view the full API documentation:
License
Licensed under Apache-2.0. See LICENSE for details.
Contributing
Contributions are welcome! Please ensure:
- All tests pass (
cargo test) - Code is formatted (
cargo fmt) - No clippy warnings (
cargo clippy) - New features include tests and documentation