Repository: not-fl3/nanoserde
Pull request #50 (2022-11-11 04:18:17)

Additional collection types
* Add impls for hashset, linkedlist, btreeset
* add test for all new impls


Patch:
diff --git a/src/serde_bin.rs b/src/serde_bin.rs
index 6e9bce8..61a1ad0 100644
--- a/src/serde_bin.rs
+++ b/src/serde_bin.rs
@@ -2,14 +2,15 @@ use core::convert::TryInto;
 use core::hash::Hash;
 
 use alloc::boxed::Box;
+use alloc::collections::{LinkedList, BTreeSet};
 use alloc::string::{String, ToString};
 use alloc::vec::Vec;
 
 #[cfg(features = "no_std")]
-use hashbrown::HashMap;
+use hashbrown::{HashMap, HashSet};
 
 #[cfg(not(features = "no_std"))]
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 
 /// A trait for objects that can be serialized to binary.
 pub trait SerBin {
@@ -254,6 +255,87 @@ where
     }
 }
 
+impl<T> SerBin for LinkedList<T>
+where
+    T: SerBin,
+{
+    fn ser_bin(&self, s: &mut Vec<u8>) {
+        let len = self.len();
+        len.ser_bin(s);
+        for item in self.iter() {
+            item.ser_bin(s);
+        }
+    }
+}
+
+impl<T> DeBin for LinkedList<T>
+where
+    T: DeBin,
+{
+    fn de_bin(o: &mut usize, d: &[u8]) -> Result<LinkedList<T>, DeBinErr> {
+        let len: usize = DeBin::de_bin(o, d)?;
+        let mut out = LinkedList::new();
+        for _ in 0..len {
+            out.push_back(DeBin::de_bin(o, d)?)
+        }
+        Ok(out)
+    }
+}
+
+impl<T> SerBin for HashSet<T>
+where
+    T: SerBin,
+{
+    fn ser_bin(&self, s: &mut Vec<u8>) {
+        let len = self.len();
+        len.ser_bin(s);
+        for item in self.iter() {
+            item.ser_bin(s);
+        }
+    }
+}
+
+impl<T> DeBin for HashSet<T>
+where
+    T: DeBin + Hash + Eq,
+{
+    fn de_bin(o: &mut usize, d: &[u8]) -> Result<HashSet<T>, DeBinErr> {
+        let len: usize = DeBin::de_bin(o, d)?;
+        let mut out = HashSet::new();
+        for _ in 0..len {
+            out.insert(DeBin::de_bin(o, d)?);
+        }
+        Ok(out)
+    }
+}
+
+impl<T> SerBin for BTreeSet<T>
+where
+    T: SerBin,
+{
+    fn ser_bin(&self, s: &mut Vec<u8>) {
+        let len = self.len();
+        len.ser_bin(s);
+        for item in self.iter() {
+            item.ser_bin(s);
+        }
+    }
+}
+
+impl<T> DeBin for BTreeSet<T>
+where
+    T: DeBin + Ord,
+{
+    fn de_bin(o: &mut usize, d: &[u8]) -> Result<BTreeSet<T>, DeBinErr> {
+        let len: usize = DeBin::de_bin(o, d)?;
+        let mut out = BTreeSet::new();
+        for _ in 0..len {
+            out.insert(DeBin::de_bin(o, d)?);
+        }
+        Ok(out)
+    }
+}
+
 impl<T> SerBin for Option<T>
 where
     T: SerBin,
diff --git a/src/serde_json.rs b/src/serde_json.rs
index aadd791..77148f0 100644
--- a/src/serde_json.rs
+++ b/src/serde_json.rs
@@ -2,15 +2,16 @@ use core::hash::Hash;
 use core::str::Chars;
 
 use alloc::boxed::Box;
+use alloc::collections::{LinkedList, BTreeSet};
 use alloc::format;
 use alloc::string::{String, ToString};
 use alloc::vec::Vec;
 
 #[cfg(features = "no_std")]
-use hashbrown::HashMap;
+use hashbrown::{HashMap, HashSet};
 
 #[cfg(not(features = "no_std"))]
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 
 /// The internal state of a JSON serialization.
 pub struct SerJsonState {
@@ -845,6 +846,119 @@ where
     }
 }
 
