serde_value_flatten/lib.rs
1// Copyright 2019-present, OVH SAS
2// All rights reserved.
3//
4// This OVH Software is licensed to you under the MIT license <LICENSE-MIT
5// https://opensource.org/licenses/MIT> or the Modified BSD license <LICENSE-BSD
6// https://opensource.org/licenses/BSD-3-Clause>, at your option. This file may not be copied,
7// modified, or distributed except according to those terms. Please review the Licences for the
8// specific language governing permissions and limitations relating to use of the SAFE Network
9// Software.
10
11//! # Serde Flatten Value
12//!
13//! Based on `serde-value`, `serde-value-flatten` provides a function to flatten any struct which
14//! implement `serde::Serialize`.
15//!
16//! ## Quickstart
17//!
18//! You can start using it by first adding it to your `Cargo.toml`:
19//!
20//! ```toml
21//! [dependencies]
22//! serde = "1.0"
23//! serde_derive = "1.0"
24//! serde_value_flatten = "0.1"
25//! ```
26//!
27//! Then, create a structure which implement the `serde::Serialize` trait and use it with any
28//! serde lib.
29//!
30//! ## Example
31//!
32//! ```rust
33//! #[derive(Serialize, Clone, Debug)]
34//! struct SubFoo {
35//! a: String,
36//! b: u64,
37//! }
38//!
39//! #[derive(Serialize, Clone, Debug)]
40//! struct Foo {
41//! a: String,
42//! b: f64,
43//! c: Vec<i8>,
44//! d: SubFoo,
45//! }
46//!
47//! fn main() {
48//! let foo = Foo { a: "test".into(), b: 0.5, c: vec![5, 9], d: SubFoo { a: "subtest".into(), b: 695217 } };
49//! let ser = serde_value_flatten::to_flatten_maptree("_", Some("_"), &foo).unwrap();
50//!
51//! println!("{}", serde_json::to_string_pretty(&ser).unwrap());
52//! }
53//! ```
54//! **Output**:
55//! ```json
56//! {
57//! "_a": "test",
58//! "_b": 0.5,
59//! "_c_0": 5,
60//! "_c_1": 9,
61//! "_d_a": "subtest",
62//! "_d_b": 695217
63//! }
64//! ```
65//!
66//! ### Feature ovh-ldp
67//!
68//! The feature `ovh-ldp` allow to suffix fields names to suits to the [LDP naming conventions](https://docs.ovh.com/fr/logs-data-platform/field-naming-conventions/).
69//!
70//! In your `Cargo.toml`, set:
71//!
72//! ```toml
73//! [dependencies]
74//! serde = "1.0"
75//! serde_derive = "1.0"
76//! serde_value_flatten = { version = "0.1", features = ["ovh-ldp"] }
77//! ```
78//!
79//! Re-run the previous example, and now the output will be :
80//!
81//! ```json
82//! {
83//! "_a": "test",
84//! "_b_float": 0.5,
85//! "_c_0_long": 5,
86//! "_c_1_long": 9,
87//! "_d_a": "subtest",
88//! "_d_b_double": 695217
89//! }
90//! ```
91#![doc(
92 html_logo_url = "https://eu.api.ovh.com/images/com-square-bichro.png",
93 html_favicon_url = "https://www.ovh.com/favicon.ico",
94)]
95#![deny(warnings, missing_docs)]
96extern crate serde;
97extern crate serde_value;
98
99use std::collections::BTreeMap;
100
101mod ser;
102
103#[inline]
104/// Function to flatten any structure which implement the `serde::Serialize`.
105///
106/// Keys or attributes names will be will concatenated as path (e.g: `{ a: {b: 5}} -> { a_b: 5 }`).
107///
108/// # Configuration
109///
110/// * **key_separator**: Separator to use at each level change.
111/// * **prefix**: Prefix to use on the first level before the attribute / key / index name
112///
113/// ## Example
114///
115/// ```rust
116/// #[derive(Serialize, Clone, Debug)]
117/// struct SubFoo {
118/// a: String,
119/// b: u64,
120/// }
121///
122/// #[derive(Serialize, Clone, Debug)]
123/// struct Foo {
124/// a: String,
125/// b: f64,
126/// c: Vec<i8>,
127/// d: SubFoo,
128/// }
129///
130/// fn main() {
131/// let foo = Foo { a: "test".into(), b: 0.5, c: vec![5, 9], d: SubFoo { a: "subtest".into(), b: 695217 } };
132/// let ser = serde_value_flatten::to_flatten_maptree("|", None, &foo).unwrap();
133///
134/// println!("{}", serde_json::to_string_pretty(&ser).unwrap());
135/// }
136/// ```
137/// **Output**:
138/// ```json
139/// {
140/// "a": "test",
141/// "b": 0.5,
142/// "c|0": 5,
143/// "c|1": 9,
144/// "d|a": "subtest",
145/// "d|b": 695217
146/// }
147/// ```
148pub fn to_flatten_maptree<T: ?Sized>(key_separator: &str, prefix: Option<&str>, src: &T) -> Result<BTreeMap<serde_value::Value, serde_value::Value>, serde_value::SerializerError>
149 where T: serde::Serialize {
150 Ok(ser::FlatSerializer::new(key_separator.into(), prefix.unwrap_or("").into())
151 .disassemble("", "", &serde_value::to_value(src)?))
152}
153