1use serde::{de::{DeserializeOwned, Visitor}, Deserializer};
2
3pub fn deser_stringified_format<'de, D, T, F, E>(deserializer: D, parser: F) -> Result<T, D::Error>
7where
8 D: Deserializer<'de>,
9 T: serde::de::DeserializeOwned,
10 F: Fn(&str) -> Result<T, E>,
11 E: std::fmt::Display,
12{
13 struct StringifiedFormatVisitor<T, F, E> {
14 parser: F,
15 marker: std::marker::PhantomData<T>,
16 error_marker: std::marker::PhantomData<E>,
17 }
18
19 impl<'de, T, F, E> Visitor<'de> for StringifiedFormatVisitor<T, F, E>
20 where
21 T: serde::de::DeserializeOwned,
22 F: Fn(&str) -> Result<T, E>,
23 E: std::fmt::Display,
24 {
25 type Value = T;
26
27 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
28 write!(
29 formatter,
30 "a string containing formatted data that parses to type {}",
31 std::any::type_name::<T>()
32 )
33 }
34
35 fn visit_str<A>(self, value: &str) -> Result<Self::Value, A>
36 where
37 A: serde::de::Error,
38 {
39 (self.parser)(value).map_err(A::custom)
40 }
41
42 fn visit_borrowed_str<A>(self, value: &'de str) -> Result<Self::Value, A>
43 where
44 A: serde::de::Error,
45 {
46 (self.parser)(value).map_err(A::custom)
47 }
48 }
49
50 deserializer.deserialize_str(StringifiedFormatVisitor {
51 parser,
52 marker: std::marker::PhantomData,
53 error_marker: std::marker::PhantomData,
54 })
55}
56
57#[cfg(feature = "serde_json")]
58pub fn deser_stringified_json<'de, D, T>(deserializer: D) -> Result<T, D::Error>
59where
60 D: serde::Deserializer<'de>,
61 T: DeserializeOwned,
62{
63 deser_stringified_format(deserializer, |s| serde_json::from_str(s))
65}
66
67#[cfg(feature = "serde_yaml")]
68pub fn deser_stringified_yaml<'de, D, T>(deserializer: D) -> Result<T, D::Error>
69where
70 D: serde::Deserializer<'de>,
71 T: DeserializeOwned,
72{
73 deser_stringified_format(deserializer, |s| serde_yaml::from_str(s))
74}
75
76#[cfg(feature = "toml")]
77pub fn deser_stringified_toml<'de, D, T>(deserializer: D) -> Result<T, D::Error>
78where
79 D: serde::Deserializer<'de>,
80 T: serde::de::DeserializeOwned,
81{
82 deser_stringified_format(deserializer, |s| toml::from_str(s))
83}
84
85#[cfg(test)]
86mod tests {
87 use serde::Deserialize;
88 use super::*;
89
90 #[derive(Deserialize)]
91 struct Metadata {
92 key: i32,
93 enabled: bool,
94 }
95
96 #[test]
97 #[cfg(feature = "serde_json")]
98 fn json_parsing() {
99 #[derive(Deserialize)]
100 struct Example<T: DeserializeOwned> {
101 #[serde(deserialize_with = "deser_stringified_json")]
102 data: T,
103 }
104
105 let json_str = r#"{"data": "{\"key\": 1, \"enabled\": false}"}"#;
106 let parsed: Example<serde_json::Value> = serde_json::from_str(json_str).unwrap();
107 assert_eq!(parsed.data, serde_json::json!({"key": 1, "enabled": false}));
108
109 let struct_parsed: Example<Metadata> = serde_json::from_str(json_str).unwrap();
110 assert_eq!(struct_parsed.data.key, 1);
111 assert_eq!(struct_parsed.data.enabled, false);
112 }
113
114 #[test]
115 #[cfg(feature = "serde_yaml")]
116 fn yaml_parsing() {
117 #[derive(Deserialize)]
118 struct Example<T: DeserializeOwned> {
119 #[serde(deserialize_with = "deser_stringified_yaml")]
120 data: T,
121 }
122
123 let yaml_str = r#"
124data: |
125 key: 1
126 enabled: false
127"#;
128 let parsed: Example<serde_yaml::Value> = serde_yaml::from_str(yaml_str).unwrap();
129
130 let mut expected_mapping = serde_yaml::Mapping::new();
131 expected_mapping.insert(
132 serde_yaml::Value::String("key".to_string()),
133 serde_yaml::Value::Number(1.into()),
134 );
135 expected_mapping.insert(
136 serde_yaml::Value::String("enabled".to_string()),
137 serde_yaml::Value::Bool(false),
138 );
139 let expected = serde_yaml::Value::Mapping(expected_mapping);
140 assert_eq!(parsed.data, expected);
141
142 let struct_parsed: Example<Metadata> = serde_yaml::from_str(yaml_str).unwrap();
143 assert_eq!(struct_parsed.data.key, 1);
144 assert_eq!(struct_parsed.data.enabled, false);
145 }
146
147 #[test]
148 #[cfg(feature = "toml")]
149 fn toml_parsing() {
150 #[derive(Deserialize)]
151 struct Example<T: serde::de::DeserializeOwned> {
152 #[serde(deserialize_with = "deser_stringified_toml")]
153 data: T,
154 }
155
156 let toml_str = "data = \"\"\"\nkey = 1\nenabled = false\n\"\"\"";
157 let parsed: Example<toml::Value> = toml::from_str(toml_str).unwrap();
158
159 let mut expected = toml::value::Table::new();
160 expected.insert("key".to_string(), toml::Value::Integer(1));
161 expected.insert("enabled".to_string(), toml::Value::Boolean(false));
162 assert_eq!(parsed.data, toml::Value::Table(expected));
163
164 let struct_parsed: Example<Metadata> = toml::from_str(toml_str).unwrap();
165 assert_eq!(struct_parsed.data.key, 1);
166 assert_eq!(struct_parsed.data.enabled, false);
167 }
168}