+impl<T> SerJson for HashSet<T>
+where
+    T: SerJson,
+{
+    fn ser_json(&self, d: usize, s: &mut SerJsonState) {
+        s.out.push('[');
+        if self.len() > 0 {
+            let last = self.len() - 1;
+            for (index, item) in self.iter().enumerate() {
+                s.indent(d + 1);
+                item.ser_json(d + 1, s);
+                if index != last {
+                    s.out.push(',');
+                }
+            }
+        }
+        s.out.push(']');
+    }
+}
+
+impl<T> DeJson for HashSet<T>
+where
+    T: DeJson + Hash + Eq,
+{
+    fn de_json(s: &mut DeJsonState, i: &mut Chars) -> Result<HashSet<T>, DeJsonErr> {
+        let mut out = HashSet::new();
+        s.block_open(i)?;
+
+        while s.tok != DeJsonTok::BlockClose {
+            out.insert(DeJson::de_json(s, i)?);
+            s.eat_comma_block(i)?;
+        }
+        s.block_close(i)?;
+        Ok(out)
+    }
+}
+
+impl<T> SerJson for LinkedList<T>
+where
+    T: SerJson,
+{
+    fn ser_json(&self, d: usize, s: &mut SerJsonState) {
+        s.out.push('[');
+        if self.len() > 0 {
+            let last = self.len() - 1;
+            for (index, item) in self.iter().enumerate() {
+                s.indent(d + 1);
+                item.ser_json(d + 1, s);
+                if index != last {
+                    s.out.push(',');
+                }
+            }
+        }
+        s.out.push(']');
+    }
+}
+
+impl<T> DeJson for LinkedList<T>
+where
+    T: DeJson,
+{
+    fn de_json(s: &mut DeJsonState, i: &mut Chars) -> Result<LinkedList<T>, DeJsonErr> {
+        let mut out = LinkedList::new();
+        s.block_open(i)?;
+
+        while s.tok != DeJsonTok::BlockClose {
+            out.push_back(DeJson::de_json(s, i)?);
+            s.eat_comma_block(i)?;
+        }
+        s.block_close(i)?;
+        Ok(out)
+    }
+}
+
+impl<T> SerJson for BTreeSet<T>
+where
+    T: SerJson,
+{
+    fn ser_json(&self, d: usize, s: &mut SerJsonState) {
+        s.out.push('[');
+        if self.len() > 0 {
+            let last = self.len() - 1;
+            for (index, item) in self.iter().enumerate() {
+                s.indent(d + 1);
+                item.ser_json(d + 1, s);
+                if index != last {
+                    s.out.push(',');
+                }
+            }
+        }
+        s.out.push(']');
+    }
+}
+
+impl<T> DeJson for BTreeSet<T>
+where
+    T: DeJson + Ord,
+{
+    fn de_json(s: &mut DeJsonState, i: &mut Chars) -> Result<BTreeSet<T>, DeJsonErr> {
+        let mut out = BTreeSet::new();
+        s.block_open(i)?;
+
+        while s.tok != DeJsonTok::BlockClose {
+            out.insert(DeJson::de_json(s, i)?);
+            s.eat_comma_block(i)?;
+        }
+        s.block_close(i)?;
+        Ok(out)
+    }
+}
+
+
+
 impl<T> SerJson for [T]
 where
     T: SerJson,
diff --git a/src/serde_ron.rs b/src/serde_ron.rs
index f793513..6c59b6a 100644
--- a/src/serde_ron.rs
+++ b/src/serde_ron.rs
@@ -2,15 +2,16 @@ use core::hash::Hash;
 use core::str::Chars;
 
 use alloc::boxed::Box;
+use alloc::collections::{LinkedList, BTreeSet};
 use alloc::format;
 use alloc::string::{String, ToString};
 use alloc::vec::Vec;
 
 #[cfg(features = "no_std")]
