1use std::{
9 collections::{BTreeMap, HashMap},
10 marker::PhantomData,
11};
12
13use serde::{Deserializer, Serialize, Serializer, de::DeserializeOwned, ser::SerializeMap};
14
15pub trait NumberedItems: Default {
16 type Item: DeserializeOwned + Serialize;
17 const PREFIX: &'static str;
18
19 fn key_matches(name: &str) -> bool {
20 Self::check_key(name).is_some()
21 }
22
23 fn check_key(name: &str) -> Option<u32> {
24 let (first_part, second_part) = name.split_once(Self::PREFIX)?;
25
26 if first_part.is_empty() {
27 let num = second_part.parse::<u32>().ok()?;
28 Some(num)
29 } else {
30 None
31 }
32 }
33
34 fn make_key(number: &u32) -> String {
35 format!("{}{}", Self::PREFIX, number)
36 }
37}
38
39pub trait Test {
40 fn test_fn() -> fn(&str) -> bool;
41}
42
43pub fn deserialize_additional_data<'de, T, O, D>(d: D) -> Result<HashMap<String, O>, D::Error>
44where
45 D: Deserializer<'de>,
46 T: Test,
47 O: serde::de::Deserialize<'de>,
48{
49 struct Visitor<O, T> {
50 _phantom: PhantomData<(O, T)>,
51 }
52
53 impl<O, T> Default for Visitor<O, T> {
54 fn default() -> Self {
55 Self {
56 _phantom: Default::default(),
57 }
58 }
59 }
60
61 impl<'de, O, T> serde::de::Visitor<'de> for Visitor<O, T>
62 where
63 O: serde::de::Deserialize<'de>,
64 T: Test,
65 {
66 type Value = HashMap<String, O>;
67
68 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
69 write!(f, "additional properties")
70 }
71
72 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
73 where
74 A: serde::de::MapAccess<'de>,
75 {
76 let mut output = HashMap::new();
77
78 loop {
79 let (key, value) = match map.next_entry::<&str, O>() {
80 Ok(Some(key)) => key,
81 Ok(None) => break,
82 Err(_) => continue,
83 };
84
85 if (T::test_fn())(key) {
86 continue;
87 }
88
89 output.insert(key.to_string(), value);
90 }
91
92 Ok(output)
93 }
94 }
95
96 d.deserialize_map(Visitor::<O, T>::default())
97}
98
99macro_rules! define_multi_fns {
100 ($([$type:ident, $ser:ident, $des:ident]),*) => {
101 $(
102 pub fn $ser<V, S>(value: &$type<u32, V::Item>, s: S) -> Result<S::Ok, S::Error>
103 where
104 S: Serializer,
105 V: NumberedItems,
106 {
107 let mut map = s.serialize_map(Some(value.len()))?;
108
109 for (key, value) in value.iter() {
110 map.serialize_entry(&V::make_key(key), value)?;
111 }
112
113 map.end()
114 }
115
116 pub fn $des<'de, V, D>(d: D) -> Result<$type<u32, V::Item>, D::Error>
117 where
118 V: NumberedItems,
119 D: Deserializer<'de>,
120 {
121 struct InternalVisitor<V, D> {
122 _phantom: PhantomData<(D, V)>,
123 }
124
125 impl<V, D> Default for InternalVisitor<V, D> {
126 fn default() -> Self {
127 Self {
128 _phantom: Default::default(),
129 }
130 }
131 }
132
133 impl<'de, V, D> serde::de::Visitor<'de> for InternalVisitor<V, D>
134 where
135 V: NumberedItems,
136 D: Deserializer<'de>,
137 {
138 type Value = $type<u32, V::Item>;
139
140 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
141 write!(f, "Multi-numbered items with prefix {}", V::PREFIX)
142 }
143
144 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
145 where
146 A: serde::de::MapAccess<'de>,
147 {
148 let mut output = $type::new();
149
150 while let Some(key) = map.next_key::<&str>()? {
151 let key = if let Some(idx) = V::check_key(key) {
152 idx
153 } else {
154 continue;
155 };
156
157 let value = map.next_value::<V::Item>()?;
158 output.insert(key, value);
159 }
160
161 Ok(output)
162 }
163 }
164
165 d.deserialize_map(InternalVisitor::<V, D>::default())
166 }
167 )*
168 };
169}
170
171define_multi_fns!(
172 [HashMap, serialize_multi, deserialize_multi],
173 [BTreeMap, serialize_multi_btree, deserialize_multi_btree]
174);
175
176#[cfg(test)]
177mod test {
178 use std::collections::{BTreeMap, HashMap};
179
180 use serde::{Deserialize, Serialize};
181
182 use super::{NumberedItems, Test};
183
184 #[derive(Default)]
185 struct NumberedNames;
186
187 impl NumberedItems for NumberedNames {
188 type Item = String;
189 const PREFIX: &'static str = "name";
190 }
191
192 #[derive(Debug, Deserialize, Serialize, PartialEq)]
193 struct Names {
194 #[serde(
195 flatten,
196 deserialize_with = "super::deserialize_multi_btree::<'_, NumberedNames, _>",
197 serialize_with = "super::serialize_multi_btree::<NumberedNames, _>"
198 )]
199 names: BTreeMap<u32, String>,
200 #[serde(
201 flatten,
202 deserialize_with = "super::deserialize_additional_data::<'_, Names, _, _>"
203 )]
204 additional_data: HashMap<String, String>,
205 }
206
207 impl Test for Names {
208 fn test_fn() -> fn(&str) -> bool {
209 fn the_test(input: &str) -> bool {
210 ["names"].contains(&input) || NumberedNames::key_matches(input)
211 }
212
213 the_test
214 }
215 }
216
217 fn map_kv<K, V, NK, NV>((k, v): (K, V)) -> (NK, NV)
218 where
219 K: Into<NK>,
220 V: Into<NV>,
221 {
222 (k.into(), v.into())
223 }
224
225 #[test]
226 pub fn deserialize_multi() {
227 let text = r#"{ "name1": "value1", "name2": "value2", "name_4": 0, "name_3": false, "name_2": "additional" }"#;
228
229 let names: Names = serde_json::from_str(text).unwrap();
230 let expected = Names {
231 names: [(1u32, "value1"), (2, "value2")]
232 .into_iter()
233 .map(map_kv)
234 .collect(),
235 additional_data: [("name_2", "additional")].into_iter().map(map_kv).collect(),
236 };
237
238 assert_eq!(names, expected);
239 }
240
241 #[test]
242 fn serialize_mluti() {
243 let names = Names {
244 names: [(1u32, "value1"), (2, "value2")]
245 .into_iter()
246 .map(map_kv)
247 .collect(),
248 additional_data: [("name_2", "additional")].into_iter().map(map_kv).collect(),
249 };
250
251 let expected = r#"{"name1":"value1","name2":"value2","name_2":"additional"}"#;
252 let json = serde_json::to_string(&names).unwrap();
253 assert_eq!(json, expected);
254 }
255}