1use serde::de::value::Error as ValueError;
2use serde::Serialize;
3#[cfg(feature = "ron")]
4use std::borrow::Cow;
5
6use crate::content::{json, yaml, Content, ContentSerializer};
7use crate::settings::Settings;
8
9pub enum SerializationFormat {
10 #[cfg(feature = "csv")]
11 Csv,
12 #[cfg(feature = "ron")]
13 Ron,
14 #[cfg(feature = "toml")]
15 Toml,
16 Yaml,
17 Json,
18 JsonCompact,
19}
20
21#[derive(Debug)]
22pub enum SnapshotLocation {
23 Inline,
24 File,
25}
26
27pub fn serialize_content(mut content: Content, format: SerializationFormat) -> String {
28 content = Settings::with(|settings| {
29 if settings.sort_maps() {
30 content.sort_maps();
31 }
32 #[cfg(feature = "redactions")]
33 {
34 content = settings.apply_redactions(content);
35 }
36 content
37 });
38
39 match format {
40 SerializationFormat::Yaml => yaml::to_string(&content)[4..].to_string(),
41 SerializationFormat::Json => json::to_string_pretty(&content),
42 SerializationFormat::JsonCompact => json::to_string_compact(&content),
43 #[cfg(feature = "csv")]
44 SerializationFormat::Csv => {
45 let mut buf = Vec::with_capacity(128);
46 {
47 let mut writer = csv::Writer::from_writer(&mut buf);
48 if let Some(content_slice) = content.as_slice() {
51 for content in content_slice {
52 writer.serialize(content).unwrap();
53 }
54 } else {
55 writer.serialize(&content).unwrap();
56 }
57 writer.flush().unwrap();
58 }
59 if buf.ends_with(b"\n") {
60 buf.truncate(buf.len() - 1);
61 }
62 String::from_utf8(buf).unwrap()
63 }
64 #[cfg(feature = "ron")]
65 SerializationFormat::Ron => {
66 let mut buf = String::new();
67 let mut config = ron::ser::PrettyConfig::new();
68 config.new_line = Cow::Borrowed("\n");
69 config.indentor = Cow::Borrowed(" ");
70 config.struct_names = true;
71 let mut serializer = ron::ser::Serializer::with_options(
72 &mut buf,
73 Some(config),
74 &ron::options::Options::default(),
75 )
76 .unwrap();
77 content.serialize(&mut serializer).unwrap();
78 buf
79 }
80 #[cfg(feature = "toml")]
81 SerializationFormat::Toml => {
82 let mut rv = toml::to_string_pretty(&content).unwrap();
83 if rv.ends_with('\n') {
84 rv.truncate(rv.len() - 1);
85 }
86 rv
87 }
88 }
89}
90
91pub fn serialize_value<S: Serialize>(s: &S, format: SerializationFormat) -> String {
92 let serializer = ContentSerializer::<ValueError>::new();
93 let content = Serialize::serialize(s, serializer).unwrap();
94 serialize_content(content, format)
95}
96
97#[cfg(feature = "redactions")]
98pub fn serialize_value_redacted<S: Serialize>(
99 s: &S,
100 redactions: &[(crate::redaction::Selector, crate::redaction::Redaction)],
101 format: SerializationFormat,
102) -> String {
103 let serializer = ContentSerializer::<ValueError>::new();
104 let mut content = Serialize::serialize(s, serializer).unwrap();
105 for (selector, redaction) in redactions {
106 content = selector.redact(content, redaction);
107 }
108 serialize_content(content, format)
109}
110
111#[test]
112fn test_yaml_serialization() {
113 let yaml = serialize_content(
114 Content::Map(vec![
115 (
116 Content::from("env"),
117 Content::Seq(vec![
118 Content::from("ENVIRONMENT"),
119 Content::from("production"),
120 ]),
121 ),
122 (
123 Content::from("cmdline"),
124 Content::Seq(vec![Content::from("my-tool"), Content::from("run")]),
125 ),
126 ]),
127 SerializationFormat::Yaml,
128 );
129 crate::assert_snapshot!(&yaml, @r"
130 env:
131 - ENVIRONMENT
132 - production
133 cmdline:
134 - my-tool
135 - run
136 ");
137
138 let inline_yaml = serialize_content(
139 Content::Map(vec![
140 (
141 Content::from("env"),
142 Content::Seq(vec![
143 Content::from("ENVIRONMENT"),
144 Content::from("production"),
145 ]),
146 ),
147 (
148 Content::from("cmdline"),
149 Content::Seq(vec![Content::from("my-tool"), Content::from("run")]),
150 ),
151 ]),
152 SerializationFormat::Yaml,
153 );
154 crate::assert_snapshot!(&inline_yaml, @r"
155 env:
156 - ENVIRONMENT
157 - production
158 cmdline:
159 - my-tool
160 - run
161 ");
162}