chore: update ethers-contract-derive to use syn 2
This commit is contained in:
parent
ef5a37b2e5
commit
85f6710471
|
@ -40,8 +40,7 @@ impl Contracts {
|
||||||
|
|
||||||
impl Parse for Contracts {
|
impl Parse for Contracts {
|
||||||
fn parse(input: ParseStream) -> Result<Self> {
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
let inner =
|
let inner = input.parse_terminated(ContractArgs::parse, Token![;])?.into_iter().collect();
|
||||||
input.parse_terminated::<_, Token![;]>(ContractArgs::parse)?.into_iter().collect();
|
|
||||||
Ok(Self { inner })
|
Ok(Self { inner })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,7 +121,7 @@ impl Parse for Parameter {
|
||||||
"methods" => {
|
"methods" => {
|
||||||
let content;
|
let content;
|
||||||
braced!(content in input);
|
braced!(content in input);
|
||||||
let parsed = content.parse_terminated::<_, Token![;]>(Spanned::<Method>::parse)?;
|
let parsed = content.parse_terminated(Spanned::<Method>::parse, Token![;])?;
|
||||||
|
|
||||||
let mut methods = Vec::with_capacity(parsed.len());
|
let mut methods = Vec::with_capacity(parsed.len());
|
||||||
let mut signatures = HashSet::new();
|
let mut signatures = HashSet::new();
|
||||||
|
@ -141,7 +140,7 @@ impl Parse for Parameter {
|
||||||
"derives" | "event_derives" => {
|
"derives" | "event_derives" => {
|
||||||
let content;
|
let content;
|
||||||
parenthesized!(content in input);
|
parenthesized!(content in input);
|
||||||
let derives = content.parse_terminated::<_, Token![,]>(Path::parse)?;
|
let derives = content.parse_terminated(Path::parse, Token![,])?;
|
||||||
Ok(Parameter::Derives(derives))
|
Ok(Parameter::Derives(derives))
|
||||||
}
|
}
|
||||||
_ => Err(Error::new(name.span(), "unexpected named parameter")),
|
_ => Err(Error::new(name.span(), "unexpected named parameter")),
|
||||||
|
@ -168,7 +167,7 @@ impl Parse for Method {
|
||||||
// function params
|
// function params
|
||||||
let content;
|
let content;
|
||||||
parenthesized!(content in input);
|
parenthesized!(content in input);
|
||||||
let params = content.parse_terminated::<_, Token![,]>(Ident::parse)?;
|
let params = content.parse_terminated(Ident::parse, Token![,])?;
|
||||||
let last_i = params.len().saturating_sub(1);
|
let last_i = params.len().saturating_sub(1);
|
||||||
|
|
||||||
signature.push('(');
|
signature.push('(');
|
||||||
|
|
|
@ -11,12 +11,10 @@ use syn::{parse::Error, DeriveInput};
|
||||||
|
|
||||||
/// Generates the `ethcall` trait support
|
/// Generates the `ethcall` trait support
|
||||||
pub(crate) fn derive_eth_call_impl(input: DeriveInput) -> Result<TokenStream, Error> {
|
pub(crate) fn derive_eth_call_impl(input: DeriveInput) -> Result<TokenStream, Error> {
|
||||||
let attributes = parse_calllike_attributes(&input, "ethcall")?;
|
let attributes = parse_calllike_attributes!(input, "ethcall");
|
||||||
|
|
||||||
let function_call_name =
|
let function_call_name = attributes.name(&input.ident);
|
||||||
attributes.name.map(|(s, _)| s).unwrap_or_else(|| input.ident.to_string());
|
let mut function = if let Some((abi, span)) = attributes.abi() {
|
||||||
|
|
||||||
let mut function = if let Some((abi, span)) = attributes.abi {
|
|
||||||
let sig = abi.trim_start_matches("function ").trim_start();
|
let sig = abi.trim_start_matches("function ").trim_start();
|
||||||
// try to parse as solidity function
|
// try to parse as solidity function
|
||||||
match HumanReadableParser::parse_function(&abi) {
|
match HumanReadableParser::parse_function(&abi) {
|
||||||
|
|
|
@ -7,97 +7,50 @@ use ethers_core::{
|
||||||
};
|
};
|
||||||
use proc_macro2::{Ident, Span, TokenStream};
|
use proc_macro2::{Ident, Span, TokenStream};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{parse::Error, spanned::Spanned, AttrStyle, DeriveInput, Lit, Meta, NestedMeta};
|
use syn::{DeriveInput, LitStr, Result};
|
||||||
|
|
||||||
/// All the attributes the `EthCall`/`EthError` macro supports
|
/// All the attributes the `EthCall`/`EthError` macro supports
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct EthCalllikeAttributes {
|
pub struct EthCalllikeAttributes {
|
||||||
pub name: Option<(String, Span)>,
|
pub name: Option<LitStr>,
|
||||||
pub abi: Option<(String, Span)>,
|
pub abi: Option<LitStr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// extracts the attributes from the struct annotated with the given attribute
|
impl EthCalllikeAttributes {
|
||||||
pub fn parse_calllike_attributes(
|
pub fn name(&self, fallback: &Ident) -> String {
|
||||||
input: &DeriveInput,
|
self.name.as_ref().map(|s| s.value()).unwrap_or_else(|| fallback.to_string())
|
||||||
attr_name: &str,
|
|
||||||
) -> Result<EthCalllikeAttributes, Error> {
|
|
||||||
let mut result = EthCalllikeAttributes::default();
|
|
||||||
for a in input.attrs.iter() {
|
|
||||||
if let AttrStyle::Outer = a.style {
|
|
||||||
if let Ok(Meta::List(meta)) = a.parse_meta() {
|
|
||||||
if meta.path.is_ident(attr_name) {
|
|
||||||
for n in meta.nested.iter() {
|
|
||||||
if let NestedMeta::Meta(meta) = n {
|
|
||||||
match meta {
|
|
||||||
Meta::Path(path) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
path.span(),
|
|
||||||
format!("unrecognized {attr_name} parameter"),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
Meta::List(meta) => {
|
|
||||||
return Err(Error::new(
|
pub fn abi(&self) -> Option<(String, Span)> {
|
||||||
meta.path.span(),
|
self.abi.as_ref().map(|s| (s.value(), s.span()))
|
||||||
format!("unrecognized {attr_name} parameter"),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
Meta::NameValue(meta) => {
|
|
||||||
if meta.path.is_ident("name") {
|
|
||||||
if let Lit::Str(ref lit_str) = meta.lit {
|
|
||||||
if result.name.is_none() {
|
|
||||||
result.name =
|
|
||||||
Some((lit_str.value(), lit_str.span()));
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"name already specified",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"name must be a string",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else if meta.path.is_ident("abi") {
|
|
||||||
if let Lit::Str(ref lit_str) = meta.lit {
|
|
||||||
if result.abi.is_none() {
|
|
||||||
result.abi =
|
|
||||||
Some((lit_str.value(), lit_str.span()));
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"abi already specified",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"abi must be a string",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
format!("unrecognized {attr_name} parameter"),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! parse_calllike_attributes {
|
||||||
|
($input:ident, $attr_ident:literal) => {{
|
||||||
|
let mut result = EthCalllikeAttributes::default();
|
||||||
|
$crate::utils::parse_attributes!($input.attrs.iter(), $attr_ident, meta,
|
||||||
|
"name", result.name => {
|
||||||
|
meta.input.parse::<::syn::Token![=]>()?;
|
||||||
|
let litstr: ::syn::LitStr = meta.input.parse()?;
|
||||||
|
result.name = Some(litstr);
|
||||||
|
}
|
||||||
|
"abi", result.abi => {
|
||||||
|
meta.input.parse::<::syn::Token![=]>()?;
|
||||||
|
let litstr: ::syn::LitStr = meta.input.parse()?;
|
||||||
|
result.abi = Some(litstr);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
result
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
pub(crate) use parse_calllike_attributes;
|
||||||
|
|
||||||
/// Generates the decode implementation based on the type's runtime `AbiType` impl
|
/// Generates the decode implementation based on the type's runtime `AbiType` impl
|
||||||
pub fn derive_decode_impl_with_abi_type(
|
pub fn derive_decode_impl_with_abi_type(
|
||||||
input: &DeriveInput,
|
input: &DeriveInput,
|
||||||
trait_ident: Ident,
|
trait_ident: Ident,
|
||||||
) -> Result<TokenStream, Error> {
|
) -> Result<TokenStream> {
|
||||||
let datatypes_array = utils::abi_parameters_array(input, &trait_ident.to_string())?;
|
let datatypes_array = utils::abi_parameters_array(input, &trait_ident.to_string())?;
|
||||||
Ok(derive_decode_impl(datatypes_array, trait_ident))
|
Ok(derive_decode_impl(datatypes_array, trait_ident))
|
||||||
}
|
}
|
||||||
|
@ -130,7 +83,7 @@ pub fn derive_codec_impls(
|
||||||
input: &DeriveInput,
|
input: &DeriveInput,
|
||||||
decode_impl: TokenStream,
|
decode_impl: TokenStream,
|
||||||
trait_ident: Ident,
|
trait_ident: Ident,
|
||||||
) -> Result<TokenStream, Error> {
|
) -> Result<TokenStream> {
|
||||||
// the ethers crates to use
|
// the ethers crates to use
|
||||||
let ethers_core = ethers_core_crate();
|
let ethers_core = ethers_core_crate();
|
||||||
let ethers_contract = ethers_contract_crate();
|
let ethers_contract = ethers_contract_crate();
|
||||||
|
|
|
@ -11,11 +11,10 @@ use syn::{parse::Error, DeriveInput};
|
||||||
|
|
||||||
/// Generates the `EthError` trait support
|
/// Generates the `EthError` trait support
|
||||||
pub(crate) fn derive_eth_error_impl(input: DeriveInput) -> Result<TokenStream, Error> {
|
pub(crate) fn derive_eth_error_impl(input: DeriveInput) -> Result<TokenStream, Error> {
|
||||||
let attributes = parse_calllike_attributes(&input, "etherror")?;
|
let attributes = parse_calllike_attributes!(input, "etherror");
|
||||||
|
|
||||||
let error_name = attributes.name.map(|(s, _)| s).unwrap_or_else(|| input.ident.to_string());
|
let error_name = attributes.name(&input.ident);
|
||||||
|
let mut error = if let Some((src, span)) = attributes.abi() {
|
||||||
let mut error = if let Some((src, span)) = attributes.abi {
|
|
||||||
let raw_function_sig = src.trim_start_matches("error ").trim_start();
|
let raw_function_sig = src.trim_start_matches("error ").trim_start();
|
||||||
// try to parse as solidity error
|
// try to parse as solidity error
|
||||||
match HumanReadableParser::parse_error(&src) {
|
match HumanReadableParser::parse_error(&src) {
|
||||||
|
|
|
@ -6,16 +6,12 @@ use ethers_core::{
|
||||||
abi::{Event, EventExt, EventParam, HumanReadableParser},
|
abi::{Event, EventExt, EventParam, HumanReadableParser},
|
||||||
macros::{ethers_contract_crate, ethers_core_crate},
|
macros::{ethers_contract_crate, ethers_core_crate},
|
||||||
};
|
};
|
||||||
use hex::FromHex;
|
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{
|
use syn::{spanned::Spanned, Data, DeriveInput, Error, Field, Fields, LitStr, Result, Token};
|
||||||
parse::Error, spanned::Spanned, AttrStyle, Data, DeriveInput, Field, Fields, Lit, Meta,
|
|
||||||
NestedMeta,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Generates the `EthEvent` trait support
|
/// Generates the `EthEvent` trait support
|
||||||
pub(crate) fn derive_eth_event_impl(input: DeriveInput) -> Result<TokenStream, Error> {
|
pub(crate) fn derive_eth_event_impl(input: DeriveInput) -> Result<TokenStream> {
|
||||||
let name = &input.ident;
|
let name = &input.ident;
|
||||||
let attributes = parse_event_attributes(&input)?;
|
let attributes = parse_event_attributes(&input)?;
|
||||||
|
|
||||||
|
@ -64,7 +60,7 @@ pub(crate) fn derive_eth_event_impl(input: DeriveInput) -> Result<TokenStream, E
|
||||||
|
|
||||||
let (abi, event_sig) = (event.abi_signature(), event.signature());
|
let (abi, event_sig) = (event.abi_signature(), event.signature());
|
||||||
|
|
||||||
let signature = if let Some((hash, _)) = attributes.signature_hash {
|
let signature = if let Some((hash, _)) = attributes.signature {
|
||||||
utils::signature(&hash)
|
utils::signature(&hash)
|
||||||
} else {
|
} else {
|
||||||
utils::signature(event_sig.as_bytes())
|
utils::signature(event_sig.as_bytes())
|
||||||
|
@ -122,7 +118,7 @@ impl EventField {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derive_decode_from_log_impl(input: &DeriveInput, event: &Event) -> Result<TokenStream, Error> {
|
fn derive_decode_from_log_impl(input: &DeriveInput, event: &Event) -> Result<TokenStream> {
|
||||||
let ethers_core = ethers_core_crate();
|
let ethers_core = ethers_core_crate();
|
||||||
|
|
||||||
let fields: Vec<_> = match input.data {
|
let fields: Vec<_> = match input.data {
|
||||||
|
@ -291,7 +287,7 @@ fn derive_decode_from_log_impl(input: &DeriveInput, event: &Event) -> Result<Tok
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine the event's ABI by parsing the AST
|
/// Determine the event's ABI by parsing the AST
|
||||||
fn derive_abi_event_from_fields(input: &DeriveInput) -> Result<Event, Error> {
|
fn derive_abi_event_from_fields(input: &DeriveInput) -> Result<Event> {
|
||||||
let event = Event {
|
let event = Event {
|
||||||
name: input.ident.to_string(),
|
name: input.ident.to_string(),
|
||||||
inputs: utils::derive_abi_inputs_from_fields(input, "EthEvent")?
|
inputs: utils::derive_abi_inputs_from_fields(input, "EthEvent")?
|
||||||
|
@ -303,53 +299,18 @@ fn derive_abi_event_from_fields(input: &DeriveInput) -> Result<Event, Error> {
|
||||||
Ok(event)
|
Ok(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_field_attributes(field: &Field) -> Result<(Option<String>, bool), Error> {
|
fn parse_field_attributes(field: &Field) -> Result<(Option<String>, bool)> {
|
||||||
let mut indexed = false;
|
let mut indexed = None::<bool>;
|
||||||
let mut topic_name = None;
|
let mut topic_name = None::<String>;
|
||||||
for a in field.attrs.iter() {
|
utils::parse_attributes!(field.attrs.iter(), "ethevent", meta,
|
||||||
if let AttrStyle::Outer = a.style {
|
"indexed", indexed => { indexed = Some(true) }
|
||||||
if let Ok(Meta::List(meta)) = a.parse_meta() {
|
"name", topic_name => {
|
||||||
if meta.path.is_ident("ethevent") {
|
meta.input.parse::<Token![=]>()?;
|
||||||
for n in meta.nested.iter() {
|
let litstr: LitStr = meta.input.parse()?;
|
||||||
if let NestedMeta::Meta(meta) = n {
|
topic_name = Some(litstr.value());
|
||||||
match meta {
|
|
||||||
Meta::Path(path) => {
|
|
||||||
if path.is_ident("indexed") {
|
|
||||||
indexed = true;
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
path.span(),
|
|
||||||
"unrecognized ethevent parameter",
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
Meta::List(meta) => {
|
Ok((topic_name, indexed.unwrap_or_default()))
|
||||||
return Err(Error::new(
|
|
||||||
meta.path.span(),
|
|
||||||
"unrecognized ethevent parameter",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
Meta::NameValue(meta) => {
|
|
||||||
if meta.path.is_ident("name") {
|
|
||||||
if let Lit::Str(ref lit_str) = meta.lit {
|
|
||||||
topic_name = Some(lit_str.value());
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"name attribute must be a string",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((topic_name, indexed))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All the attributes the `EthEvent` macro supports
|
/// All the attributes the `EthEvent` macro supports
|
||||||
|
@ -357,139 +318,32 @@ fn parse_field_attributes(field: &Field) -> Result<(Option<String>, bool), Error
|
||||||
struct EthEventAttributes {
|
struct EthEventAttributes {
|
||||||
name: Option<(String, Span)>,
|
name: Option<(String, Span)>,
|
||||||
abi: Option<(String, Span)>,
|
abi: Option<(String, Span)>,
|
||||||
signature_hash: Option<(Vec<u8>, Span)>,
|
signature: Option<(Vec<u8>, Span)>,
|
||||||
anonymous: Option<(bool, Span)>,
|
anonymous: Option<(bool, Span)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// extracts the attributes from the struct annotated with `EthEvent`
|
/// extracts the attributes from the struct annotated with `EthEvent`
|
||||||
fn parse_event_attributes(input: &DeriveInput) -> Result<EthEventAttributes, Error> {
|
fn parse_event_attributes(input: &DeriveInput) -> Result<EthEventAttributes> {
|
||||||
let mut result = EthEventAttributes::default();
|
let mut result = EthEventAttributes::default();
|
||||||
for a in input.attrs.iter() {
|
utils::parse_attributes!(input.attrs.iter(), "ethevent", meta,
|
||||||
if let AttrStyle::Outer = a.style {
|
"name", result.name => {
|
||||||
if let Ok(Meta::List(meta)) = a.parse_meta() {
|
meta.input.parse::<Token![=]>()?;
|
||||||
if meta.path.is_ident("ethevent") {
|
let litstr: LitStr = meta.input.parse()?;
|
||||||
for n in meta.nested.iter() {
|
result.name = Some((litstr.value(), litstr.span()));
|
||||||
if let NestedMeta::Meta(meta) = n {
|
|
||||||
match meta {
|
|
||||||
Meta::Path(path) => {
|
|
||||||
if let Some(name) = path.get_ident() {
|
|
||||||
if &*name.to_string() == "anonymous" {
|
|
||||||
if result.anonymous.is_none() {
|
|
||||||
result.anonymous = Some((true, name.span()));
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
name.span(),
|
|
||||||
"anonymous already specified",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Err(Error::new(
|
|
||||||
path.span(),
|
|
||||||
"unrecognized ethevent parameter",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
Meta::List(meta) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.path.span(),
|
|
||||||
"unrecognized ethevent parameter",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
Meta::NameValue(meta) => {
|
|
||||||
if meta.path.is_ident("anonymous") {
|
|
||||||
if let Lit::Bool(ref bool_lit) = meta.lit {
|
|
||||||
if result.anonymous.is_none() {
|
|
||||||
result.anonymous =
|
|
||||||
Some((bool_lit.value, bool_lit.span()));
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"anonymous already specified",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"name must be a string",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else if meta.path.is_ident("name") {
|
|
||||||
if let Lit::Str(ref lit_str) = meta.lit {
|
|
||||||
if result.name.is_none() {
|
|
||||||
result.name =
|
|
||||||
Some((lit_str.value(), lit_str.span()));
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"name already specified",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"name must be a string",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else if meta.path.is_ident("abi") {
|
|
||||||
if let Lit::Str(ref lit_str) = meta.lit {
|
|
||||||
if result.abi.is_none() {
|
|
||||||
result.abi =
|
|
||||||
Some((lit_str.value(), lit_str.span()));
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"abi already specified",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"abi must be a string",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else if meta.path.is_ident("signature") {
|
|
||||||
if let Lit::Str(ref lit_str) = meta.lit {
|
|
||||||
if result.signature_hash.is_none() {
|
|
||||||
match Vec::from_hex(lit_str.value()) {
|
|
||||||
Ok(sig) => {
|
|
||||||
result.signature_hash =
|
|
||||||
Some((sig, lit_str.span()))
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
format!(
|
|
||||||
"Expected hex signature: {err:?}"
|
|
||||||
),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"signature already specified",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"signature must be a hex string",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(Error::new(
|
|
||||||
meta.span(),
|
|
||||||
"unrecognized ethevent parameter",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
"abi", result.abi => {
|
||||||
|
meta.input.parse::<Token![=]>()?;
|
||||||
|
let litstr: LitStr = meta.input.parse()?;
|
||||||
|
result.abi = Some((litstr.value(), litstr.span()));
|
||||||
}
|
}
|
||||||
|
"signature", result.signature => {
|
||||||
|
meta.input.parse::<Token![=]>()?;
|
||||||
|
let litstr: LitStr = meta.input.parse()?;
|
||||||
|
let s = litstr.value();
|
||||||
|
let b = hex::decode(s.strip_prefix("0x").unwrap_or(&s)).map_err(|e| meta.error(e))?;
|
||||||
|
result.signature = Some((b, litstr.span()));
|
||||||
}
|
}
|
||||||
|
"anonymous", result.anonymous => { result.anonymous = Some((true, meta.path.span())); }
|
||||||
|
);
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,35 @@ use syn::{
|
||||||
PathArguments, Type,
|
PathArguments, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Parses the specified attributes from a `syn::Attribute` iterator.
|
||||||
|
macro_rules! parse_attributes {
|
||||||
|
($attrs:expr, $attr_ident:literal, $meta:ident, $($field:pat, $opt:expr => $block:block)*) => {
|
||||||
|
const ERROR: &str = concat!("unrecognized ", $attr_ident, " attribute");
|
||||||
|
const ALREADY_SPECIFIED: &str = concat!($attr_ident, " attribute already specified");
|
||||||
|
|
||||||
|
for attr in $attrs {
|
||||||
|
if !attr.path().is_ident($attr_ident) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr.parse_nested_meta(|$meta| {
|
||||||
|
let ident = $meta.path.get_ident().ok_or_else(|| $meta.error(ERROR))?.to_string();
|
||||||
|
match ident.as_str() {
|
||||||
|
$(
|
||||||
|
$field if $opt.is_none() => $block,
|
||||||
|
$field => return Err($meta.error(ALREADY_SPECIFIED)),
|
||||||
|
)*
|
||||||
|
|
||||||
|
_ => return Err($meta.error(ERROR)),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub(crate) use parse_attributes;
|
||||||
|
|
||||||
pub fn ident(name: &str) -> Ident {
|
pub fn ident(name: &str) -> Ident {
|
||||||
Ident::new(name, Span::call_site())
|
Ident::new(name, Span::call_site())
|
||||||
}
|
}
|
||||||
|
@ -104,6 +133,8 @@ pub fn param_type_quote(kind: &ParamType) -> TokenStream {
|
||||||
/// Tries to find the corresponding `ParamType` used for tokenization for the
|
/// Tries to find the corresponding `ParamType` used for tokenization for the
|
||||||
/// given type
|
/// given type
|
||||||
pub fn find_parameter_type(ty: &Type) -> Result<ParamType, Error> {
|
pub fn find_parameter_type(ty: &Type) -> Result<ParamType, Error> {
|
||||||
|
const ERROR: &str = "Failed to derive proper ABI from array field";
|
||||||
|
|
||||||
match ty {
|
match ty {
|
||||||
Type::Array(arr) => {
|
Type::Array(arr) => {
|
||||||
let ty = find_parameter_type(&arr.elem)?;
|
let ty = find_parameter_type(&arr.elem)?;
|
||||||
|
@ -114,7 +145,7 @@ pub fn find_parameter_type(ty: &Type) -> Result<ParamType, Error> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Error::new(arr.span(), "Failed to derive proper ABI from array field"))
|
Err(Error::new(arr.span(), ERROR))
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::Path(ty) => {
|
Type::Path(ty) => {
|
||||||
|
@ -151,7 +182,7 @@ pub fn find_parameter_type(ty: &Type) -> Result<ParamType, Error> {
|
||||||
s => parse_param_type(s),
|
s => parse_param_type(s),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.ok_or_else(|| Error::new(ty.span(), "Failed to derive proper ABI from fields"))
|
.ok_or_else(|| Error::new(ty.span(), ERROR))
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::Tuple(ty) => ty
|
Type::Tuple(ty) => ty
|
||||||
|
@ -161,7 +192,7 @@ pub fn find_parameter_type(ty: &Type) -> Result<ParamType, Error> {
|
||||||
.collect::<Result<Vec<_>, _>>()
|
.collect::<Result<Vec<_>, _>>()
|
||||||
.map(ParamType::Tuple),
|
.map(ParamType::Tuple),
|
||||||
|
|
||||||
_ => Err(Error::new(ty.span(), "Failed to derive proper ABI from fields")),
|
_ => Err(Error::new(ty.span(), ERROR)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue