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