# `sval`
[![Build Status](https://travis-ci.com/sval-rs/sval.svg?branch=master)](https://travis-ci.com/sval-rs/sval)
[![Latest version](https://img.shields.io/crates/v/sval.svg)](https://crates.io/crates/sval)
[![Documentation Latest](https://docs.rs/sval/badge.svg)](https://docs.rs/sval)
A lightweight, no-std, object-safe, serialization-only API for structured values with `serde` and `std::fmt` support.
Producers of structured values use the `value` module. Consumers of structured values use the `stream` module.
`sval` offers a JSON-like data model, which is more limiting than `serde`'s, but capable enough to represent Rust data-structures in one form or another.
This library is designed to plug a no-std-object-safe sized hole in Rust's current serialization ecosystem. The driving use-case is structured logging, where individual events are typically small, and there's no complete schema that can tie values in any one event to values in another.
**`sval_json` and `sval_derive` are mostly pilfered from dtolnay's [excellent `miniserde` project](https://github.com/dtolnay/miniserde).**
# Supported formats
- [JSON](https://crates.io/crates/sval_json), the ubiquitous JavaScript Object Notation used by many HTTP APIs.
# Minimum `rustc`
This library requires Rust `1.31.0`.
# See also
- [`serde`](https://docs.rs/serde)
- [`miniserde`](https://docs.rs/miniserde)
# Cargo features
`sval` has the following optional features that can be enabled in your `Cargo.toml`:
- `std`: assume `std` is available and add support for `std` types. Implies `alloc`.
- `alloc`: assume a global allocator is available.
- `derive`: add support for `#[derive(Value)]`.
- `serde`: enable integration with major versions of `serde`. Some implementations of `sval::Value` may not be representable without the `alloc` feature.
- `serde1`: enable integration with just the `1.x` version of `serde`. Any future versions of `serde` will also receive their own feature.
- `fmt`: support converting any `Value` into a `Debug`.
- `arbitrary-depth`: support stateful values with any depth. Implies `alloc`.
- `test`: add helpers for testing implementations of `Value`. Implies `std`. You should avoid using this feature outside of `dev-dependencies`.
# How to use it
Add `sval` to your crate dependencies:
```toml
[dependencies.sval]
version = "1.0.0-alpha.5"
```
## To support my data-structures
Simple struct-like data-structures can derive `sval::Value`:
```toml
[dependencies.sval]
features = ["derive"]
```
```rust
#[macro_use]
extern crate sval;
#[derive(Value)]
struct MyData {
id: u64,
name: String,
}
```
Other data-structures can implement `sval::Value` manually:
```rust
use sval::value::{self, Value};
struct MyId(u64);
impl Value for MyId {
fn stream(&self, stream: &mut value::Stream) -> value::Result {
stream.u64(self.0)
}
}
```
## To format my data
The `sval_json` crate can format any `sval::Value` as JSON:
```toml
[dependencies.sval_json]
version = "1.0.0-alpha.5"
features = ["std"]
```
```rust
let my_json = sval_json::to_string(my_data)?;
```
## To integrate with `serde`
`sval` has out-of-the-box `serde` integration between `sval::Value`s and `serde::Serialize`s. Add the `serde` feature to `sval` to enable it:
```toml
[dependencies.sval]
features = ["serde"]
```
Use the `to_serialize` function to turn any `sval::Value` into a `serde::Serialize`:
```rust
let my_serialize = sval::serde::v1::to_serialize(my_data);
```
Use the `to_value` function to turn any `serde::Serialize` into a `sval::Value`:
```rust
let my_value = sval::serde::v1::to_value(my_data);
```
When the `serde` feature is available, structures that already derive `Serialize` can also always derive `Value`. The `Value` implementation will behave the same as `Serialize`:
```rust
#[derive(Serialize, Value)]
#[sval(derive_from = "serde")]
struct MyData {
id: u64,
name: String,
#[serde(flatten)]
props: serde_json::Map<String, serde_json::Value>,
}
```
## To integrate with `std::fmt`
`sval` can provide a compatible `Debug` implementation for any `sval::Value`. Add the `fmt` feature to `sval` to enable it:
```toml
[dependencies.sval]
features = ["fmt"]
```
Use the `to_debug` function to turn any `sval::Value` into a `std::fmt::Debug`:
```rust
fn with_value(value: impl Value) {
dbg!(sval::fmt::to_debug(&value));
..
}
```