Repository: not-fl3/nanoserde
Pull request #44 (2022-07-09 18:41:26)

Added beginning support for generics to serbin and debin proc macros
Did some work on the proc macros and they can now derive impls for some structs and enums with generics. Where bounds probably wont work yet. Should be reusable work for the json and ron macros as well

expenses: Hey @knickish are you planning on working more on this? Should someone take it over?
expenses: I've made a new branch for this here: https://github.com/not-fl3/nanoserde/compare/master...expenses:nanoserde:generics-simplify?expand=1
expenses: > > Hey @knickish are you planning on working more on this? Should someone take it over?
> 
> Yeah i am, I was dogfooding and found some issues with associated types parsing, will put it back up when I have time to fix them.

Ah right. Well maybe you could think about merging the changes I've made here: https://github.com/knickish/nanoserde/compare/generics_mvp...expenses:nanoserde:generics-simplify?expand=1 ?
not-fl3: I am so sorry on being super slow with reviewing this

It looks good to me, if you both @expenses @knickish agrees on the final PR - I'll merge it!


knickish: @expenses @not-fl3 Sounds good, I'll pull in those fixes and put it back up in the next day or two
knickish: Tested with and without no-std, seems to work.
not-fl3: Okay, let's merge it
@expenses feel free to make follow up PR with your changes! 

Patch:
diff --git a/derive/Cargo.toml b/derive/Cargo.toml
index d7bff7f..90b7372 100644
--- a/derive/Cargo.toml
+++ b/derive/Cargo.toml
@@ -9,4 +9,9 @@ license = "MIT"
 [lib]
 proc-macro = true
 
+[features]
+default = []
+no_std = ["dep:hashbrown"]
+
 [dependencies]
+hashbrown = { version = "0.12.3", optional = true }
diff --git a/derive/src/lib.rs b/derive/src/lib.rs
index 9464441..46ab935 100644
--- a/derive/src/lib.rs
+++ b/derive/src/lib.rs
@@ -1,4 +1,4 @@
-#![no_std]
+#![cfg_attr(features = "no_std", no_std)]
 
 extern crate alloc;
 extern crate proc_macro;
diff --git a/derive/src/parse.rs b/derive/src/parse.rs
index 8207059..e1a5bee 100644
--- a/derive/src/parse.rs
+++ b/derive/src/parse.rs
@@ -12,6 +12,14 @@ use alloc::{format, vec};
 
 use proc_macro::{Delimiter, Group, TokenStream, TokenTree};
 
