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
extern crate proc_macro; mod r#enum; mod helper; mod r#struct; use crate::helper::IROHA; 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, Lit, Meta, NestedMeta}; #[proc_macro_derive(ToTokens, attributes(Iroha))] 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 == IROHA { match attr.parse_meta() { Ok(Meta::List(list)) => { for item in list.nested.iter() { mod_path_tokens = match item { NestedMeta::Meta(Meta::NameValue(mod_path)) => { if mod_path.path != MOD_PATH { Err(Error::new_spanned( &attr, "Attribute `Iroha` only support argument `mod_path`", )) } else { match match &mod_path.lit { Lit::Str(path_str) => Ok(path_str.value()), _ => 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 mod path", ) }) }) { Ok(Ok(tokens)) => Ok(Some(tokens)), Ok(Err(e)) => Err(e), Err(e) => Err(e), } } } _ => Err(Error::new_spanned( &attr, "Argument of `Iroha` must be a meta.", )), }; } } Err(e) => mod_path_tokens = Err(e), _ => { mod_path_tokens = Err(Error::new_spanned( &attr, "Attribute `Iroha` only support list.", )) } } } } 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(), }) }