edn_rs/serialize/
mod.rs

1use alloc::collections::{BTreeMap, BTreeSet, LinkedList};
2use alloc::format;
3use alloc::string::{String, ToString};
4use alloc::vec::Vec;
5
6/// Trait that allows you to implement Serialization for each type of your choice.
7/// Example:
8/// ```rust
9/// use edn_rs::serialize::Serialize;
10///
11/// #[derive(Debug)]
12/// struct YourType;
13///
14/// impl Serialize for YourType {
15///     fn serialize(&self) -> String {
16///         format!("{:?}", self)
17///     }
18/// }
19/// ```
20///
21/// Implemented for all generic types.
22pub trait Serialize {
23    fn serialize(&self) -> String;
24}
25
26macro_rules! ser_primitives {
27    ( $( $name:ty ),+ ) => {
28        $(
29            impl Serialize for $name
30            {
31                fn serialize(&self) -> String {
32                    format!("{:?}", self)
33                }
34            }
35        )+
36    };
37}
38
39impl<T> Serialize for Vec<T>
40where
41    T: Serialize,
42{
43    fn serialize(&self) -> String {
44        let aux_vec = self
45            .iter()
46            .map(Serialize::serialize)
47            .collect::<Vec<String>>();
48        let mut s = String::new();
49        s.push('[');
50        s.push_str(&aux_vec.join(", "));
51        s.push(']');
52        s
53    }
54}
55
56#[cfg(feature = "std")]
57impl<T, H: std::hash::BuildHasher> Serialize for std::collections::HashSet<T, H>
58where
59    T: Serialize,
60{
61    fn serialize(&self) -> String {
62        let aux_vec = self
63            .iter()
64            .map(Serialize::serialize)
65            .collect::<Vec<String>>();
66        let mut s = String::new();
67        s.push('#');
68        s.push('{');
69        s.push_str(&aux_vec.join(", "));
70        s.push('}');
71        s
72    }
73}
74
75impl<T> Serialize for BTreeSet<T>
76where
77    T: Serialize,
78{
79    fn serialize(&self) -> String {
80        let aux_vec = self
81            .iter()
82            .map(Serialize::serialize)
83            .collect::<Vec<String>>();
84        let mut s = String::new();
85        s.push('#');
86        s.push('{');
87        s.push_str(&aux_vec.join(", "));
88        s.push('}');
89        s
90    }
91}
92
93impl<T> Serialize for LinkedList<T>
94where
95    T: Serialize,
96{
97    fn serialize(&self) -> String {
98        let aux_vec = self
99            .iter()
100            .map(Serialize::serialize)
101            .collect::<Vec<String>>();
102        let mut s = String::new();
103        s.push('(');
104        s.push_str(&aux_vec.join(", "));
105        s.push(')');
106        s
107    }
108}
109
110#[cfg(feature = "std")]
111impl<T, H: std::hash::BuildHasher> Serialize for std::collections::HashMap<String, T, H>
112where
113    T: Serialize,
114{
115    fn serialize(&self) -> String {
116        let aux_vec = self
117            .iter()
118            .map(|(k, v)| format!(":{} {}", k.replace([' ', '_'], "-"), v.serialize()))
119            .collect::<Vec<String>>();
120        let mut s = String::new();
121        s.push('{');
122        s.push_str(&aux_vec.join(", "));
123        s.push('}');
124        s
125    }
126}
127
128#[cfg(feature = "std")]
129impl<T, H: ::std::hash::BuildHasher> Serialize for std::collections::HashMap<&str, T, H>
130where
131    T: Serialize,
132{
133    fn serialize(&self) -> String {
134        let aux_vec = self
135            .iter()
136            .map(|(k, v)| format!(":{} {}", k.replace([' ', '_'], "-"), v.serialize()))
137            .collect::<Vec<String>>();
138        let mut s = String::new();
139        s.push('{');
140        s.push_str(&aux_vec.join(", "));
141        s.push('}');
142        s
143    }
144}
145
146impl<T> Serialize for BTreeMap<String, T>
147where
148    T: Serialize,
149{
150    fn serialize(&self) -> String {
151        let aux_vec = self
152            .iter()
153            .map(|(k, v)| format!(":{} {}", k.replace([' ', '_'], "-"), v.serialize()))
154            .collect::<Vec<String>>();
155        let mut s = String::new();
156        s.push('{');
157        s.push_str(&aux_vec.join(", "));
158        s.push('}');
159        s
160    }
161}
162
163impl<T> Serialize for BTreeMap<&str, T>
164where
165    T: Serialize,
166{
167    fn serialize(&self) -> String {
168        let aux_vec = self
169            .iter()
170            .map(|(k, v)| format!(":{} {}", k.replace([' ', '_'], "-"), v.serialize()))
171            .collect::<Vec<String>>();
172        let mut s = String::new();
173        s.push('{');
174        s.push_str(&aux_vec.join(", "));
175        s.push('}');
176        s
177    }
178}
179
180// Primitive Types
181ser_primitives![i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64, bool];
182
183impl Serialize for () {
184    fn serialize(&self) -> String {
185        "nil".to_string()
186    }
187}
188
189impl Serialize for String {
190    fn serialize(&self) -> String {
191        format!("{self:?}")
192    }
193}
194
195impl Serialize for &str {
196    fn serialize(&self) -> String {
197        format!("{self:?}")
198    }
199}
200
201impl Serialize for char {
202    fn serialize(&self) -> String {
203        format!("\\{self}")
204    }
205}
206
207impl<T> Serialize for Option<T>
208where
209    T: Serialize,
210{
211    fn serialize(&self) -> String {
212        self.as_ref().map_or_else(
213            || String::from("nil"),
214            crate::serialize::Serialize::serialize,
215        )
216    }
217}
218
219// Complex types
220impl<A: Serialize> Serialize for (A,) {
221    fn serialize(&self) -> String {
222        format!("({})", self.0.serialize())
223    }
224}
225
226impl<A: Serialize, B: Serialize> Serialize for (A, B) {
227    fn serialize(&self) -> String {
228        format!("({}, {})", self.0.serialize(), self.1.serialize())
229    }
230}
231
232impl<A: Serialize, B: Serialize, C: Serialize> Serialize for (A, B, C) {
233    fn serialize(&self) -> String {
234        format!(
235            "({}, {}, {})",
236            self.0.serialize(),
237            self.1.serialize(),
238            self.2.serialize()
239        )
240    }
241}
242
243impl<A: Serialize, B: Serialize, C: Serialize, D: Serialize> Serialize for (A, B, C, D) {
244    fn serialize(&self) -> String {
245        format!(
246            "({}, {}, {}, {})",
247            self.0.serialize(),
248            self.1.serialize(),
249            self.2.serialize(),
250            self.3.serialize()
251        )
252    }
253}
254
255impl<A: Serialize, B: Serialize, C: Serialize, D: Serialize, E: Serialize> Serialize
256    for (A, B, C, D, E)
257{
258    fn serialize(&self) -> String {
259        format!(
260            "({}, {}, {}, {}, {})",
261            self.0.serialize(),
262            self.1.serialize(),
263            self.2.serialize(),
264            self.3.serialize(),
265            self.4.serialize()
266        )
267    }
268}
269
270impl<A: Serialize, B: Serialize, C: Serialize, D: Serialize, E: Serialize, F: Serialize> Serialize
271    for (A, B, C, D, E, F)
272{
273    fn serialize(&self) -> String {
274        format!(
275            "({}, {}, {}, {}, {}, {})",
276            self.0.serialize(),
277            self.1.serialize(),
278            self.2.serialize(),
279            self.3.serialize(),
280            self.4.serialize(),
281            self.5.serialize()
282        )
283    }
284}
285
286#[cfg(test)]
287mod test {
288    use alloc::collections::BTreeSet;
289    use alloc::vec;
290
291    use super::*;
292
293    #[test]
294    fn unit() {
295        assert_eq!(().serialize(), "nil");
296    }
297
298    #[test]
299    fn primitive_types() {
300        let i = -34i32;
301        assert_eq!(i.serialize(), String::from("-34"));
302        assert_eq!('c'.serialize(), String::from("\\c"));
303        assert_eq!(8i8.serialize(), String::from("8"));
304        assert_eq!(8i16.serialize(), String::from("8"));
305        assert_eq!(8i32.serialize(), String::from("8"));
306        assert_eq!(8i64.serialize(), String::from("8"));
307        assert_eq!(8i64.serialize(), String::from("8"));
308        assert_eq!(8isize.serialize(), String::from("8"));
309        assert_eq!(128u8.serialize(), String::from("128"));
310        assert_eq!(128u16.serialize(), String::from("128"));
311        assert_eq!(128u32.serialize(), String::from("128"));
312        assert_eq!(128u64.serialize(), String::from("128"));
313        assert_eq!(128u64.serialize(), String::from("128"));
314        assert_eq!(128usize.serialize(), String::from("128"));
315        assert_eq!(true.serialize(), String::from("true"));
316    }
317
318    #[test]
319    fn tuples() {
320        let t2 = (12i32, 3.5f32);
321        let t3 = (12i32, 3.5f32, "oi");
322        let t4 = (12i32, 3.5f32, "oi", 'd');
323
324        assert_eq!(t2.serialize(), "(12, 3.5)");
325        assert_eq!(t3.serialize(), "(12, 3.5, \"oi\")");
326        assert_eq!(t4.serialize(), "(12, 3.5, \"oi\", \\d)");
327    }
328
329    #[test]
330    fn vectors() {
331        let v_i8 = vec![3i8, 12i8, 24i8, 72i8];
332        let v_u16 = vec![3u16, 12u16, 24u16, 72u16];
333        let v_f32 = vec![3.0f32, 12.1f32, 24.2f32, 72.3f32];
334        let v_i64 = vec![3i64, 12i64, 24i64, 72i64];
335        let v_u64 = vec![3u64, 12u64, 24u64, 72u64];
336        let v_bool = vec![true, false];
337
338        assert_eq!(v_i8.serialize(), "[3, 12, 24, 72]");
339        assert_eq!(v_u16.serialize(), "[3, 12, 24, 72]");
340        assert_eq!(v_f32.serialize(), "[3.0, 12.1, 24.2, 72.3]");
341        assert_eq!(v_i64.serialize(), "[3, 12, 24, 72]");
342        assert_eq!(v_u64.serialize(), "[3, 12, 24, 72]");
343        assert_eq!(v_bool.serialize(), "[true, false]");
344    }
345
346    #[test]
347    fn literals_vec() {
348        let v_str = vec!["aba", "cate", "azul"];
349        let v_string = vec!["aba".to_string(), "cate".to_string(), "azul".to_string()];
350
351        assert_eq!(v_str.serialize(), "[\"aba\", \"cate\", \"azul\"]");
352        assert_eq!(v_string.serialize(), "[\"aba\", \"cate\", \"azul\"]");
353    }
354
355    #[test]
356    fn hashsets() {
357        use alloc::collections::BTreeSet;
358
359        let set_i8 = (vec![3i8, 12i8, 24i8, 72i8]
360            .into_iter()
361            .collect::<BTreeSet<i8>>())
362        .serialize();
363        let set_u16 = (vec![3u16, 12u16, 24u16, 72u16]
364            .into_iter()
365            .collect::<BTreeSet<u16>>())
366        .serialize();
367        let set_i64 = (vec![3i64, 12i64, 24i64, 72i64]
368            .into_iter()
369            .collect::<BTreeSet<i64>>())
370        .serialize();
371        let set_bool = (vec![true, false].into_iter().collect::<BTreeSet<bool>>()).serialize();
372        let set_str = (vec!["aba", "cate", "azul"]
373            .into_iter()
374            .collect::<BTreeSet<&str>>())
375        .serialize();
376        let set_string = (vec!["aba".to_string(), "cate".to_string(), "azul".to_string()]
377            .into_iter()
378            .collect::<BTreeSet<String>>())
379        .serialize();
380
381        assert!(
382            set_i8.contains("#{")
383                && set_i8.contains(',')
384                && set_i8.contains('3')
385                && set_i8.contains('}')
386        );
387        assert!(
388            set_u16.contains("#{")
389                && set_u16.contains(',')
390                && set_u16.contains('3')
391                && set_u16.contains('}')
392        );
393        assert!(
394            set_i64.contains("#{")
395                && set_i64.contains(',')
396                && set_i64.contains('3')
397                && set_i64.contains('}')
398        );
399        assert!(
400            set_bool.contains("#{")
401                && set_bool.contains(',')
402                && set_bool.contains("true")
403                && set_bool.contains("false")
404                && set_bool.contains('}')
405        );
406        assert!(
407            set_str.contains("#{")
408                && set_str.contains(',')
409                && set_str.contains("\"aba\"")
410                && set_str.contains("\"cate\"")
411                && set_str.contains('}')
412        );
413        assert!(
414            set_string.contains("#{")
415                && set_string.contains(',')
416                && set_string.contains("\"aba\"")
417                && set_string.contains("\"cate\"")
418                && set_string.contains('}')
419        );
420    }
421
422    #[test]
423    fn btreesets() {
424        let set_i8 = (vec![3i8, 12i8, 24i8, 72i8]
425            .into_iter()
426            .collect::<BTreeSet<i8>>())
427        .serialize();
428        let set_u16 = (vec![3u16, 12u16, 24u16, 72u16]
429            .into_iter()
430            .collect::<BTreeSet<u16>>())
431        .serialize();
432        let set_i64 = (vec![3i64, 12i64, 24i64, 72i64]
433            .into_iter()
434            .collect::<BTreeSet<i64>>())
435        .serialize();
436        let set_bool = (vec![true, false].into_iter().collect::<BTreeSet<bool>>()).serialize();
437        let set_str = (vec!["aba", "cate", "azul"]
438            .into_iter()
439            .collect::<BTreeSet<&str>>())
440        .serialize();
441        let set_string = (vec!["aba".to_string(), "cate".to_string(), "azul".to_string()]
442            .into_iter()
443            .collect::<BTreeSet<String>>())
444        .serialize();
445
446        assert!(
447            set_i8.contains("#{")
448                && set_i8.contains(',')
449                && set_i8.contains('3')
450                && set_i8.contains('}')
451        );
452        assert!(
453            set_u16.contains("#{")
454                && set_u16.contains(',')
455                && set_u16.contains('3')
456                && set_u16.contains('}')
457        );
458        assert!(
459            set_i64.contains("#{")
460                && set_i64.contains(',')
461                && set_i64.contains('3')
462                && set_i64.contains('}')
463        );
464        assert!(
465            set_bool.contains("#{")
466                && set_bool.contains(',')
467                && set_bool.contains("true")
468                && set_bool.contains("false")
469                && set_bool.contains('}')
470        );
471        assert!(
472            set_str.contains("#{")
473                && set_str.contains(',')
474                && set_str.contains("\"aba\"")
475                && set_str.contains("\"cate\"")
476                && set_str.contains('}')
477        );
478        assert!(
479            set_string.contains("#{")
480                && set_string.contains(',')
481                && set_string.contains("\"aba\"")
482                && set_string.contains("\"cate\"")
483                && set_string.contains('}')
484        );
485    }
486
487    #[test]
488    fn lists() {
489        use alloc::collections::LinkedList;
490
491        let list_i8 = (vec![3i8, 12i8, 24i8, 72i8]
492            .into_iter()
493            .collect::<LinkedList<i8>>())
494        .serialize();
495        let list_u16 = (vec![3u16, 12u16, 24u16, 72u16]
496            .into_iter()
497            .collect::<LinkedList<u16>>())
498        .serialize();
499        let list_i64 = (vec![3i64, 12i64, 24i64, 72i64]
500            .into_iter()
501            .collect::<LinkedList<i64>>())
502        .serialize();
503        let list_f64 = (vec![3.1f64, 12.2f64, 24.3f64, 72.4f64]
504            .into_iter()
505            .collect::<LinkedList<f64>>())
506        .serialize();
507        let list_bool = (vec![true, false].into_iter().collect::<LinkedList<bool>>()).serialize();
508        let list_str = (vec!["aba", "cate", "azul"]
509            .into_iter()
510            .collect::<LinkedList<&str>>())
511        .serialize();
512        let list_string = (vec!["aba".to_string(), "cate".to_string(), "azul".to_string()]
513            .into_iter()
514            .collect::<LinkedList<String>>())
515        .serialize();
516
517        assert_eq!(list_i8, "(3, 12, 24, 72)");
518        assert_eq!(list_u16, "(3, 12, 24, 72)");
519        assert_eq!(list_i64, "(3, 12, 24, 72)");
520        assert_eq!(list_f64, "(3.1, 12.2, 24.3, 72.4)");
521        assert_eq!(list_bool, "(true, false)");
522        assert_eq!(list_str, "(\"aba\", \"cate\", \"azul\")");
523        assert_eq!(list_string, "(\"aba\", \"cate\", \"azul\")");
524    }
525
526    #[test]
527    fn hashmap() {
528        let m_i64 = map! {"hello world" => 5i64, "bye_bye" => 125i64}.serialize();
529        let m_bool =
530            map! {"hello world".to_string() => true, "bye_bye".to_string() => false}.serialize();
531        let m_str = map!{"hello world".to_string() => "this is str 1", "bye_bye".to_string() => "this is str 2"}.serialize();
532
533        assert!(
534            m_i64.contains(":hello-world 5")
535                && m_i64.contains(":bye-bye 125")
536                && m_i64.contains('{')
537                && m_i64.contains('}')
538        );
539        assert!(
540            m_bool.contains(":hello-world true")
541                && m_bool.contains(":bye-bye false")
542                && m_bool.contains('{')
543                && m_bool.contains('}')
544        );
545        assert!(
546            m_str.contains(":hello-world \"this is str 1\"")
547                && m_str.contains(":bye-bye \"this is str 2\"")
548                && m_str.contains('{')
549                && m_str.contains('}')
550        );
551    }
552
553    #[test]
554    fn multi_sized_tuples() {
555        assert_eq!((1,).serialize(), "(1)");
556        assert_eq!((1, "cool").serialize(), "(1, \"cool\")");
557        assert_eq!((1, "cool", false).serialize(), "(1, \"cool\", false)");
558        assert_eq!(
559            (1, "cool", false, 'z').serialize(),
560            "(1, \"cool\", false, \\z)"
561        );
562        assert_eq!(
563            (1, "cool", false, 'z', None::<String>).serialize(),
564            "(1, \"cool\", false, \\z, nil)"
565        );
566    }
567}