1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use proc_macro::TokenStream;
use quote::quote;
use syn::{DeriveInput};

#[proc_macro_derive(Serialize)]
pub fn impl_serialize(input: TokenStream) -> TokenStream {
    let ast = syn::parse_macro_input!(input as DeriveInput);

    let c_ident = ast.ident;
    let n_fields = ast.attrs.len();
    let mut ser_fields = match ast.data {
        syn::Data::Struct(str) => str.fields.into_iter()
                                                        .map(|f| f.ident)
                                                        .filter(|f| f.is_some())
                                                        .map(|f| f.unwrap()),
        syn::Data::Enum(_) => panic!("cannot serialize enums as of yet"),
        syn::Data::Union(_) => panic!("cannot serialize unions as of yet"),
    };
    let closing_field = ser_fields.next_back()
        .map(|f| Some(quote!(ser.serialize_field(stringify!(#f), &self.#f, &lib_contra::position::Position::Closing )?; ))).into_iter();
    let trailing_fields = ser_fields
        .map(|f| Some(quote!(ser.serialize_field(stringify!(#f), &self.#f, &lib_contra::position::Position::Trailing)?; ))).into_iter();
    let ser_fields = trailing_fields.chain(closing_field.into_iter()).filter(|f| f.is_some());

    quote!(
        impl lib_contra::serialize::Serialize for #c_ident {
            fn serialize<S: lib_contra::serializer::Serializer>(&self, ser: &mut S, _pos: &lib_contra::position::Position) -> lib_contra::error::SuccessResult {
                ser.begin_struct(stringify!(#c_ident), #n_fields)?;

                #(#ser_fields)*
                
                ser.end_struct(stringify!(#c_ident))?;
                
                Ok(())
            }
        }
    ).into()
}





#[proc_macro_derive(Deserialize)]
pub fn impl_deserialize(input: TokenStream) -> TokenStream {
    let ast = syn::parse_macro_input!(input as DeriveInput);

    let c_ident = ast.ident;
    let n_fields = ast.attrs.len();
    let field_idents = match ast.data {
        syn::Data::Struct(str) => str.fields.into_iter()
                                                        .map(|f| f.ident)
                                                        .filter(|f| f.is_some())
                                                        .map(|f| f.unwrap()),
        syn::Data::Enum(_) => panic!("cannot deserialize enums as of yet"),
        syn::Data::Union(_) => panic!("cannot deserialize unions as of yet"),
    };

    let mut des_fields = field_idents.clone();
    let closing_field = des_fields.next_back()
        .map(|f| Some(quote!(let #f = des.deserialize_field(stringify!(#f))?;))).into_iter();
    let trailing_fields = des_fields
        .map(|f| Some(quote!(let #f = des.deserialize_field(stringify!(#f))?;))).into_iter();
    let des_fields = trailing_fields.chain(closing_field).filter(|f| f.is_some());

    quote!(
        impl lib_contra::deserialize::Deserialize for #c_ident {
            fn deserialize<D: lib_contra::deserializer::Deserializer>(des: &mut D) -> Result<Self, lib_contra::error::AnyError> {
                des.deserialize_struct_begin(stringify!(#c_ident), #n_fields)?;
                
                #(#des_fields)*
    
                des.deserialize_struct_end(stringify!(#c_ident))?;

                Ok(#c_ident {
                    #(#field_idents),*
                })
            }
        }
    ).into()
}