+
+#[cfg(features = "no_std")]
+use hashbrown::HashMap;
+
+#[cfg(not(features = "no_std"))]
+use std::collections::HashMap;
+
+
 #[derive(Debug)]
 pub struct Attribute {
     pub name: String,
@@ -36,7 +44,7 @@ pub struct Field {
 }
 
 #[allow(dead_code)]
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub struct Type {
     pub is_option: bool,
     pub path: String,
@@ -48,6 +56,7 @@ pub struct Struct {
     pub named: bool,
     pub fields: Vec<Field>,
     pub attributes: Vec<Attribute>,
+    pub generics: HashMap<String, String>
 }
 
 #[derive(Debug)]
@@ -63,6 +72,7 @@ pub struct Enum {
     pub name: String,
     pub variants: Vec<EnumVariant>,
     pub attributes: Vec<Attribute>,
+    pub generics: HashMap<String, String>
 }
 
 #[allow(dead_code)]
@@ -186,7 +196,7 @@ pub fn next_group(source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Opt
 //     println!("{:?}", source.peek());
 // }
 
-fn next_type<T: Iterator<Item = TokenTree>>(mut source: &mut Peekable<T>) -> Option<Type> {
+fn next_type<T: Iterator<Item = TokenTree>>(mut source: &mut Peekable<T>, generic_typenames: &HashMap<String, String> ) -> Option<Type> {
     let group = next_group(&mut source);
     if group.is_some() {
         let mut group = group.unwrap().stream().into_iter().peekable();
@@ -196,7 +206,7 @@ fn next_type<T: Iterator<Item = TokenTree>>(mut source: &mut Peekable<T>) -> Opt
             path: "".to_string(),
         };
 
-        while let Some(next_ty) = next_type(&mut group) {
+        while let Some(next_ty) = next_type(&mut group, generic_typenames) {
             tuple_type.path.push_str(&format!("{}, ", next_ty.path));
         }
 
@@ -214,9 +224,9 @@ fn next_type<T: Iterator<Item = TokenTree>>(mut source: &mut Peekable<T>) -> Opt
 
     let angel_bracket = next_exact_punct(&mut source, "<");
     if angel_bracket.is_some() {
-        let mut generic_type = next_type(source).expect("Expecting generic argument");
+        let mut generic_type = next_type(source, generic_typenames).expect("Expecting generic argument");
         while let Some(_comma) = next_exact_punct(&mut source, ",") {
-            let next_ty = next_type(source).expect("Expecting generic argument");
+            let next_ty = next_type(source, generic_typenames).expect("Expecting generic argument");
             generic_type.path.push_str(&format!(", {}", next_ty.path));
         }
 
@@ -225,7 +235,7 @@ fn next_type<T: Iterator<Item = TokenTree>>(mut source: &mut Peekable<T>) -> Opt
 
         if ty == "Option" {
             Some(Type {
-                path: generic_type.path,
+                path: generic_type.path.clone(),
                 is_option: true,
             })
         } else {
@@ -236,7 +246,7 @@ fn next_type<T: Iterator<Item = TokenTree>>(mut source: &mut Peekable<T>) -> Opt
         }
     } else {
         Some(Type {
-            path: ty,
+            path: ty.clone(),
             is_option: false,
         })
     }
@@ -311,6 +321,7 @@ fn next_attributes_list(source: &mut Peekable<impl Iterator<Item = TokenTree>>)
 fn next_fields(
     mut body: &mut Peekable<impl Iterator<Item = TokenTree>>,
     named: bool,
+    generic_typenames: &HashMap<String, String>
 ) -> Vec<Field> {
     let mut fields = vec![];
 
@@ -330,7 +341,7 @@ fn next_fields(
             None
         };
 
-        let ty = next_type(&mut body).expect("Expected field type");
+        let ty = next_type(&mut body, &generic_typenames).expect("Expected field type");
         let _punct = next_punct(&mut body);
 
         fields.push(Field {
@@ -345,7 +356,7 @@ fn next_fields(
 
 fn next_struct(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Struct {
     let struct_name = next_ident(&mut source).expect("Unnamed structs are not supported");
-
+    let generic_types = get_bounds(source);
     let group = next_group(&mut source);
     // unit struct
     if group.is_none() {
@@ -357,8 +368,10 @@ fn next_struct(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> St
             fields: vec![],
             attributes: vec![],
             named: false,
+            generics: Default::default(),
         };
     };
+    
     let group = group.unwrap();
     let delimiter = group.delimiter();
     let named = match delimiter {
@@ -369,7 +382,7 @@ fn next_struct(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> St
     };
 
     let mut body = group.stream().into_iter().peekable();
-    let fields = next_fields(&mut body, named);
+    let fields = next_fields(&mut body, named, &generic_types);
 
     if named == false {
         next_exact_punct(&mut source, ";").expect("Expected ; on the end of tuple struct");
@@ -380,12 +393,13 @@ fn next_struct(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> St
         named,
         fields,
         attributes: vec![],
+        generics: generic_types
     }
 }
 
 fn next_enum(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Enum {
     let enum_name = next_ident(&mut source).expect("Unnamed enums are not supported");
-
+    let generic_types = get_bounds(source);
     let group = next_group(&mut source);
     // unit enum
     if group.is_none() {
@@ -393,7 +407,7 @@ fn next_enum(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Enum
             name: enum_name,
             variants: vec![],
             attributes: vec![],
-        };
+            generics: Default::default(),        };
     };
     let group = group.unwrap();
     let mut body = group.stream().into_iter().peekable();
@@ -428,7 +442,7 @@ fn next_enum(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Enum
         };
         {
             let mut body = group.stream().into_iter().peekable();
-            let fields = next_fields(&mut body, named);
+            let fields = next_fields(&mut body, named, &generic_types);
             variants.push(EnumVariant {
                 name: variant_name,
                 named,
@@ -444,7 +458,103 @@ fn next_enum(mut source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Enum
         name: enum_name,
         variants,
         attributes: vec![],
+        generics: generic_types
+    }
+}
+
+fn get_bounds(source: &mut Peekable<impl Iterator<Item = TokenTree>>) -> HashMap<String, String> {
+    let mut ret = HashMap::new();
+
+    match source.peek() {
+        Some(content) if content.to_string() == "<" => {
+            source.next();
+            let mut typename = "".to_string(); 
+            let mut generic_bound = String::new();
+            let mut in_type = true;
+            while let Some(tok) = source.next() {
+                match tok.to_string().as_str() {
+                    ">" => {
+                        ret.insert(typename.clone(), generic_bound.clone());
+                        typename.clear();
+                        generic_bound.clear();
+                        break
+                    },
+                    ":" => {
+                        if in_type {
+                            in_type = false
+                        } else {
+                            generic_bound += ":";
+                        }
+                    },
+                    "," => {
+                        ret.insert(typename.clone(), generic_bound.clone());
+                        typename.clear();
+                        generic_bound.clear();
+                        in_type = true
+                    },
+                    c => {
+                        if in_type {
+                            typename+=c;
+                        } else {
+                            generic_bound += c;
+                        }
+                    }
+                }
+            }
+        },
+        _ => ()
+    }
+    ret
+}
+
+pub(crate) fn struct_bounds_strings(struct_: &Struct, bound_name: &str) -> (String, String) {
+    let generics: &HashMap<String, String> = &struct_.generics;
+    if generics.is_empty() {
+        return ("".to_string(), "".to_string());
+    }
+    let mut generic_w_bounds = "<".to_string();
+    for (generic, bounds) in generics.iter() {
+        let mut bounds = bounds.to_string();
+        if !bounds.is_empty() {
+            bounds += " + ";
+        }
+        bounds += &format!("nanoserde::{}", bound_name);
+
+        generic_w_bounds += &format!("{}: {}, ", generic, bounds);
+    }
+    generic_w_bounds += ">";
+
+    let mut generic_no_bounds = "<".to_string();
+    for (generic, _bounds) in generics.iter() {
+        generic_no_bounds += &format!("{}, ", generic);
+    }
+    generic_no_bounds += ">";
+    return (generic_w_bounds, generic_no_bounds);
+}
+
+pub(crate) fn enum_bounds_strings(enum_: &Enum, bound_name: &str) -> (String, String) {
+    let generics: &HashMap<String, String> = &enum_.generics;
+
+    if generics.is_empty() {
+        return ("".to_string(), "".to_string());
+    }
+    let mut generic_w_bounds = "<".to_string();
+    for (generic, bounds) in generics.iter() {
+        let mut bounds = bounds.to_string();
+        if !bounds.is_empty() {
+            bounds += " + ";
+        }
+        bounds += &format!("nanoserde::{}", bound_name);
+        generic_w_bounds += &format!("{}: {}, ", generic, bounds);
+    }
+    generic_w_bounds += ">";
+
+    let mut generic_no_bounds = "<".to_string();
+    for (generic, _bounds) in generics.iter() {
+        generic_no_bounds += &format!("{}, ", generic);
     }
+    generic_no_bounds += ">";
+    return (generic_w_bounds, generic_no_bounds);
 }
 
 pub fn parse_data(input: TokenStream) -> Data {
diff --git a/derive/src/serde_bin.rs b/derive/src/serde_bin.rs
index 8544ffe..184be49 100644
--- a/derive/src/serde_bin.rs
+++ b/derive/src/serde_bin.rs
@@ -1,7 +1,7 @@
 use alloc::format;
 use alloc::string::String;
 
-use crate::parse::{Enum, Struct};
+use crate::parse::{Enum, Struct, struct_bounds_strings, enum_bounds_strings};
 
 use proc_macro::TokenStream;
 
@@ -35,6 +35,7 @@ pub fn derive_de_bin_proxy(proxy_type: &str, type_: &str) -> TokenStream {
 
 pub fn derive_ser_bin_struct(struct_: &Struct) -> TokenStream {
     let mut body = String::new();
+    let (generic_w_bounds, generic_no_bounds) = struct_bounds_strings(struct_, "SerBin");
 
     for field in &struct_.fields {
         if let Some(proxy) = crate::shared::attrs_proxy(&field.attributes) {
@@ -54,12 +55,12 @@ pub fn derive_ser_bin_struct(struct_: &Struct) -> TokenStream {
         }
     }
     format!(
-        "impl SerBin for {} {{
+        "impl{} SerBin for {}{} {{
             fn ser_bin(&self, s: &mut Vec<u8>) {{
                 {}
             }}
         }}",
-        struct_.name, body
+        generic_w_bounds, struct_.name, generic_no_bounds, body
     )
     .parse()
     .unwrap()
@@ -67,6 +68,7 @@ pub fn derive_ser_bin_struct(struct_: &Struct) -> TokenStream {
 
 pub fn derive_ser_bin_struct_unnamed(struct_: &Struct) -> TokenStream {
     let mut body = String::new();
+    let (generic_w_bounds, generic_no_bounds) = struct_bounds_strings(struct_, "SerBin");
 
     for (n, field) in struct_.fields.iter().enumerate() {
         if let Some(proxy) = crate::shared::attrs_proxy(&field.attributes) {
@@ -77,12 +79,12 @@ pub fn derive_ser_bin_struct_unnamed(struct_: &Struct) -> TokenStream {
         }
     }
     format!(
-        "impl SerBin for {} {{
+        "impl{} SerBin for {}{} {{
             fn ser_bin(&self, s: &mut Vec<u8>) {{
                 {}
             }}
         }}",
-        struct_.name, body
+        generic_w_bounds, struct_.name, generic_no_bounds, body
     )
     .parse()
     .unwrap()
@@ -90,6 +92,7 @@ pub fn derive_ser_bin_struct_unnamed(struct_: &Struct) -> TokenStream {
 
 pub fn derive_de_bin_struct(struct_: &Struct) -> TokenStream {
     let mut body = String::new();
+    let (generic_w_bounds, generic_no_bounds) = struct_bounds_strings(struct_, "DeBin");
 
     for field in &struct_.fields {
         if let Some(proxy) = crate::shared::attrs_proxy(&field.attributes) {
@@ -107,14 +110,14 @@ pub fn derive_de_bin_struct(struct_: &Struct) -> TokenStream {
     }
 
     format!(
-        "impl DeBin for {} {{
+        "impl{} DeBin for {}{} {{
             fn de_bin(o:&mut usize, d:&[u8]) -> core::result::Result<Self, nanoserde::DeBinErr> {{
                 core::result::Result::Ok(Self {{
                     {}
                 }})
             }}
         }}",
-        struct_.name, body
+        generic_w_bounds, struct_.name, generic_no_bounds, body
     )
     .parse()
     .unwrap()
@@ -122,6 +125,7 @@ pub fn derive_de_bin_struct(struct_: &Struct) -> TokenStream {
 
 pub fn derive_de_bin_struct_unnamed(struct_: &Struct) -> TokenStream {
     let mut body = String::new();
+    let (generic_w_bounds, generic_no_bounds) = struct_bounds_strings(struct_, "DeBin");
 
     for (n, field) in struct_.fields.iter().enumerate() {
         if let Some(proxy) = crate::shared::attrs_proxy(&field.attributes) {
@@ -135,14 +139,14 @@ pub fn derive_de_bin_struct_unnamed(struct_: &Struct) -> TokenStream {
     }
 
     format!(
-        "impl DeBin for {} {{
+        "impl{} DeBin for {}{} {{
             fn de_bin(o:&mut usize, d:&[u8]) -> core::result::Result<Self, nanoserde::DeBinErr> {{
                 core::result::Result::Ok(Self {{
                     {}
                 }})
             }}
         }}",
-        struct_.name, body
+        generic_w_bounds, struct_.name, generic_no_bounds, body
     )
     .parse()
     .unwrap()
@@ -150,6 +154,7 @@ pub fn derive_de_bin_struct_unnamed(struct_: &Struct) -> TokenStream {
 
 pub fn derive_ser_bin_enum(enum_: &Enum) -> TokenStream {
     let mut r = String::new();
+    let (generic_w_bounds, generic_no_bounds) = enum_bounds_strings(enum_, "SerBin");
 
     for (index, variant) in enum_.variants.iter().enumerate() {
         let lit = format!("{}u16", index);
@@ -187,14 +192,14 @@ pub fn derive_ser_bin_enum(enum_: &Enum) -> TokenStream {
     }
 
     format!(
-        "impl SerBin for {} {{
+        "impl{} SerBin for {}{} {{
             fn ser_bin(&self, s: &mut Vec<u8>) {{
                 match self {{
                   {}
                 }}
             }}
         }}",
-        enum_.name, r
+        generic_w_bounds,enum_.name,generic_no_bounds, r
     )
     .parse()
     .unwrap()
@@ -202,6 +207,7 @@ pub fn derive_ser_bin_enum(enum_: &Enum) -> TokenStream {
 
 pub fn derive_de_bin_enum(enum_: &Enum) -> TokenStream {
     let mut r = String::new();
+    let (generic_w_bounds, generic_no_bounds) = enum_bounds_strings(enum_, "DeBin");
 
     for (index, variant) in enum_.variants.iter().enumerate() {
         let lit = format!("{}u16", index);
@@ -233,7 +239,7 @@ pub fn derive_de_bin_enum(enum_: &Enum) -> TokenStream {
     }
 
     format!(
-        "impl  DeBin for {} {{
+        "impl{}  DeBin for {}{} {{
             fn de_bin(o:&mut usize, d:&[u8]) -> core::result::Result<Self, nanoserde::DeBinErr> {{
                 let id: u16 = DeBin::de_bin(o,d)?;
                 Ok(match id {{
@@ -241,7 +247,7 @@ pub fn derive_de_bin_enum(enum_: &Enum) -> TokenStream {
                     _ => return core::result::Result::Err(nanoserde::DeBinErr{{o:*o, l:0, s:d.len()}})
                 }})
             }}
-        }}", enum_.name, r)
+        }}", generic_w_bounds,enum_.name,generic_no_bounds, r)
         .parse()
         .unwrap()
 }
diff --git a/derive/src/serde_json.rs b/derive/src/serde_json.rs
index 497483e..4cc7dfb 100644
--- a/derive/src/serde_json.rs
+++ b/derive/src/serde_json.rs
@@ -3,7 +3,7 @@ use alloc::string::{String, ToString};
 use alloc::{vec, vec::Vec};
 
 use crate::{
-    parse::{Enum, Field, Struct},
+    parse::{Enum, Field, Struct, struct_bounds_strings, enum_bounds_strings},
     shared,
 };
 
@@ -25,6 +25,7 @@ pub fn derive_ser_json_proxy(proxy_type: &str, type_: &str) -> TokenStream {
 
 pub fn derive_ser_json_struct(struct_: &Struct) -> TokenStream {
     let mut s = String::new();
+    let (generic_w_bounds, generic_no_bounds) = struct_bounds_strings(struct_, "SerJson");
 
     l!(s, "let mut first_field_was_serialized = false;");
 
@@ -66,7 +67,7 @@ pub fn derive_ser_json_struct(struct_: &Struct) -> TokenStream {
 
     format!(
         "
-        impl SerJson for {} {{
+        impl{} SerJson for {}{} {{
             fn ser_json(&self, d: usize, s: &mut nanoserde::SerJsonState) {{
                 s.st_pre();
                 {}
@@ -74,7 +75,7 @@ pub fn derive_ser_json_struct(struct_: &Struct) -> TokenStream {
             }}
         }}
     ",
-        struct_.name, s
+        generic_w_bounds, struct_.name, generic_no_bounds, s
     )
     .parse()
     .unwrap()
@@ -216,14 +217,15 @@ pub fn derive_de_json_struct(struct_: &Struct) -> TokenStream {
             || shared::attrs_default_with(&struct_.attributes).is_some(),
         &struct_.fields[..],
     );
+    let (generic_w_bounds, generic_no_bounds) = struct_bounds_strings(struct_, "DeJson");
 
     format!(
-        "impl DeJson for {} {{
+        "impl{} DeJson for {}{} {{
             fn de_json(s: &mut nanoserde::DeJsonState, i: &mut core::str::Chars) -> core::result::Result<Self,
             nanoserde::DeJsonErr> {{
                 core::result::Result::Ok({{ {} }})
             }}
-        }}", struct_.name, body)
+        }}", generic_w_bounds, struct_.name, generic_no_bounds, body)
         .parse().unwrap()
 }
 
@@ -362,6 +364,7 @@ pub fn derive_ser_json_enum(enum_: &Enum) -> TokenStream {
 pub fn derive_de_json_enum(enum_: &Enum) -> TokenStream {
     let mut r_units = String::new();
     let mut r_rest = String::new();
+    let (generic_w_bounds, generic_no_bounds) = enum_bounds_strings(enum_, "DeJson");
 
     for variant in &enum_.variants {
         let json_variant_name =
@@ -403,10 +406,10 @@ pub fn derive_de_json_enum(enum_: &Enum) -> TokenStream {
     }
 
     let mut r = format!(
-        "impl DeJson for {} {{
+        "impl{} DeJson for {}{} {{
             fn de_json(s: &mut nanoserde::DeJsonState, i: &mut core::str::Chars) -> core::result::Result<Self, nanoserde::DeJsonErr> {{
                 match s.tok {{",
-        enum_.name,
+        generic_w_bounds, generic_no_bounds, enum_.name,
     );
 
     if !r_rest.is_empty() {
@@ -455,6 +458,7 @@ pub fn derive_de_json_enum(enum_: &Enum) -> TokenStream {
 
 pub fn derive_ser_json_struct_unnamed(struct_: &Struct) -> TokenStream {
     let mut body = String::new();
+    let (generic_w_bounds, generic_no_bounds) = struct_bounds_strings(struct_, "SerJson");
 
     let transparent = shared::attrs_transparent(&struct_.attributes);
 
@@ -483,12 +487,12 @@ pub fn derive_ser_json_struct_unnamed(struct_: &Struct) -> TokenStream {
 
     format!(
         "
-        impl SerJson for {} {{
+        impl{} SerJson for {}{} {{
             fn ser_json(&self, d: usize, s: &mut nanoserde::SerJsonState) {{
                 {}
             }}
         }}",
-        struct_.name, body
+        generic_w_bounds, struct_.name, generic_no_bounds, body
     )
     .parse()
     .unwrap()
@@ -496,6 +500,7 @@ pub fn derive_ser_json_struct_unnamed(struct_: &Struct) -> TokenStream {
 
 pub fn derive_de_json_struct_unnamed(struct_: &Struct) -> TokenStream {
     let mut body = String::new();
+    let (generic_w_bounds, generic_no_bounds) = struct_bounds_strings(struct_, "DeJson");
 
     let transparent = shared::attrs_transparent(&struct_.attributes);
 
@@ -528,11 +533,11 @@ pub fn derive_de_json_struct_unnamed(struct_: &Struct) -> TokenStream {
     };
 
     format! ("
-        impl DeJson for {} {{
+        impl{} DeJson for {}{} {{
             fn de_json(s: &mut nanoserde::DeJsonState, i: &mut core::str::Chars) -> core::result::Result<Self,nanoserde::DeJsonErr> {{
                 {}
                 core::result::Result::Ok(r)
             }}
-        }}",struct_.name, body
+        }}",generic_w_bounds, struct_.name, generic_no_bounds, body
     ).parse().unwrap()
 }


Test patch:
diff --git a/tests/bin.rs b/tests/bin.rs
index 494f0b3..2872326 100644
--- a/tests/bin.rs
+++ b/tests/bin.rs
@@ -24,6 +24,36 @@ fn binary() {
     assert!(test == test_deserialized);
 }
 
+#[test]
+fn binary_generics() {
+    #[derive(DeBin, SerBin, PartialEq)]
+    pub struct TestStruct<A, B> {
+        pub a: A,
+        b: Option<B>,
+    }
+
+    let test: TestStruct<i32, f32> = TestStruct { a: 1, b: Some(2.) };
+
+    let bytes = SerBin::serialize_bin(&test);
+
+    let test_deserialized = DeBin::deserialize_bin(&bytes).unwrap();
+
+    assert!(test == test_deserialized);
+
+    #[derive(DeBin, SerBin, PartialEq)]
+    pub enum TestEnum<A, B> {
+        Test(A, B),
+    }
+
+    let test: TestEnum<i32, f32> = TestEnum::Test(3, 15.);
+
+    let bytes = SerBin::serialize_bin(&test);
+
+    let test_deserialized = DeBin::deserialize_bin(&bytes).unwrap();
+
+    assert!(test == test_deserialized);
+}
+
 #[test]
 fn field_proxy() {
     #[derive(PartialEq)]