quote_data_codegen/
lib.rs

1extern crate proc_macro;
2
3mod r#enum;
4mod helper;
5mod r#struct;
6
7use helper::MOD_PATH;
8use proc_macro::TokenStream;
9use proc_macro2::TokenStream as TokenStream2;
10use r#enum::EnumStructure;
11use r#struct::StructStructure;
12use std::str::FromStr;
13use syn::{parse_macro_input, Data, DeriveInput, Error, Expr, Lit, Meta};
14
15#[proc_macro_derive(QuoteIt, attributes(mod_path))]
16pub fn derive_to_tokens(input: TokenStream) -> TokenStream {
17    let input = parse_macro_input! {input as DeriveInput};
18    let mut mod_path_tokens: Result<Option<TokenStream2>, Error> = Ok(None);
19
20    for attr in &input.attrs {
21        if attr.path() == MOD_PATH {
22            match &attr.meta {
23                Meta::NameValue(mod_path) => {
24                    mod_path_tokens = match match &mod_path.value {
25                        Expr::Lit(path_lit) => match &path_lit.lit {
26                            Lit::Str(path_str) => Ok(path_str.value()),
27                            _ => Err(Error::new_spanned(
28                                mod_path,
29                                "`mod_path` must be a string",
30                            ))
31                        },
32                        _ => Err(Error::new_spanned(
33                            mod_path,
34                            "`mod_path` must be a string",
35                        )),
36                    }
37                        .map(|path| {
38                            TokenStream2::from_str(path.as_str()).map_err(|_| {
39                                Error::new_spanned(
40                                    mod_path,
41                                    "Value of `mod_path` must be a path of mod",
42                                )
43                            })
44                        }) {
45                        Ok(Ok(tokens)) => Ok(Some(tokens)),
46                        Ok(Err(e)) => Err(e),
47                        Err(e) => Err(e),
48                    }
49                }
50                _ => {
51                    mod_path_tokens = Err(Error::new_spanned(
52                        attr,
53                        "Attribute `mod_path` must be a named value.",
54                    ))
55                }
56            }
57        }
58    }
59
60    let mod_path_tokens = match mod_path_tokens {
61        Ok(result) => result,
62        Err(e) => return TokenStream::from(e.to_compile_error()),
63    };
64
65    let result = match &input.data {
66        Data::Enum(_) => {
67            EnumStructure::from_ast(&input, mod_path_tokens).map(|s| s.get_implement())
68        }
69        Data::Struct(_) => {
70            StructStructure::from_ast(&input, mod_path_tokens).map(|s| s.get_implement())
71        }
72        _ => Err(Error::new_spanned(&input, "Unknown data type")),
73    };
74
75    TokenStream::from(match result {
76        Ok(Ok(tokens)) => tokens,
77        Ok(Err(e)) => e.to_compile_error(),
78        Err(e) => e.to_compile_error(),
79    })
80}