1use std::{borrow::Cow, convert::AsRef};
2
3use serde::{Serialize, Serializer};
4use serde_json::value::RawValue;
5
6#[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 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}