tinyklv 0.1.0

The simplest Key-Length-Value (KLV) framework in Rust
Documentation
# Tutorial 11 - Optional fields, `default`, and fallback impls

### `Option<T>` fields

Optional types are handled with ease. During encoding, they are omitted when `None`
and encoded as expected when `Some`. Duringd ecoding, they simply default to `None`,
but when encountered, it will populate it as `Some`.

This can be useful in majority of cases. 

### `default` / `default = expr` field attributes

***NOTE:*** _these are different than the `default` container attributes, which define
default decoders/encoders_

The `default` _field_ attribute is similar to a `serde(default)`, where values
are initialized using `<T as Default>::default()`. 

Rather, you can set a default value using `default = ..`, if you want it initialized
using a different value than `<T as Default>::default`

For example

```rust
#[derive(Default)]
enum Color {
    #[default]
    Red,
    Green,
    Blue,
}

#[derive(Klv)]
#[klv(..)]
struct Paint {
    #[klv(default)]
    color_first: Color,     // <-- initialized using Color::Red
    
    #[klv(default = Color::Blue)]
    color_second: Color     // <-- initialized using Color::Blue
}
```

A short packet with three keys: a required `sequence`, an optional
`signal_dbm`, and a `battery_pct` that falls back to `100` when absent.
The thin stream below is hand-rolled to show the grammar - just
`key, len, value` triples. Decoding it produces `None` and `100` for the
two missing keys; no error, no panic.

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

```rust
{{#include ../../../../examples/book_12_a_default.rs}}
```

## Fallback Implementation

### `trait_fallback` (container-level)

Any field lacking a `enc`/`dec` in any location will automatically cause
a proc-macro error. However, more frequently than not, `tinyklv::EncodeValue`
and `tinyklv::DecodeValue` traits are utilized for impls on custom types.

As a result, it makes sense to use these instead of writing them out explicitly
everytime. Therefore, we can use the `trait_fallback` container attribute
to use the traits as a final fallback for finding the decoder/encoder:

```rust
#[derive(Klv)]
#[klv(..)]
struct Paint {
    #[klv(
        key = 0x01,
        dec = Size::decode_value,
        enc = Size::encode_value,
    )]
    size: Size,
    
    #[klv(
        key = 0x02,
        dec = Color::decode_value,
        enc = Color::encode_value,
    )]
    color: Color,
}
```

Instead, you can write:

```rust
#[derive(Klv)]
#[klv(
    ..,
    tinyklv_trait_fallback,
)]
struct Paint {
    #[klv(key = 0x01)]
    size: Size,
    
    #[klv(key = 0x02)]
    color: Color,
}
```

Where `Size` and `Color` in both examples implement `tinyklv::EncodeValue` and
`tinyklv::DecodeValue`

## Examples

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

```rust
{{#include ../../../../examples/book_12_b_fallback.rs}}
```

## Overview

- `Option<T>` composes: a missing key stays `None`, a present one defers
  to `T`'s impls.
- Bare field `default` (no `=`) calls `Default::default()` on the field type -
  handy when the type already has a sensible zero value.
- Field `default = expr` supplies a concrete fallback; the field type stays `T`.
- Field-level `enc` / `dec` take first precedence in which codec to use.
- Container `default(typ = T, ..)` take second precedence in which codec to use.
- Fallback runs last - it is opt-in and silent unless reached.

**Next:** [12 - Nested packets](../advanced/12-nested-packets.md)