vertigo/driver_module/js_value/
serialize.rs

1use 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
288/// Deserialize from JsJson to T
289pub 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
295/// Serialize T to JsJson
296pub 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}