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
#![recursion_limit = "128"]
#![cfg_attr(tarpaulin, skip)]
#![warn(unused_extern_crates)]

extern crate proc_macro;
use syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
fn impl_default_json_macro(ast: &syn::DeriveInput) -> TokenStream {
    let name = &ast.ident;
    let gen = quote! {

        impl<'a> From<&'a #name> for JsonString {
            fn from(v: &#name) -> JsonString {
                match ::serde_json::to_string(v) {
                    Ok(s) => Ok(JsonString::from_json(&s)),
                    Err(e) => {
                        eprintln!("Error serializing to JSON: {:?}", e);
                        Err(PersistenceError::SerializationError(e.to_string()))
                    },
                }.expect(&format!("could not Jsonify {}: {:?}", stringify!(#name), v))
            }
        }

        impl From<#name> for JsonString {
            fn from(v: #name) -> JsonString {
                JsonString::from(&v)
            }
        }

        impl<'a> ::std::convert::TryFrom<&'a JsonString> for #name {
            type Error = PersistenceError;
            fn try_from(json_string: &JsonString) -> Result<Self, Self::Error> {
                match ::serde_json::from_str(&String::from(json_string)) {
                    Ok(d) => Ok(d),
                    Err(e) => Err(PersistenceError::SerializationError(e.to_string())),
                }
            }
        }

        impl ::std::convert::TryFrom<JsonString> for #name {
            type Error = PersistenceError;
            fn try_from(json_string: JsonString) -> Result<Self, Self::Error> {
                #name::try_from(&json_string)
            }
        }
    };
    gen.into()
}

#[proc_macro_derive(DefaultJson)]
pub fn default_json_derive(input: TokenStream) -> TokenStream {
    // Construct a represntation of Rust code as a syntax tree
    // that we can manipulate
    let ast = syn::parse(input).unwrap();

    // Build the trait implementation
    impl_default_json_macro(&ast)
}