1use std::{borrow::Cow, convert::AsRef};
2
3use serde::{Serialize, Serializer};
4use serde_json::value::RawValue;
5
6#[derive(Debug)]
13#[stability::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 where
19 S: Serializer,
20 {
21 let s = self.0.as_ref();
22 let r = replace_newline(s);
23
24 if let Some(value) = as_raw_json(&r) {
25 value.serialize(serializer)
26 } else {
27 s.serialize(serializer)
29 }
30 }
31}
32
33fn replace_newline(raw: &str) -> Cow<'_, str> {
34 if raw.contains('\n') {
35 Cow::from(raw.replace('\n', " "))
36 } else {
37 Cow::from(raw)
38 }
39}
40
41fn as_raw_json(raw: &str) -> Option<&RawValue> {
42 let raw = raw.trim();
43 serde_json::from_str(raw).ok()
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[derive(Serialize)]
51 struct Data {
52 a: u32,
53 r: Raw<String>,
54 }
55
56 #[test]
57 fn json() {
58 assert_eq!(
59 serde_json::to_string(&Data {
60 a: 42,
61 r: Raw(r#"{"b":42}"#.into()),
62 })
63 .unwrap(),
64 r#"{"a":42,"r":{"b":42}}"#
65 );
66
67 assert_eq!(
68 serde_json::to_string(&Data {
69 a: 42,
70 r: Raw("{\"b\":\n42}".into()),
71 })
72 .unwrap(),
73 r#"{"a":42,"r":{"b": 42}}"#
74 );
75 }
76
77 #[test]
78 fn non_json() {
79 assert_eq!(
80 serde_json::to_string(&Data {
81 a: 42,
82 r: Raw("foo\nbar".into()),
83 })
84 .unwrap(),
85 r#"{"a":42,"r":"foo\nbar"}"#
86 );
87 }
88}