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
#![recursion_limit = "256"]
extern crate proc_macro;
use ethabi::{Error, Result};
use std::borrow::Cow;
const ERROR_MSG: &str = "`derive(EthabiContract)` in substreams-ethereum failed";
#[proc_macro_derive(EthabiContract, attributes(ethabi_contract_options))]
pub fn ethabi_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = syn::parse(input).expect(ERROR_MSG);
let gen = impl_ethabi_derive(&ast).expect(ERROR_MSG);
gen.into()
}
fn impl_ethabi_derive(ast: &syn::DeriveInput) -> Result<proc_macro2::TokenStream> {
let options = get_options(&ast.attrs, "ethabi_contract_options")?;
let path = get_option(&options, "path")?;
substreams_ethereum_abigen::generate_abi_code(path)
.map_err(|e| Error::Other(Cow::Owned(format!("{}", e))))
}
fn get_options(attrs: &[syn::Attribute], name: &str) -> Result<Vec<syn::NestedMeta>> {
let options = attrs
.iter()
.flat_map(syn::Attribute::parse_meta)
.find(|meta| meta.path().is_ident(name));
match options {
Some(syn::Meta::List(list)) => Ok(list.nested.into_iter().collect()),
_ => Err(Error::Other(Cow::Borrowed("Unexpected meta item"))),
}
}
fn get_option(options: &[syn::NestedMeta], name: &str) -> Result<String> {
let item = options
.iter()
.flat_map(|nested| match *nested {
syn::NestedMeta::Meta(ref meta) => Some(meta),
_ => None,
})
.find(|meta| meta.path().is_ident(name))
.ok_or_else(|| Error::Other(Cow::Owned(format!("Expected to find option {}", name))))?;
str_value_of_meta_item(item, name)
}
fn str_value_of_meta_item(item: &syn::Meta, name: &str) -> Result<String> {
if let syn::Meta::NameValue(ref name_value) = *item {
if let syn::Lit::Str(ref value) = name_value.lit {
return Ok(value.value());
}
}
Err(Error::Other(Cow::Owned(format!(
r#"`{}` must be in the form `#[{}="something"]`"#,
name, name
))))
}