vertigo/driver_module/js_value/
serialize.rs

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