tinyklv 0.1.0

The simplest Key-Length-Value (KLV) framework in Rust
Documentation
# Tutorial 13 - Repeated extraction

Sensor pipelines frequently batch readings back-to-back inside a single UDP
datagram, file record, or log line. When each reading is sentinel-framed,
`drain_frames` peels them off one at a time until the buffer is exhausted.

`tinyklv` exposes this as the `DrainFrames` trait, auto-implemented for any
`T: DecodeFrame<S>` (which requires a sentinel):

```rust,ignore
let readings: Vec<SensorReading> = SensorReading::drain_frames(&mut input)?;
```

Semantics: `drain_frames` calls `decode_frame` until the stream either
cleanly ends (returns whatever was collected so far) or hits a real parse
error (propagates the error with context). Callers are never left guessing
whether an empty `Vec` means "no items" or "parse failed on item N".

For sentinel-less streams, use the `Vec<T>` blanket impl of `DecodeValue`
instead:

```rust,ignore
let readings: Vec<SensorReading> = Vec::<SensorReading>::decode_value(&mut input)?;
```

The example builds five `SensorReading` values, encodes each as a full
frame, concatenates them into one buffer, and drains the whole batch in a
single call.

Run this example: `cargo run --example book_13_repeated_extraction`

```rust,no_run
{{#include ../../../../examples/book_13_repeated_extraction.rs}}
```

- `DrainFrames::drain_frames` returns `Vec<Self>` from a sentinel-framed stream.
- `Vec<T>::decode_value` returns `Vec<T>` from an unframed stream.
- Clean EOF = success; parse error = propagated error, not silent truncation.

**Next:** [14 - Break conditions](./14-break-condition.md)