1use crate::{key::flatten_keys, value::ValueExt, Encoding, Error, Result};
5use serde_json::Value;
6
7#[derive(Debug, Default, Clone, PartialEq)]
10pub struct SerializeOptions {
11 pub compact: bool,
14 pub newline: bool,
16 pub keys_as_csv_headers: bool,
21 pub csv_delimiter: Option<u8>,
23 pub text_join_separator: Option<String>,
25}
26
27impl SerializeOptions {
28 pub fn new() -> Self {
30 Self::default()
31 }
32}
33
34#[derive(Debug, Default, Clone)]
48pub struct SerializerBuilder {
49 opts: SerializeOptions,
50}
51
52impl SerializerBuilder {
53 pub fn new() -> Self {
55 Self::default()
56 }
57
58 pub fn compact(&mut self, yes: bool) -> &mut Self {
61 self.opts.compact = yes;
62 self
63 }
64
65 pub fn newline(&mut self, yes: bool) -> &mut Self {
67 self.opts.newline = yes;
68 self
69 }
70
71 pub fn keys_as_csv_headers(&mut self, yes: bool) -> &mut Self {
76 self.opts.keys_as_csv_headers = yes;
77 self
78 }
79
80 pub fn csv_delimiter(&mut self, delim: u8) -> &mut Self {
82 self.opts.csv_delimiter = Some(delim);
83 self
84 }
85
86 pub fn text_join_separator<S>(&mut self, sep: S) -> &mut Self
88 where
89 S: AsRef<str>,
90 {
91 self.opts.text_join_separator = Some(sep.as_ref().to_owned());
92 self
93 }
94
95 pub fn build<W>(&self, writer: W) -> Serializer<W>
97 where
98 W: std::io::Write,
99 {
100 Serializer::with_options(writer, self.opts.clone())
101 }
102}
103
104pub struct Serializer<W> {
106 writer: W,
107 opts: SerializeOptions,
108}
109
110impl<W> Serializer<W>
111where
112 W: std::io::Write,
113{
114 pub fn new(writer: W) -> Self {
116 Self::with_options(writer, Default::default())
117 }
118
119 pub fn with_options(writer: W, opts: SerializeOptions) -> Self {
121 Self { writer, opts }
122 }
123
124 pub fn serialize(&mut self, encoding: Encoding, value: Value) -> Result<()> {
143 match encoding {
144 Encoding::Yaml => self.serialize_yaml(value)?,
145 Encoding::Json => self.serialize_json(value)?,
146 Encoding::Toml => self.serialize_toml(value)?,
147 Encoding::Csv => self.serialize_csv(value)?,
148 Encoding::QueryString => self.serialize_query_string(value)?,
149 Encoding::Xml => self.serialize_xml(value)?,
150 Encoding::Text => self.serialize_text(value)?,
151 Encoding::Gron => self.serialize_gron(value)?,
152 encoding => return Err(Error::UnsupportedEncoding(encoding)),
153 };
154
155 if self.opts.newline {
156 self.writer.write_all(b"\n")?;
157 }
158
159 Ok(())
160 }
161
162 fn serialize_yaml(&mut self, value: Value) -> Result<()> {
163 Ok(serde_yaml::to_writer(&mut self.writer, &value)?)
164 }
165
166 fn serialize_json(&mut self, value: Value) -> Result<()> {
167 if self.opts.compact {
168 serde_json::to_writer(&mut self.writer, &value)?
169 } else {
170 serde_json::to_writer_pretty(&mut self.writer, &value)?
171 }
172
173 Ok(())
174 }
175
176 fn serialize_toml(&mut self, value: Value) -> Result<()> {
177 let value = toml::Value::try_from(value)?;
178
179 let s = if self.opts.compact {
180 toml::ser::to_string(&value)?
181 } else {
182 toml::ser::to_string_pretty(&value)?
183 };
184
185 Ok(self.writer.write_all(s.as_bytes())?)
186 }
187
188 fn serialize_csv(&mut self, value: Value) -> Result<()> {
189 let mut buf = Vec::new();
193 {
194 let mut csv_writer = csv::WriterBuilder::new()
195 .delimiter(self.opts.csv_delimiter.unwrap_or(b','))
196 .from_writer(&mut buf);
197
198 let mut headers: Option<Vec<String>> = None;
199 let empty_value = Value::String("".into());
200
201 for row in value.into_array().into_iter() {
202 let row_data = if !self.opts.keys_as_csv_headers {
203 row.into_array()
204 .into_iter()
205 .map(Value::into_string)
206 .collect::<Vec<_>>()
207 } else {
208 let row = row.into_object("csv");
209
210 if headers.is_none() {
212 let header_data = row.keys().cloned().collect();
213 csv_writer.serialize(&header_data)?;
214 headers = Some(header_data);
215 }
216
217 headers
218 .as_ref()
219 .unwrap()
220 .iter()
221 .map(|header| row.get(header).unwrap_or(&empty_value))
222 .cloned()
223 .map(Value::into_string)
224 .collect::<Vec<_>>()
225 };
226
227 csv_writer.serialize(row_data)?;
228 }
229 }
230
231 Ok(self.writer.write_all(&buf)?)
232 }
233
234 fn serialize_query_string(&mut self, value: Value) -> Result<()> {
235 Ok(serde_qs::to_writer(&value, &mut self.writer)?)
236 }
237
238 fn serialize_xml(&mut self, value: Value) -> Result<()> {
239 Ok(serde_xml_rs::to_writer(&mut self.writer, &value)?)
240 }
241
242 fn serialize_text(&mut self, value: Value) -> Result<()> {
243 let sep = self
244 .opts
245 .text_join_separator
246 .clone()
247 .unwrap_or_else(|| String::from('\n'));
248
249 let text = value
250 .into_array()
251 .into_iter()
252 .map(Value::into_string)
253 .collect::<Vec<String>>()
254 .join(&sep);
255
256 Ok(self.writer.write_all(text.as_bytes())?)
257 }
258
259 fn serialize_gron(&mut self, value: Value) -> Result<()> {
260 let output = flatten_keys(value, "json")
261 .as_object()
262 .unwrap()
263 .into_iter()
264 .map(|(k, v)| format!("{} = {};\n", k, v))
265 .collect::<String>();
266
267 Ok(self.writer.write_all(output.as_bytes())?)
268 }
269}
270
271#[cfg(test)]
272mod test {
273 use super::*;
274 use pretty_assertions::assert_eq;
275 use serde_json::json;
276 use std::str;
277
278 #[track_caller]
279 fn assert_serializes_to(encoding: Encoding, value: Value, expected: &str) {
280 assert_builder_serializes_to(&mut SerializerBuilder::new(), encoding, value, expected)
281 }
282
283 #[track_caller]
284 fn assert_builder_serializes_to(
285 builder: &mut SerializerBuilder,
286 encoding: Encoding,
287 value: Value,
288 expected: &str,
289 ) {
290 let mut buf = Vec::new();
291 let mut ser = builder.build(&mut buf);
292
293 ser.serialize(encoding, value).unwrap();
294 assert_eq!(str::from_utf8(&buf).unwrap(), expected);
295 }
296
297 #[test]
298 fn test_serialize_json() {
299 assert_builder_serializes_to(
300 &mut SerializerBuilder::new().compact(true),
301 Encoding::Json,
302 json!(["one", "two"]),
303 "[\"one\",\"two\"]",
304 );
305 assert_serializes_to(
306 Encoding::Json,
307 json!(["one", "two"]),
308 "[\n \"one\",\n \"two\"\n]",
309 );
310 }
311
312 #[test]
313 fn test_serialize_csv() {
314 assert_serializes_to(
315 Encoding::Csv,
316 json!([["one", "two"], ["three", "four"]]),
317 "one,two\nthree,four\n",
318 );
319 assert_builder_serializes_to(
320 &mut SerializerBuilder::new().keys_as_csv_headers(true),
321 Encoding::Csv,
322 json!([
323 {"one": "val1", "two": "val2"},
324 {"one": "val3", "three": "val4"},
325 {"two": "val5"}
326 ]),
327 "one,two\nval1,val2\nval3,\n,val5\n",
328 );
329 assert_builder_serializes_to(
330 &mut SerializerBuilder::new().keys_as_csv_headers(true),
331 Encoding::Csv,
332 json!({"one": "val1", "two": "val2"}),
333 "one,two\nval1,val2\n",
334 );
335 assert_serializes_to(Encoding::Csv, json!("non-array"), "non-array\n");
336 assert_serializes_to(
337 Encoding::Csv,
338 json!([{"non-array": "row"}]),
339 "\"{\"\"non-array\"\":\"\"row\"\"}\"\n",
340 );
341 assert_builder_serializes_to(
342 &mut SerializerBuilder::new().keys_as_csv_headers(true),
343 Encoding::Csv,
344 json!([["non-object-row"]]),
345 "csv\n\"[\"\"non-object-row\"\"]\"\n",
346 );
347 }
348
349 #[test]
350 fn test_serialize_text() {
351 assert_serializes_to(Encoding::Text, json!(["one", "two"]), "one\ntwo");
352 assert_serializes_to(
353 Encoding::Text,
354 json!([{"foo": "bar"}, "baz"]),
355 "{\"foo\":\"bar\"}\nbaz",
356 );
357 assert_serializes_to(Encoding::Text, json!({"foo": "bar"}), "{\"foo\":\"bar\"}");
358 }
359}