-use hashbrown::HashMap;
+use hashbrown::{HashMap, HashSet};
 
 #[cfg(not(features = "no_std"))]
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 
 /// The internal state of a RON serialization.
 pub struct SerRonState {
@@ -50,7 +51,7 @@ impl SerRonState {
 pub trait SerRon {
     /// Serialize Self to a RON string.
     ///
-    /// This is a convenient wrapper around `ser_json`.
+    /// This is a convenient wrapper around `ser_ron`.
     fn serialize_ron(&self) -> String {
         let mut s = SerRonState { out: String::new() };
         self.ser_ron(0, &mut s);
@@ -882,6 +883,118 @@ where
     }
 }
 
+impl<T> SerRon for HashSet<T>
+where
+    T: SerRon,
+{
+    fn ser_ron(&self, d: usize, s: &mut SerRonState) {
+        s.out.push('[');
+        if self.len() > 0 {
+            let last = self.len() - 1;
+            for (index, item) in self.iter().enumerate() {
+                s.indent(d + 1);
+                item.ser_ron(d + 1, s);
+                if index != last {
+                    s.out.push(',');
+                }
+            }
+        }
+        s.out.push(']');
+    }
+}
+
+impl<T> DeRon for HashSet<T>
+where
+    T: DeRon + Hash + Eq,
+{
+    fn de_ron(s: &mut DeRonState, i: &mut Chars) -> Result<HashSet<T>, DeRonErr> {
+        let mut out = HashSet::new();
+        s.block_open(i)?;
+
+        while s.tok != DeRonTok::BlockClose {
+            out.insert(DeRon::de_ron(s, i)?);
+            s.eat_comma_block(i)?;
+        }
+        s.block_close(i)?;
+        Ok(out)
+    }
+}
+
+impl<T> SerRon for LinkedList<T>
+where
+    T: SerRon,
+{
+    fn ser_ron(&self, d: usize, s: &mut SerRonState) {
+        s.out.push('[');
+        if self.len() > 0 {
+            let last = self.len() - 1;
+            for (index, item) in self.iter().enumerate() {
+                s.indent(d + 1);
+                item.ser_ron(d + 1, s);
+                if index != last {
+                    s.out.push(',');
+                }
+            }
+        }
+        s.out.push(']');
+    }
+}
+
+impl<T> DeRon for LinkedList<T>
+where
+    T: DeRon,
+{
+    fn de_ron(s: &mut DeRonState, i: &mut Chars) -> Result<LinkedList<T>, DeRonErr> {
+        let mut out = LinkedList::new();
+        s.block_open(i)?;
+
+        while s.tok != DeRonTok::BlockClose {
+            out.push_back(DeRon::de_ron(s, i)?);
+            s.eat_comma_block(i)?;
+        }
+        s.block_close(i)?;
+        Ok(out)
+    }
+}
+
+impl<T> SerRon for BTreeSet<T>
+where
+    T: SerRon,
+{
+    fn ser_ron(&self, d: usize, s: &mut SerRonState) {
+        s.out.push('[');
+        if self.len() > 0 {
+            let last = self.len() - 1;
+            for (index, item) in self.iter().enumerate() {
+                s.indent(d + 1);
+                item.ser_ron(d + 1, s);
+                if index != last {
+                    s.out.push(',');
+                }
+            }
+        }
+        s.out.push(']');
+    }
+}
+
+impl<T> DeRon for BTreeSet<T>
+where
+    T: DeRon + Ord,
+{
+    fn de_ron(s: &mut DeRonState, i: &mut Chars) -> Result<BTreeSet<T>, DeRonErr> {
+        let mut out = BTreeSet::new();
+        s.block_open(i)?;
+
+        while s.tok != DeRonTok::BlockClose {
+            out.insert(DeRon::de_ron(s, i)?);
+            s.eat_comma_block(i)?;
+        }
+        s.block_close(i)?;
+        Ok(out)
+    }
+}
+
+
 impl<T> SerRon for [T]
 where
     T: SerRon,


Test patch:
diff --git a/tests/bin.rs b/tests/bin.rs
index 2872326..4d88eb3 100644
--- a/tests/bin.rs
+++ b/tests/bin.rs
@@ -1,3 +1,5 @@
+use std::collections::{LinkedList, HashSet, BTreeSet};
+
 use nanoserde::{DeBin, SerBin};
 
 #[test]
@@ -198,3 +200,27 @@ fn pub_tuple_struct() {
     #[derive(DeBin, SerBin, PartialEq)]
     struct Foo(pub [u8; 3]);
 }
+
+#[test]
+fn collections() {
+    #[derive(DeBin, SerBin, PartialEq, Debug)]
+    pub struct Test {
+        pub a: Vec<i32>,
+        pub b: LinkedList<f32>,
+        pub c: HashSet<i32>,
+        pub d: BTreeSet<i32>,
+    }
+
+    let test: Test = Test {
+        a: vec![1, 2, 3],
+        b: vec![1.0, 2.0, 3.0, 4.0].into_iter().collect(),
+        c: vec![1, 2, 3, 4, 5].into_iter().collect(),
+        d: vec![1, 2, 3, 4, 5, 6].into_iter().collect()
+    };
+
+    let bytes = SerBin::serialize_bin(&test);
+
+    let test_deserialized = DeBin::deserialize_bin(&bytes).unwrap();
+
+    assert_eq!(test, test_deserialized);
+}
\ No newline at end of file
diff --git a/tests/json.rs b/tests/json.rs
index 7cd0654..1f27bc2 100644
--- a/tests/json.rs
+++ b/tests/json.rs
@@ -1,6 +1,6 @@
 use nanoserde::{DeJson, SerJson};
 
-use std::collections::HashMap;
+use std::collections::{HashMap, LinkedList, HashSet, BTreeSet};
 
 #[test]
 fn de() {
@@ -410,6 +410,30 @@ fn exponents() {
     assert_eq!(foo.h, 0.01);
 }
 
+#[test]
+fn collections() {
+    #[derive(DeJson, SerJson, PartialEq, Debug)]
+    pub struct Test {
+        pub a: Vec<i32>,
+        pub b: LinkedList<f32>,
+        pub c: HashSet<i32>,
+        pub d: BTreeSet<i32>,
+    }
+
+    let test: Test = Test {
+        a: vec![1, 2, 3],
+        b: vec![1.0, 2.0, 3.0, 4.0].into_iter().collect(),
+        c: vec![1, 2, 3, 4, 5].into_iter().collect(),
+        d: vec![1, 2, 3, 4, 5, 6].into_iter().collect()
+    };
+
+    let bytes = SerJson::serialize_json(&test);
+
+    let test_deserialized = DeJson::deserialize_json(&bytes).unwrap();
+
+    assert_eq!(test, test_deserialized);
+}
+
 #[test]
 fn jsonerror() {
     #[derive(DeJson)]
diff --git a/tests/ron.rs b/tests/ron.rs
index 17370ac..e5e5a5a 100644
--- a/tests/ron.rs
+++ b/tests/ron.rs
@@ -1,6 +1,6 @@
 use nanoserde::{DeRon, SerRon};
 
-use std::collections::HashMap;
+use std::collections::{HashMap, LinkedList, HashSet, BTreeSet};
 
 #[test]
 fn ron_de() {
@@ -207,6 +207,30 @@ fn array() {
     assert_eq!(bar.floats_a, None);
 }
 
+#[test]
+fn collections() {
+    #[derive(DeRon, SerRon, PartialEq, Debug)]
+    pub struct Test {
+        pub a: Vec<i32>,
+        pub b: LinkedList<f32>,
+        pub c: HashSet<i32>,
+        pub d: BTreeSet<i32>,
+    }
+
+    let test: Test = Test {
+        a: vec![1, 2, 3],
+        b: vec![1.0, 2.0, 3.0, 4.0].into_iter().collect(),
+        c: vec![1, 2, 3, 4, 5].into_iter().collect(),
+        d: vec![1, 2, 3, 4, 5, 6].into_iter().collect()
+    };
+
+    let bytes = SerRon::serialize_ron(&test);
+
+    let test_deserialized = DeRon::deserialize_ron(&bytes).unwrap();
+
+    assert_eq!(test, test_deserialized);
+}
+
 #[test]
 fn path_type() {
     #[derive(DeRon)]