substreams_ethereum_derive/
lib.rs1#![recursion_limit = "256"]
10
11extern crate proc_macro;
12
13use ethabi::{Error, Result};
14use std::borrow::Cow;
15
16const ERROR_MSG: &str = "`derive(EthabiContract)` in substreams-ethereum failed";
17
18#[proc_macro_derive(EthabiContract, attributes(ethabi_contract_options))]
19pub fn ethabi_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
20 let ast = syn::parse(input).expect(ERROR_MSG);
21 let gen = impl_ethabi_derive(&ast).expect(ERROR_MSG);
22 gen.into()
23}
24
25fn impl_ethabi_derive(ast: &syn::DeriveInput) -> Result<proc_macro2::TokenStream> {
26 let options = get_options(&ast.attrs, "ethabi_contract_options")?;
27 let path = get_option(&options, "path")?;
28
29 substreams_ethereum_abigen::generate_abi_code(path)
30 .map_err(|e| Error::Other(Cow::Owned(format!("{}", e))))
31}
32
33fn get_options(attrs: &[syn::Attribute], name: &str) -> Result<Vec<syn::NestedMeta>> {
34 let options = attrs
35 .iter()
36 .flat_map(syn::Attribute::parse_meta)
37 .find(|meta| meta.path().is_ident(name));
38
39 match options {
40 Some(syn::Meta::List(list)) => Ok(list.nested.into_iter().collect()),
41 _ => Err(Error::Other(Cow::Borrowed("Unexpected meta item"))),
42 }
43}
44
45fn get_option(options: &[syn::NestedMeta], name: &str) -> Result<String> {
46 let item = options
47 .iter()
48 .flat_map(|nested| match *nested {
49 syn::NestedMeta::Meta(ref meta) => Some(meta),
50 _ => None,
51 })
52 .find(|meta| meta.path().is_ident(name))
53 .ok_or_else(|| Error::Other(Cow::Owned(format!("Expected to find option {}", name))))?;
54
55 str_value_of_meta_item(item, name)
56}
57
58fn str_value_of_meta_item(item: &syn::Meta, name: &str) -> Result<String> {
59 if let syn::Meta::NameValue(ref name_value) = *item {
60 if let syn::Lit::Str(ref value) = name_value.lit {
61 return Ok(value.value());
62 }
63 }
64
65 Err(Error::Other(Cow::Owned(format!(
66 r#"`{}` must be in the form `#[{}="something"]`"#,
67 name, name
68 ))))
69}