quote-data-codegen 1.0.0

Internal codegen for quote-it
Documentation
extern crate proc_macro;

mod r#enum;
mod helper;
mod r#struct;

use helper::MOD_PATH;
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use r#enum::EnumStructure;
use r#struct::StructStructure;
use std::str::FromStr;
use syn::{parse_macro_input, Data, DeriveInput, Error, Expr, Lit, Meta};

#[proc_macro_derive(QuoteIt, attributes(mod_path))]
pub fn derive_to_tokens(input: TokenStream) -> TokenStream {
    let input = parse_macro_input! {input as DeriveInput};
    let mut mod_path_tokens: Result<Option<TokenStream2>, Error> = Ok(None);

    for attr in &input.attrs {
        if attr.path() == MOD_PATH {
            match &attr.meta {
                Meta::NameValue(mod_path) => {
                    mod_path_tokens = match match &mod_path.value {
                        Expr::Lit(path_lit) => match &path_lit.lit {
                            Lit::Str(path_str) => Ok(path_str.value()),
                            _ => Err(Error::new_spanned(
                                mod_path,
                                "`mod_path` must be a string",
                            ))
                        },
                        _ => Err(Error::new_spanned(
                            mod_path,
                            "`mod_path` must be a string",
                        )),
                    }
                        .map(|path| {
                            TokenStream2::from_str(path.as_str()).map_err(|_| {
                                Error::new_spanned(
                                    mod_path,
                                    "Value of `mod_path` must be a path of mod",
                                )
                            })
                        }) {
                        Ok(Ok(tokens)) => Ok(Some(tokens)),
                        Ok(Err(e)) => Err(e),
                        Err(e) => Err(e),
                    }
                }
                _ => {
                    mod_path_tokens = Err(Error::new_spanned(
                        attr,
                        "Attribute `mod_path` must be a named value.",
                    ))
                }
            }
        }
    }

    let mod_path_tokens = match mod_path_tokens {
        Ok(result) => result,
        Err(e) => return TokenStream::from(e.to_compile_error()),
    };

    let result = match &input.data {
        Data::Enum(_) => {
            EnumStructure::from_ast(&input, mod_path_tokens).map(|s| s.get_implement())
        }
        Data::Struct(_) => {
            StructStructure::from_ast(&input, mod_path_tokens).map(|s| s.get_implement())
        }
        _ => Err(Error::new_spanned(&input, "Unknown data type")),
    };

    TokenStream::from(match result {
        Ok(Ok(tokens)) => tokens,
        Ok(Err(e)) => e.to_compile_error(),
        Err(e) => e.to_compile_error(),
    })
}