vertigo/driver_module/js_value/
serialize.rs1use std::collections::{BTreeMap, HashMap};
2use std::rc::Rc;
3
4use crate::driver_module::js_value::js_json_struct::JsJsonNumber;
5use crate::driver_module::js_value::MapItem;
6
7use super::js_json_struct::JsJson;
8
9#[derive(Debug)]
10struct JsJsonContextInner {
11 parent: Option<Rc<JsJsonContextInner>>,
12 current: String,
13}
14
15#[derive(Clone, Debug)]
16pub struct JsJsonContext {
17 inner: Rc<JsJsonContextInner>,
18}
19
20impl JsJsonContext {
21 pub fn new(current: impl Into<String>) -> JsJsonContext {
22 Self {
23 inner: Rc::new(JsJsonContextInner {
24 parent: None,
25 current: current.into(),
26 }),
27 }
28 }
29
30 pub fn add(&self, child: impl ToString) -> JsJsonContext {
31 Self {
32 inner: Rc::new(JsJsonContextInner {
33 parent: Some(self.inner.clone()),
34 current: child.to_string(),
35 }),
36 }
37 }
38
39 pub fn convert_to_string(&self) -> String {
40 let mut path = Vec::new();
41 let mut current = self.inner.clone();
42
43 loop {
44 path.push(current.current.clone());
45
46 let Some(parent) = current.parent.clone() else {
47 return path.into_iter().rev().collect::<Vec<_>>().join(" -> ");
48 };
49
50 current = parent;
51 }
52 }
53}
54
55impl std::fmt::Display for JsJsonContext {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 f.write_str(&self.convert_to_string())
58 }
59}
60
61pub trait JsJsonSerialize {
62 fn to_json(self) -> JsJson;
63}
64
65pub trait JsJsonDeserialize
66where
67 Self: Sized,
68{
69 fn from_json(context: JsJsonContext, json: JsJson) -> Result<Self, JsJsonContext>;
70}
71
72impl JsJsonSerialize for String {
73 fn to_json(self) -> JsJson {
74 JsJson::String(self)
75 }
76}
77
78impl JsJsonDeserialize for String {
79 fn from_json(context: JsJsonContext, json: JsJson) -> Result<Self, JsJsonContext> {
80 match json {
81 JsJson::String(value) => Ok(value),
82 other => {
83 let message = ["string expected, received ", other.typename()].concat();
84 Err(context.add(message))
85 }
86 }
87 }
88}
89
90macro_rules! impl_js_json_for_number {
91 ($name:ty) => {
92 impl JsJsonSerialize for $name {
93 fn to_json(self) -> JsJson {
94 JsJson::Number(JsJsonNumber(self as f64))
95 }
96 }
97
98 impl JsJsonDeserialize for $name {
99 fn from_json(context: JsJsonContext, json: JsJson) -> Result<Self, JsJsonContext> {
100 match json {
101 JsJson::Number(JsJsonNumber(value)) => Ok(value as Self),
102 other => Err(context
103 .add(["number($name) expected, received ", other.typename()].concat())),
104 }
105 }
106 }
107 };
108}
109
110impl_js_json_for_number!(i8);
111impl_js_json_for_number!(i16);
112impl_js_json_for_number!(i32);
113impl_js_json_for_number!(i64);
114impl_js_json_for_number!(isize);
115
116impl_js_json_for_number!(u8);
117impl_js_json_for_number!(u16);
118impl_js_json_for_number!(u32);
119impl_js_json_for_number!(u64);
120impl_js_json_for_number!(usize);
121
122impl_js_json_for_number!(f32);
123impl_js_json_for_number!(f64);
124
125impl JsJsonSerialize for bool {
126 fn to_json(self) -> JsJson {
127 match self {
128 false => JsJson::False,
129 true => JsJson::True,
130 }
131 }
132}
133
134impl JsJsonDeserialize for bool {
135 fn from_json(context: JsJsonContext, json: JsJson) -> Result<Self, JsJsonContext> {
136 match json {
137 JsJson::False => Ok(false),
138 JsJson::True => Ok(true),
139 other => {
140 let message = ["bool expected, received ", other.typename()].concat();
141 Err(context.add(message))
142 }
143 }
144 }
145}
146
147impl JsJsonSerialize for () {
148 fn to_json(self) -> JsJson {
149 JsJson::Object(BTreeMap::default())
150 }
151}
152
153impl JsJsonDeserialize for () {
154 fn from_json(context: JsJsonContext, json: JsJson) -> Result<Self, JsJsonContext> {
155 let map = json.get_hashmap(&context)?;
156
157 if !map.is_empty() {
158 let message = "Empty {} expected, inner content received".to_string();
159 return Err(context.add(message));
160 }
161
162 Ok(())
163 }
164}
165
166impl JsJsonSerialize for &str {
167 fn to_json(self) -> JsJson {
168 JsJson::String(self.into())
169 }
170}
171
172impl<T: JsJsonSerialize> JsJsonSerialize for Vec<T> {
173 fn to_json(self) -> JsJson {
174 let mut list = Vec::new();
175
176 for item in self {
177 list.push(item.to_json());
178 }
179
180 JsJson::List(list)
181 }
182}
183
184impl<T: JsJsonDeserialize> JsJsonDeserialize for Vec<T> {
185 fn from_json(context: JsJsonContext, json: JsJson) -> Result<Self, JsJsonContext> {
186 let mut list = Vec::new();
187
188 let JsJson::List(inner) = json else {
189 let message = ["List expected, received ", json.typename()].concat();
190 return Err(context.add(message));
191 };
192
193 for (index, item) in inner.into_iter().enumerate() {
194 list.push(T::from_json(context.add(index), item)?);
195 }
196
197 Ok(list)
198 }
199}
200
201impl<T: JsJsonSerialize> JsJsonSerialize for Option<T> {
202 fn to_json(self) -> JsJson {
203 match self {
204 Some(value) => value.to_json(),
205 None => JsJson::Null,
206 }
207 }
208}
209
210impl<T: JsJsonDeserialize> JsJsonDeserialize for Option<T> {
211 fn from_json(context: JsJsonContext, json: JsJson) -> Result<Self, JsJsonContext> {
212 if let JsJson::Null = json {
213 return Ok(None);
214 }
215
216 Ok(Some(T::from_json(context, json)?))
217 }
218}
219
220impl<T: JsJsonSerialize> JsJsonSerialize for HashMap<String, T> {
221 fn to_json(self) -> JsJson {
222 let mut result = BTreeMap::new();
223
224 for (key, item) in self {
225 result.insert(key, item.to_json());
226 }
227
228 JsJson::Object(result)
229 }
230}
231
232impl<T: JsJsonDeserialize> JsJsonDeserialize for HashMap<String, T> {
233 fn from_json(context: JsJsonContext, json: JsJson) -> Result<Self, JsJsonContext> {
234 let map = json.get_hashmap(&context)?;
235
236 let mut result = HashMap::new();
237
238 for (key, item) in map {
239 let context = context.add(["field: '", key.as_str(), "'"].concat());
240 let value = T::from_json(context, item)?;
241 result.insert(key, value);
242 }
243
244 Ok(result)
245 }
246}
247
248impl<K: JsJsonSerialize + JsJsonDeserialize, T: JsJsonSerialize + JsJsonDeserialize> JsJsonSerialize
249 for BTreeMap<K, T>
250{
251 fn to_json(self) -> JsJson {
252 let mut result = Vec::<JsJson>::new();
253
254 for (key, item) in self {
255 result.push(MapItem { key, value: item }.to_json());
256 }
257
258 JsJson::List(result)
259 }
260}
261
262impl<K: JsJsonSerialize + JsJsonDeserialize + Ord, T: JsJsonSerialize + JsJsonDeserialize>
263 JsJsonDeserialize for BTreeMap<K, T>
264{
265 fn from_json(context: JsJsonContext, json: JsJson) -> Result<Self, JsJsonContext> {
266 let JsJson::List(list) = json else {
267 let message = ["list expected, received ", json.typename()].concat();
268 return Err(context.add(message));
269 };
270
271 let mut result = BTreeMap::new();
272
273 for (index, item) in list.into_iter().enumerate() {
274 let item = from_json::<MapItem<K, T>>(item)
275 .map_err(|err| context.add(format!("index={index} error={err}")))?;
276
277 let exist = result.insert(item.key, item.value);
278
279 if exist.is_some() {
280 return Err(context.add("Duplicate key"));
281 }
282 }
283
284 Ok(result)
285 }
286}
287
288pub fn from_json<T: JsJsonDeserialize>(json: JsJson) -> Result<T, String> {
290 let context = JsJsonContext::new("root");
291 let result = T::from_json(context, json);
292 result.map_err(|context| context.convert_to_string())
293}
294
295pub fn to_json<T: JsJsonSerialize>(value: T) -> JsJson {
297 value.to_json()
298}
299
300#[cfg(test)]
301mod tests {
302 use super::*;
303
304 #[derive(Debug, PartialEq, Clone)]
305 struct Post {
306 name: String,
307 age: u64,
308 }
309
310 impl JsJsonSerialize for Post {
311 fn to_json(self) -> JsJson {
312 JsJson::Object(BTreeMap::from([
313 ("name".to_string(), self.name.to_json()),
314 ("age".to_string(), self.age.to_json()),
315 ]))
316 }
317 }
318
319 impl JsJsonDeserialize for Post {
320 fn from_json(context: JsJsonContext, mut json: JsJson) -> Result<Self, JsJsonContext> {
321 Ok(Self {
322 name: json.get_property(&context, "name")?,
323 age: json.get_property(&context, "age")?,
324 })
325 }
326 }
327
328 #[test]
329 fn aaaa() {
330 let aaa = JsJson::String("aaa".into());
331 let aaa_post = from_json::<Post>(aaa);
332 assert_eq!(
333 aaa_post,
334 Err(String::from("root -> object expected, received string"))
335 );
336
337 let bbb = Post {
338 name: "dsada".into(),
339 age: 33,
340 };
341
342 let ccc = bbb.clone().to_json();
343 let Ok(ddd) = from_json::<Post>(ccc) else {
344 unreachable!();
345 };
346 assert_eq!(bbb, ddd);
347 }
348
349 #[test]
350 fn test_vec() {
351 let aaa = Post {
352 name: "aaa".into(),
353 age: 11,
354 };
355
356 let bbb = Post {
357 name: "bbb".into(),
358 age: 22,
359 };
360
361 let ccc = vec![aaa, bbb];
362
363 let ddd = ccc.clone().to_json();
364
365 let Ok(eee) = from_json::<Vec<Post>>(ddd) else {
366 unreachable!();
367 };
368
369 assert_eq!(ccc, eee);
370 }
371
372 #[test]
373 fn test_unit() {
374 let unit = JsJson::Object(BTreeMap::default());
375
376 let Ok(()) = from_json::<()>(unit.clone()) else {
377 unreachable!();
378 };
379
380 let unit2 = to_json(());
381
382 assert_eq!(unit2, unit)
383 }
384
385 #[test]
386 fn test_serialize_to_string() {
387 let data: Vec<u8> = b"Hello, world!".to_vec();
388
389 let encoded = data
390 .iter()
391 .map(|b| format!("{:02x}", b))
392 .collect::<String>();
393
394 let decoded = (0..encoded.len())
395 .step_by(2)
396 .map(|i| u8::from_str_radix(&encoded[i..i + 2], 16).unwrap())
397 .collect::<Vec<u8>>();
398
399 println!("Original: {}", String::from_utf8_lossy(&decoded));
400 }
401}