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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
extern crate proc_macro;

mod parse;

use proc_macro::TokenStream;
use quote::quote;
use syn::parse_macro_input;

use crate::parse::Input;

#[proc_macro_derive(Serialize_enum)]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as Input);
    let ident = input.ident;

    TokenStream::from(quote! {
        impl serde::Serialize for #ident {
            #[allow(clippy::use_self)]
            fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
            where
                S: serde::Serializer
            {
                let value = self.as_str_name();
                serde::Serialize::serialize(&value, serializer)
            }
        }
    })
}

#[proc_macro_derive(Deserialize_enum, attributes(serde))]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as Input);
    let ident = input.ident;

    TokenStream::from(quote! {
        impl<'de> serde::Deserialize<'de> for #ident {
            #[allow(clippy::use_self)]
            fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
            where
                D: serde::Deserializer<'de>,
            {
                struct discriminant;

                impl<'de> serde::de::Visitor<'de> for discriminant {
                    type Value = #ident;

                    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                        write!(formatter, "a string or an integer")
                    }

                    fn visit_str<R>(self, v: &str) -> Result<Self::Value, R>
                    where
                        R: serde::de::Error,
                    {
                        match #ident::from_str_name(v) {
                            Some(e) => Ok(e),
                            None => Err(serde::de::Error::custom(format!(
                                "unknown enum value: {}",
                                v
                            ))),
                        }
                    }

                    fn visit_i64<R>(self, v: i64) -> Result<Self::Value, R>
                    where
                        R: serde::de::Error,
                    {
                        match #ident::from_i32(v as i32) {
                            Some(e) => Ok(e),
                            None => Err(serde::de::Error::custom(format!(
                                "unknown enum value: {}",
                                v
                            )))
                        }
                    }

                    fn visit_u64<R>(self, v: u64) -> Result<Self::Value, R>
                    where
                        R: serde::de::Error,
                    {
                        match #ident::from_i32(v as i32) {
                            Some(e) => Ok(e),
                            None => Err(serde::de::Error::custom(format!(
                                "unknown enum value: {}",
                                v
                            )))
                        }
                    }
                }

                deserializer.deserialize_any(discriminant)
            }
        }
    })
}