# `value-bag` [![Rust](https://github.com/sval-rs/value-bag/workflows/Rust/badge.svg)](https://github.com/sval-rs/value-bag/actions) [![Latest version](https://img.shields.io/crates/v/value-bag.svg)](https://crates.io/crates/value-bag) [![Documentation Latest](https://docs.rs/value-bag/badge.svg)](https://docs.rs/value-bag) ## What is a value bag? A `ValueBag` is an anonymous structured value that supports casting, downcasting, formatting, and serializing. The producer of a `ValueBag` and its eventual consumer don't need to agree on a serialization contract. Any translation is handled internally by `ValueBag`. Say we capture an `i32` using its `Display` implementation as a `ValueBag`: ```rust let bag = ValueBag::capture_display(42); ``` That value can then be cast to a concrete integer type, like `u64`: ```rust let num = bag.as_u64().unwrap(); assert_eq!(42, num); ``` It could also be serialized as a number using `serde`: ```rust let num = serde_json::to_value(&bag).unwrap(); assert!(num.is_number()); ``` It works for more complex types too. Say we derive `sval::Value` on a type and capture it as a `ValueBag`: ```rust #[derive(Value)] struct Work { id: u64, description: String, } let work = Work { id: 123, description: String::from("do the work"), } let bag = ValueBag::capture_sval2(&work); ``` We could still serialize that value using `serde` without losing structure: ```rust let obj = serde_json::to_value(&bag).unwrap(); assert!(obj.is_object()); ``` It could also be formatted using `Display`: ```rust assert_eq!("Work { id: 123, description: \"do the work\" }", bag.to_string()); ``` The tradeoff in all this is that `ValueBag` needs to depend on the serialization frameworks (`sval`, `serde`, and `std::fmt`) that it supports, instead of just providing an API of its own for others to plug into. Doing this lets `ValueBag` guarantee everything will always line up, and keep its own public API narrow. ## Getting started Add the `value-bag` crate to your `Cargo.toml`: ```rust [dependencies.value-bag] version = "1.10.0" ``` You'll probably also want to add a feature for either `sval` (if you're in a no-std environment) or `serde` (if you need to integrate with other code that uses `serde`): ```rust [dependencies.value-bag] version = "1.10.0" features = ["sval2"] ``` ```rust [dependencies.value-bag] version = "1.10.0" features = ["serde1"] ``` Then you're ready to capture anonymous values! ```rust #[derive(Serialize)] struct MyValue { title: String, description: String, version: u32, } // Capture a value that implements `serde::Serialize` let bag = ValueBag::capture_serde1(&my_value); // Print the contents of the value bag println!("{:?}", bag); ``` ## Cargo features The `value-bag` crate is no-std by default, and offers the following Cargo features: - `std`: Enable support for the standard library. This allows more types to be captured in a `ValueBag`. - `error`: Enable support for capturing `std::error::Error`s. Implies `std`. - `sval`: Enable support for using the [`sval`](https://github.com/sval-rs/sval) serialization framework for inspecting `ValueBag`s by implementing `sval::value::Value`. Implies `sval2`. - `sval2`: Enable support for the stable `2.x.x` version of `sval`. - `serde`: Enable support for using the [`serde`](https://github.com/serde-rs/serde) serialization framework for inspecting `ValueBag`s by implementing `serde::Serialize`. Implies `std` and `serde1`. - `serde1`: Enable support for the stable `1.x.x` version of `serde`. - `owned`: Add support for buffering `ValueBag`s into an owned `Send + Sync` variant. - `seq`: Add support for working with sequences without needing to go through a full serialization framework. - `test`: Add test helpers for inspecting the shape of the value inside a `ValueBag`.