mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-10 07:08:05 -05:00
serial: WIP enum (de)serialization.
This commit is contained in:
@@ -21,7 +21,6 @@ struct NetCli {
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
env_logger::init();
|
||||
let args = NetCli::parse();
|
||||
let addr = vec![Url::parse(args.addr.as_str()).unwrap()];
|
||||
let mut peers = vec![];
|
||||
|
||||
36
src/serial/derive-internal/src/helpers.rs
Normal file
36
src/serial/derive-internal/src/helpers.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
use quote::ToTokens;
|
||||
use syn::{Attribute, Meta};
|
||||
//use syn::{spanned::Spanned, Attribute, Error, Meta, NestedMeta, Path};
|
||||
|
||||
pub fn contains_skip(attrs: &[Attribute]) -> bool {
|
||||
for attr in attrs.iter() {
|
||||
if let Ok(Meta::Path(path)) = attr.parse_meta() {
|
||||
if path.to_token_stream().to_string().as_str() == "skip_serialize" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn contains_initialize_with(attrs: &[Attribute]) -> syn::Result<Option<Path>> {
|
||||
for attr in attrs.iter() {
|
||||
if let Ok(Meta::List(meta_list)) = attr.parse_meta() {
|
||||
if meta_list.path.to_token_stream().to_string().as_str() == "init_serialize" {
|
||||
if meta_list.nested.len() != 1 {
|
||||
return Err(Error::new(
|
||||
meta_list.span(),
|
||||
"init_serialize requires exactly one initialization method.",
|
||||
))
|
||||
}
|
||||
let nested_meta = meta_list.nested.iter().next().unwrap();
|
||||
if let NestedMeta::Meta(Meta::Path(path)) = nested_meta {
|
||||
return Ok(Some(path.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
*/
|
||||
@@ -3,39 +3,195 @@ use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
use quote::quote;
|
||||
use syn::{Fields, Ident, Index, ItemEnum, ItemStruct, WhereClause};
|
||||
|
||||
// TODO
|
||||
mod helpers;
|
||||
use helpers::contains_skip;
|
||||
|
||||
pub fn enum_ser(input: &ItemEnum, cratename: Ident) -> syn::Result<TokenStream2> {
|
||||
let name = &input.ident;
|
||||
let (_impl_generics, _ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
let where_clause = where_clause.map_or_else(
|
||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
let mut where_clause = where_clause.map_or_else(
|
||||
|| WhereClause { where_token: Default::default(), predicates: Default::default() },
|
||||
Clone::clone,
|
||||
);
|
||||
|
||||
let mut body = TokenStream2::new();
|
||||
let mut variant_idx_body = TokenStream2::new();
|
||||
let mut fields_body = TokenStream2::new();
|
||||
for (variant_idx, variant) in input.variants.iter().enumerate() {
|
||||
let variant_idx = u8::try_from(variant_idx).expect("up to 256 enum variants are supported");
|
||||
let variant_ident = &variant.ident;
|
||||
let mut variant_header = TokenStream2::new();
|
||||
let mut variant_body = TokenStream2::new();
|
||||
match &variant.fields {
|
||||
Fields::Named(fields) => {
|
||||
for field in &fields.named {
|
||||
let field_name = field.ident.as_ref().unwrap();
|
||||
if contains_skip(&field.attrs) {
|
||||
variant_header.extend(quote! { _ #field_name, }); // TODO: Test this
|
||||
continue
|
||||
} else {
|
||||
let field_type = &field.ty;
|
||||
where_clause.predicates.push(
|
||||
syn::parse2(quote! {
|
||||
#field_type: #cratename::serial::Encodable
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
variant_header.extend(quote! { #field_name, });
|
||||
}
|
||||
variant_body.extend(quote! {
|
||||
len += self.#field_name.encode(&mut s);
|
||||
})
|
||||
}
|
||||
variant_header = quote! { { #variant_header } };
|
||||
variant_idx_body.extend(quote!(
|
||||
#name::#variant_ident { .. } => #variant_idx,
|
||||
));
|
||||
}
|
||||
Fields::Unnamed(fields) => {
|
||||
for (field_idx, field) in fields.unnamed.iter().enumerate() {
|
||||
let field_idx =
|
||||
u32::try_from(field_idx).expect("up to 2^32 fields are supported");
|
||||
if contains_skip(&field.attrs) {
|
||||
let field_ident =
|
||||
Ident::new(format!("_id{}", field_idx).as_str(), Span::call_site());
|
||||
variant_header.extend(quote! { #field_ident, });
|
||||
continue
|
||||
} else {
|
||||
let field_type = &field.ty;
|
||||
where_clause.predicates.push(
|
||||
syn::parse2(quote! {
|
||||
#field_type: #cratename::serial::Encodable
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let ln = quote! {
|
||||
let mut len = 0;
|
||||
};
|
||||
body.extend(ln);
|
||||
|
||||
for var in input.variants.iter() {
|
||||
match &var.fields {
|
||||
Fields::Named(_) => {}
|
||||
Fields::Unnamed(_) => {}
|
||||
Fields::Unit => {}
|
||||
let field_ident =
|
||||
Ident::new(format!("id{}", field_idx).as_str(), Span::call_site());
|
||||
variant_header.extend(quote! { #field_ident, });
|
||||
variant_body.extend(quote! {
|
||||
len += self.#field_ident.encode(&mut s)?;
|
||||
})
|
||||
}
|
||||
}
|
||||
variant_header = quote! { ( #variant_header )};
|
||||
variant_idx_body.extend(quote!(
|
||||
#name::#variant_ident(..) => #variant_idx,
|
||||
));
|
||||
}
|
||||
Fields::Unit => {
|
||||
variant_idx_body.extend(quote!(
|
||||
#name::#variant_ident => #variant_idx,
|
||||
));
|
||||
}
|
||||
}
|
||||
fields_body.extend(quote!(
|
||||
#name::#variant_ident #variant_header => {
|
||||
#variant_body
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
let ret = quote! {
|
||||
Ok(len)
|
||||
Ok(quote! {
|
||||
impl #impl_generics #cratename::serial::Encodable for #name #ty_generics #where_clause {
|
||||
fn encode<S: std::io::Write>(&self, mut s: S) -> ::core::result::Result<usize, std::io::Error> {
|
||||
let variant_idx: u8 = match self {
|
||||
#variant_idx_body
|
||||
};
|
||||
|
||||
s.write_all(&variant_idx.to_le_bytes())?;
|
||||
let mut len = 1;
|
||||
|
||||
match self {
|
||||
#fields_body
|
||||
}
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn enum_de(input: &ItemEnum, cratename: Ident) -> syn::Result<TokenStream2> {
|
||||
let name = &input.ident;
|
||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
let mut where_clause = where_clause.map_or_else(
|
||||
|| WhereClause { where_token: Default::default(), predicates: Default::default() },
|
||||
Clone::clone,
|
||||
);
|
||||
|
||||
let mut variant_arms = TokenStream2::new();
|
||||
for (variant_idx, variant) in input.variants.iter().enumerate() {
|
||||
let variant_idx = u8::try_from(variant_idx).expect("up to 256 enum variants are supported");
|
||||
let variant_ident = &variant.ident;
|
||||
let mut variant_header = TokenStream2::new();
|
||||
match &variant.fields {
|
||||
Fields::Named(fields) => {
|
||||
for field in &fields.named {
|
||||
let field_name = field.ident.as_ref().unwrap();
|
||||
if contains_skip(&field.attrs) {
|
||||
variant_header.extend(quote! {
|
||||
#field_name: Default::default(),
|
||||
});
|
||||
} else {
|
||||
let field_type = &field.ty;
|
||||
where_clause.predicates.push(
|
||||
syn::parse2(quote! {
|
||||
#field_type: #cratename::serial::Decodable
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
variant_header.extend(quote! {
|
||||
#field_name: #cratename::serial::Decodable::decode(&mut d)?,
|
||||
});
|
||||
}
|
||||
}
|
||||
variant_header = quote! { { #variant_header } };
|
||||
}
|
||||
Fields::Unnamed(fields) => {
|
||||
for field in fields.unnamed.iter() {
|
||||
if contains_skip(&field.attrs) {
|
||||
variant_header.extend(quote! { Default::default(), });
|
||||
} else {
|
||||
let field_type = &field.ty;
|
||||
where_clause.predicates.push(
|
||||
syn::parse2(quote! {
|
||||
#field_type: #cratename::serial::Decodable
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
variant_header
|
||||
.extend(quote! { #cratename::serial::Decodable::decode(&mut d)?, });
|
||||
}
|
||||
}
|
||||
variant_header = quote! { ( #variant_header ) };
|
||||
}
|
||||
Fields::Unit => {}
|
||||
}
|
||||
|
||||
variant_arms.extend(quote! {
|
||||
#variant_idx => #name::#variant_ident #variant_header ,
|
||||
});
|
||||
}
|
||||
|
||||
let variant_idx = quote! {
|
||||
let variant_idx: u8 = #cratename::serial::Decodable::decode(&mut d)?;
|
||||
};
|
||||
body.extend(ret);
|
||||
|
||||
Ok(quote! {
|
||||
impl #cratename::serial::Encodable for #name #where_clause {
|
||||
fn encode<S: std::io::Write>(&self, mut s: S) -> ::core::result::Result<usize, std::io::Error> {
|
||||
#body
|
||||
impl #impl_generics #cratename::serial::Decodable for #name #ty_generics #where_clause {
|
||||
fn decode<D: std::io::Read>(mut d: D) -> ::core::result::Result<Self, std::io::Error> {
|
||||
#variant_idx
|
||||
|
||||
let return_value = match variant_idx {
|
||||
#variant_arms
|
||||
_ => {
|
||||
let msg = format!("Unexpected variant index: {:?}", variant_idx);
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, msg));
|
||||
}
|
||||
};
|
||||
Ok(return_value)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -43,7 +199,7 @@ pub fn enum_ser(input: &ItemEnum, cratename: Ident) -> syn::Result<TokenStream2>
|
||||
|
||||
pub fn struct_ser(input: &ItemStruct, cratename: Ident) -> syn::Result<TokenStream2> {
|
||||
let name = &input.ident;
|
||||
let (_impl_generics, _ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
let mut where_clause = where_clause.map_or_else(
|
||||
|| WhereClause { where_token: Default::default(), predicates: Default::default() },
|
||||
Clone::clone,
|
||||
@@ -53,16 +209,9 @@ pub fn struct_ser(input: &ItemStruct, cratename: Ident) -> syn::Result<TokenStre
|
||||
|
||||
match &input.fields {
|
||||
Fields::Named(fields) => {
|
||||
let ln = quote! {
|
||||
let mut len = 0;
|
||||
};
|
||||
body.extend(ln);
|
||||
|
||||
for field in &fields.named {
|
||||
if let Some(attr) = field.attrs.get(0) {
|
||||
if attr.path.is_ident("skip_serialize") {
|
||||
continue
|
||||
}
|
||||
if contains_skip(&field.attrs) {
|
||||
continue
|
||||
}
|
||||
|
||||
let field_name = field.ident.as_ref().unwrap();
|
||||
@@ -79,18 +228,8 @@ pub fn struct_ser(input: &ItemStruct, cratename: Ident) -> syn::Result<TokenStre
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
let ret = quote! {
|
||||
Ok(len)
|
||||
};
|
||||
body.extend(ret)
|
||||
}
|
||||
Fields::Unnamed(fields) => {
|
||||
let ln = quote! {
|
||||
let mut len = 0;
|
||||
};
|
||||
body.extend(ln);
|
||||
|
||||
for field_idx in 0..fields.unnamed.len() {
|
||||
let field_idx = Index {
|
||||
index: u32::try_from(field_idx).expect("up to 2^32 fields are supported"),
|
||||
@@ -101,19 +240,16 @@ pub fn struct_ser(input: &ItemStruct, cratename: Ident) -> syn::Result<TokenStre
|
||||
};
|
||||
body.extend(delta);
|
||||
}
|
||||
|
||||
let ret = quote! {
|
||||
Ok(len)
|
||||
};
|
||||
body.extend(ret)
|
||||
}
|
||||
Fields::Unit => {}
|
||||
}
|
||||
|
||||
Ok(quote! {
|
||||
impl #cratename::serial::Encodable for #name #where_clause {
|
||||
impl #impl_generics #cratename::serial::Encodable for #name #ty_generics #where_clause {
|
||||
fn encode<S: std::io::Write>(&self, mut s: S) -> ::core::result::Result<usize, std::io::Error> {
|
||||
let mut len = 0;
|
||||
#body
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -121,7 +257,7 @@ pub fn struct_ser(input: &ItemStruct, cratename: Ident) -> syn::Result<TokenStre
|
||||
|
||||
pub fn struct_de(input: &ItemStruct, cratename: Ident) -> syn::Result<TokenStream2> {
|
||||
let name = &input.ident;
|
||||
let (_impl_generics, _ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
let mut where_clause = where_clause.map_or_else(
|
||||
|| WhereClause { where_token: Default::default(), predicates: Default::default() },
|
||||
Clone::clone,
|
||||
@@ -130,45 +266,28 @@ pub fn struct_de(input: &ItemStruct, cratename: Ident) -> syn::Result<TokenStrea
|
||||
let return_value = match &input.fields {
|
||||
Fields::Named(fields) => {
|
||||
let mut body = TokenStream2::new();
|
||||
|
||||
for field in &fields.named {
|
||||
let field_name = field.ident.as_ref().unwrap();
|
||||
let attr = field.attrs.get(0);
|
||||
|
||||
let delta: TokenStream2 =
|
||||
if attr.is_some() && attr.unwrap().path.is_ident("skip_serialize") {
|
||||
{
|
||||
let field_type = &field.ty;
|
||||
where_clause.predicates.push(
|
||||
syn::parse2(quote! {
|
||||
#field_type: core::default::Default
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
quote! {
|
||||
#field_name: #field_type::default(),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
{
|
||||
let field_type = &field.ty;
|
||||
where_clause.predicates.push(
|
||||
syn::parse2(quote! {
|
||||
#field_type: #cratename::serial::Decodable
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
quote! {
|
||||
#field_name: #cratename::serial::Decodable::decode(&mut d)?,
|
||||
}
|
||||
}
|
||||
};
|
||||
let delta: TokenStream2 = if contains_skip(&field.attrs) {
|
||||
quote! {
|
||||
#field_name: Default::default(),
|
||||
}
|
||||
} else {
|
||||
let field_type = &field.ty;
|
||||
where_clause.predicates.push(
|
||||
syn::parse2(quote! {
|
||||
#field_type: #cratename::serial::Decodable
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
quote! {
|
||||
#field_name: #cratename::serial::Decodable::decode(&mut d)?,
|
||||
}
|
||||
};
|
||||
body.extend(delta);
|
||||
}
|
||||
|
||||
quote! {
|
||||
Self { #body }
|
||||
}
|
||||
@@ -181,7 +300,6 @@ pub fn struct_de(input: &ItemStruct, cratename: Ident) -> syn::Result<TokenStrea
|
||||
};
|
||||
body.extend(delta);
|
||||
}
|
||||
|
||||
quote! {
|
||||
Self( #body )
|
||||
}
|
||||
@@ -194,7 +312,7 @@ pub fn struct_de(input: &ItemStruct, cratename: Ident) -> syn::Result<TokenStrea
|
||||
};
|
||||
|
||||
Ok(quote! {
|
||||
impl #cratename::serial::Decodable for #name #where_clause {
|
||||
impl #impl_generics #cratename::serial::Decodable for #name #ty_generics #where_clause {
|
||||
fn decode<D: std::io::Read>(mut d: D) -> ::core::result::Result<Self, std::io::Error> {
|
||||
Ok(#return_value)
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ extern crate proc_macro;
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Span;
|
||||
use proc_macro_crate::{crate_name, FoundCrate};
|
||||
use syn::{Ident, Item, ItemStruct};
|
||||
use syn::{Ident, ItemEnum, ItemStruct, ItemUnion};
|
||||
|
||||
use darkfi_derive_internal::{struct_de, struct_ser};
|
||||
use darkfi_derive_internal::{enum_de, enum_ser, struct_de, struct_ser};
|
||||
|
||||
#[proc_macro_derive(SerialEncodable, attributes(skip_serialize))]
|
||||
pub fn darkfi_serialize(input: TokenStream) -> TokenStream {
|
||||
@@ -17,9 +17,15 @@ pub fn darkfi_serialize(input: TokenStream) -> TokenStream {
|
||||
|
||||
let cratename = Ident::new(&found_crate, Span::call_site());
|
||||
|
||||
let res = match syn::parse(input).unwrap() {
|
||||
Item::Struct(strc) => struct_ser(&strc, cratename),
|
||||
_ => todo!("Not implemented type"),
|
||||
let res = if let Ok(input) = syn::parse::<ItemStruct>(input.clone()) {
|
||||
struct_ser(&input, cratename)
|
||||
} else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
|
||||
enum_ser(&input, cratename)
|
||||
} else if let Ok(_input) = syn::parse::<ItemUnion>(input) {
|
||||
todo!()
|
||||
} else {
|
||||
// Derive macros can only be defined on structs, enums, and unions.
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
TokenStream::from(match res {
|
||||
@@ -39,11 +45,15 @@ pub fn darkfi_deserialize(input: TokenStream) -> TokenStream {
|
||||
|
||||
let cratename = Ident::new(&found_crate, Span::call_site());
|
||||
|
||||
let res = if let Ok(input) = syn::parse::<ItemStruct>(input) {
|
||||
let res = if let Ok(input) = syn::parse::<ItemStruct>(input.clone()) {
|
||||
struct_de(&input, cratename)
|
||||
} else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
|
||||
enum_de(&input, cratename)
|
||||
} else if let Ok(_input) = syn::parse::<ItemUnion>(input) {
|
||||
todo!()
|
||||
} else {
|
||||
// For now we only allow derive on structs
|
||||
todo!("Implement Enum and Union")
|
||||
// Derive macros can only be defined on structs, enums, and unions.
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
TokenStream::from(match res {
|
||||
|
||||
@@ -770,52 +770,6 @@ mod tests {
|
||||
*/
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, SerialEncodable, SerialDecodable)]
|
||||
struct TestDerive0 {
|
||||
foo: String,
|
||||
bar: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, SerialEncodable, SerialDecodable)]
|
||||
struct TestDerive1 {
|
||||
baz: TestDerive0,
|
||||
meh: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, SerialEncodable, SerialDecodable)]
|
||||
struct TestDerive2(u64);
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, SerialEncodable, SerialDecodable)]
|
||||
struct TestDerive3 {
|
||||
foo: u64,
|
||||
#[skip_serialize]
|
||||
bar: u64,
|
||||
meh: u64,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_deserialize_struct() {
|
||||
let t0 = TestDerive0 { foo: String::from("Andrew"), bar: 42 };
|
||||
let t1 = TestDerive1 { baz: t0.clone(), meh: false };
|
||||
let t2 = TestDerive2(u64::MAX);
|
||||
let t3 = TestDerive3 { foo: 30, bar: 20, meh: 44 };
|
||||
|
||||
let t0_bytes = serialize(&t0);
|
||||
let t1_bytes = serialize(&t1);
|
||||
let t2_bytes = serialize(&t2);
|
||||
let t3_bytes = serialize(&t3);
|
||||
|
||||
let t0_de: TestDerive0 = deserialize(&t0_bytes).unwrap();
|
||||
let t1_de: TestDerive1 = deserialize(&t1_bytes).unwrap();
|
||||
let t2_de: TestDerive2 = deserialize(&t2_bytes).unwrap();
|
||||
let t3_de: TestDerive3 = deserialize(&t3_bytes).unwrap();
|
||||
|
||||
assert_eq!(t0, t0_de);
|
||||
assert_eq!(t1, t1_de);
|
||||
assert_eq!(t2, t2_de);
|
||||
assert_eq!(t3_de, TestDerive3 { foo: 30, bar: 0, meh: 44 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_payload_test() -> Result<(), Error> {
|
||||
let mut buf = vec![];
|
||||
@@ -836,4 +790,69 @@ mod tests {
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, SerialEncodable, SerialDecodable)]
|
||||
enum TestEnum0 {
|
||||
First,
|
||||
Second,
|
||||
Third,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, SerialEncodable, SerialDecodable)]
|
||||
enum TestEnum1 {
|
||||
First = 0x01,
|
||||
Second = 0x03,
|
||||
Third = 0xf1,
|
||||
Fourth = 0xfefe,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_serialize_deserialize_enum() {
|
||||
let first = serialize(&TestEnum0::First);
|
||||
let second = serialize(&TestEnum0::Second);
|
||||
let third = serialize(&TestEnum0::Third);
|
||||
assert_eq!(deserialize::<TestEnum0>(&first).unwrap(), TestEnum0::First);
|
||||
assert_eq!(deserialize::<TestEnum0>(&second).unwrap(), TestEnum0::Second);
|
||||
assert_eq!(deserialize::<TestEnum0>(&third).unwrap(), TestEnum0::Third);
|
||||
|
||||
let first = serialize(&TestEnum1::First);
|
||||
let second = serialize(&TestEnum1::Second);
|
||||
let third = serialize(&TestEnum1::Third);
|
||||
let fourth = serialize(&TestEnum1::Fourth);
|
||||
assert_eq!(first, [0]);
|
||||
assert_eq!(second, [1]);
|
||||
assert_eq!(third, [2]);
|
||||
assert_eq!(fourth, [3]);
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, SerialEncodable, SerialDecodable)]
|
||||
struct TestStruct0 {
|
||||
foo: u64,
|
||||
bar: bool,
|
||||
baz: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, SerialEncodable, SerialDecodable)]
|
||||
struct TestStruct1(String);
|
||||
|
||||
#[test]
|
||||
fn derive_serialize_deserialize_struct() {
|
||||
let foo = 44;
|
||||
let bar = true;
|
||||
let baz = String::from("foobarbaz");
|
||||
let ts0 = TestStruct0 { foo, bar, baz: baz.clone() };
|
||||
let ts0_s = serialize(&ts0);
|
||||
let ts0_n = deserialize::<TestStruct0>(&ts0_s).unwrap();
|
||||
assert_eq!(foo, ts0_n.foo);
|
||||
assert_eq!(bar, ts0_n.bar);
|
||||
assert_eq!(baz.clone(), ts0_n.baz);
|
||||
assert_eq!(ts0, ts0_n);
|
||||
assert_eq!(ts0_n, TestStruct0 { foo, bar, baz: baz.clone() });
|
||||
|
||||
let ts1 = TestStruct1(baz.clone());
|
||||
let ts1_s = serialize(&ts1);
|
||||
let ts1_n = deserialize::<TestStruct1>(&ts1_s).unwrap();
|
||||
assert_eq!(ts1, ts1_n);
|
||||
assert_eq!(ts1_n, TestStruct1(baz.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user