Skip to main content

elfo_core/dumping/
raw.rs

1use std::{borrow::Cow, convert::AsRef};
2
3use serde::{Serialize, Serializer};
4use serde_json::value::RawValue;
5
6/// A wrapper around a raw dump (e.g. received from WS/HTTP).
7///
8/// If the dump is valid JSON, it will be serialized as inner JSON
9/// with saving formatting, but without newlines (replaced with a space).
10///
11/// Otherwise, the dump is serialized as JSON string.
12#[derive(Debug)]
13#[instability::unstable]
14pub struct Raw<T>(pub T);
15
16impl<T: AsRef<str>> Serialize for Raw<T> {
17    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
18        let s = self.0.as_ref();
19        let r = replace_newline(s);
20
21        if let Some(value) = as_raw_json(&r) {
22            value.serialize(serializer)
23        } else {
24            // Will be serialized as a JSON string with escaping.
25            s.serialize(serializer)
26        }
27    }
28}
29
30#[cfg_attr(not(feature = "unstable"), allow(dead_code))]
31fn replace_newline(raw: &str) -> Cow<'_, str> {
32    if raw.contains('\n') {
33        Cow::from(raw.replace('\n', " "))
34    } else {
35        Cow::from(raw)
36    }
37}
38
39#[cfg_attr(not(feature = "unstable"), allow(dead_code))]
40fn as_raw_json(raw: &str) -> Option<&RawValue> {
41    let raw = raw.trim();
42    serde_json::from_str(raw).ok()
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48
49    #[derive(Serialize)]
50    struct Data {
51        a: u32,
52        r: Raw<String>,
53    }
54
55    #[test]
56    fn json() {
57        assert_eq!(
58            serde_json::to_string(&Data {
59                a: 42,
60                r: Raw(r#"{"b":42}"#.into()),
61            })
62            .unwrap(),
63            r#"{"a":42,"r":{"b":42}}"#
64        );
65
66        assert_eq!(
67            serde_json::to_string(&Data {
68                a: 42,
69                r: Raw("{\"b\":\n42}".into()),
70            })
71            .unwrap(),
72            r#"{"a":42,"r":{"b": 42}}"#
73        );
74    }
75
76    #[test]
77    fn non_json() {
78        assert_eq!(
79            serde_json::to_string(&Data {
80                a: 42,
81                r: Raw("foo\nbar".into()),
82            })
83            .unwrap(),
84            r#"{"a":42,"r":"foo\nbar"}"#
85        );
86    }
87}