Expand description
§tinyklv - KLV framework in Rust
A derive-macro framework for encoding and decoding Key-Length-Value (KLV)
binary streams, built on winnow parser combinators.
§What is KLV?
KLV is a generic Tag-Length-Value (TLV) framing pattern: every field in a byte stream is prefixed by a key identifying it and a length giving its size. It is the backbone of telemetry packets, video metadata streams, IoT sensor framing, and most custom binary protocols that need to evolve without breaking older parsers.
tinyklv is protocol-agnostic. It ships no baked-in standards - you declare
your keys, your length encoding, your sentinel, and the codec for each field
via attributes on a struct. The derive macro generates the encoder/decoder trait
implementations; you control the schema.
§Quick Start
cargo add tinyklvuse tinyklv::Klv;
use tinyklv::prelude::*;
use tinyklv::dec::binary as decb;
use tinyklv::enc::binary as encb;
#[derive(Klv, Debug, PartialEq)]
#[klv(
stream = &[u8],
sentinel = b"\x47\x48",
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize,
enc = encb::u8_from_usize),
)]
struct Heartbeat {
#[klv(
key = 0x01,
dec = decb::u8,
enc = *encb::u8,
)]
sequence: u8,
#[klv(
key = 0x02,
dec = decb::be_u16,
enc = *encb::be_u16,
)]
temperature_centideg: u16,
}
fn main() {
let original = Heartbeat {
sequence: 42,
temperature_centideg: 2350,
};
let frame = original.encode_frame();
let decoded = Heartbeat::decode_frame(
&mut frame.as_slice()
).unwrap();
assert_eq!(decoded, original);
}Full annotated version: examples/01_hello_world.rs.
§Feature Highlights
#[derive(Klv)]generates encode and decode in one pass- Built-in codecs: binary (native/BE/LE for
u8..u128,i8..i128,f32/f64), BER length, BER-OID keys, UTF-8 / UTF-16 / ASCII strings - Sentinel seeking - resync on noisy byte streams
- Streaming partial packets -
::decoder(),iter(),next(), andDecodePartial - Repeated decode with user-defined break conditions
- Nested
Klvstructs - compose packets from sub-packets - Generic structs and lifetimes supported
Option<T>fields, per-field and per-container defaults,trait_fallback,deny_unknown_keys- Stream type is user-selected - any
winnow::Streamworks
§Traits
| Trait | Purpose | Derived? |
|---|---|---|
DecodeValue<S> | Decode value body from an unframed slice | yes |
DecodeFrame<S> | Seek sentinel, read length, subslice, then decode | yes |
EncodeValue<O> | Encode the value body (KLV triples, no frame header) | yes |
EncodeFrame<O> | Encode sentinel + length + value body | yes |
DrainFrames<S> | Decode a sentinel-framed stream into Vec<T> | yes |
DecodePartial<S> | Streaming-aware decode returning Packet<T, P> | yes |
Decoder<P, S> | Owned-buffer streaming decoder with feed, iter, and next | yes |
BreakCondition<S> | Per-(key, len) stop predicate for decode loops | no |
§Documentation
§Contributing
Issues and pull requests welcome at
https://github.com/arpadav/tinyklv. Run cargo test --all and
cargo clippy --all-targets -- -D warnings before opening a PR.
§License
Licensed under the MIT License. See LICENSE for details.
§Support
If tinyklv is useful to you:
- Buy Me a Coffee
- Bitcoin:
bc1q5stdywthj254agv80s5gky6440xy73cpqgv0q7Author: aav
Re-exports§
Modules§
- codecs
- Codec Naming Conventions
- decoder
- Streaming KLV decoder
- prelude
- Convenience re-export of all traits and parser primitives needed to work with KLV streams
- traits
- Trait Architecture
Macros§
- cast
- Sets precision of a parsed value
- cast_
enc - Encode counterpart of
cast!. Casts to data type, then encodes. - scale
- Scales a parsed value of some predefined precision
- scale_
enc - Encode counterpart of
scale!. Divides by scale factor, casts to data type, then encodes. - scale_
offset_ enc - Encode counterpart of
scale!with offset. Subtracts offset, divides by scale, casts to data type, then encodes.
Type Aliases§
- Result
- Convenience re-export of
winnow::Result