Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
use crate detection
Browse files Browse the repository at this point in the history
  • Loading branch information
mattsse committed Aug 5, 2021
1 parent 5692dc2 commit dd7fb51
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 51 deletions.
2 changes: 1 addition & 1 deletion ethers-contract/ethers-contract-abigen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ mod util;

pub use ethers_core::types::Address;
pub use source::Source;
pub use util::{ethers_crate, parse_address};
pub use util::{ethers_contract_crate, ethers_core_crate, parse_address};

use anyhow::Result;
use proc_macro2::TokenStream;
Expand Down
29 changes: 18 additions & 11 deletions ethers-contract/ethers-contract-abigen/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,26 @@ use cargo_metadata::{CargoOpt, DependencyKind, Metadata, MetadataCommand};
use inflector::Inflector;
use once_cell::sync::Lazy;
use proc_macro2::{Ident, Literal, Span, TokenStream};
use quote::{format_ident, quote};
use quote::quote;
use reqwest::Client;
use syn::Ident as SynIdent;
use syn::{Ident as SynIdent, Path};

/// See `determine_ethers_crate`
/// See `determine_ethers_crates`
///
/// This ensures that the `MetadataCommand` is only run once
static ETHERS_CRATE: Lazy<&'static str> = Lazy::new(determine_ethers_crate);
static ETHERS_CRATES: Lazy<(&'static str, &'static str)> = Lazy::new(determine_ethers_crates);

/// Convenience function to turn `ETHERS_CRATE` into an `Ident`
pub fn ethers_crate() -> Ident {
format_ident!("{}", *ETHERS_CRATE)
/// Convenience function to turn the `ethers_core` name in `ETHERS_CRATE` into a `Path`
pub fn ethers_core_crate() -> Path {
syn::parse_str(ETHERS_CRATES.0).unwrap()
}
/// Convenience function to turn the `ethers_contract` name in `ETHERS_CRATE` into an `Path`
pub fn ethers_contract_crate() -> Path {
syn::parse_str(ETHERS_CRATES.1).unwrap()
}

/// The crate name to use when deriving macros
/// The crates name to use when deriving macros: (`core`, `contract`)
///
/// We try to determine which crate ident to use based on the dependencies of
/// the project in which the macro is used. This is useful because the macros,
/// like `EthEvent` are provided by the `ethers-contract` crate which depends on
Expand All @@ -29,7 +34,7 @@ pub fn ethers_crate() -> Ident {
/// | ethers_contract`, we need to use the fitting crate ident when expand the
/// macros This will attempt to parse the current `Cargo.toml` and check the
/// ethers related dependencies.
pub fn determine_ethers_crate() -> &'static str {
pub fn determine_ethers_crates() -> (&'static str, &'static str) {
MetadataCommand::new()
.manifest_path(&format!(
"{}/Cargo.toml",
Expand All @@ -42,10 +47,12 @@ pub fn determine_ethers_crate() -> &'static str {
pkg.dependencies
.iter()
.filter(|dep| dep.kind == DependencyKind::Normal)
.find_map(|pkg| (pkg.name == "ethers").then(|| "ethers"))
.find_map(|pkg| {
(pkg.name == "ethers").then(|| ("ethers::core", "ethers::contract"))
})
})
})
.unwrap_or("ethers_core")
.unwrap_or(("ethers_core", "ethers_contract"))
}

/// Expands a identifier string into an token.
Expand Down
89 changes: 50 additions & 39 deletions ethers-contract/ethers-contract-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! ethereum smart contract.
#![deny(missing_docs, unsafe_code)]

use ethers_contract_abigen::Source;
use ethers_contract_abigen::{ethers_contract_crate, ethers_core_crate, Source};
use proc_macro::TokenStream;
use proc_macro2::{Literal, Span};
use quote::{quote, quote_spanned};
Expand Down Expand Up @@ -117,6 +117,11 @@ pub fn abigen(input: TokenStream) -> TokenStream {
#[proc_macro_derive(EthEvent, attributes(ethevent))]
pub fn derive_abi_event(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);

// the ethers crates to use
let core_crate = ethers_core_crate();
let contract_crate = ethers_contract_crate();

let name = &input.ident;
let attributes = match parse_attributes(&input) {
Ok(attributes) => attributes,
Expand Down Expand Up @@ -206,21 +211,21 @@ pub fn derive_abi_event(input: TokenStream) -> TokenStream {
let anon = attributes.anonymous.map(|(b, _)| b).unwrap_or_default();

let ethevent_impl = quote! {
impl ethers_contract::EthEvent for #name {
impl #contract_crate::EthEvent for #name {

fn name() -> ::std::borrow::Cow<'static, str> {
#event_name.into()
}

fn signature() -> ethers_core::types::H256 {
fn signature() -> #core_crate::types::H256 {
#signature
}

fn abi_signature() -> ::std::borrow::Cow<'static, str> {
#abi.into()
}

fn decode_log(log: &ethers_core::abi::RawLog) -> Result<Self, ethers_core::abi::Error> where Self: Sized {
fn decode_log(log: &#core_crate::abi::RawLog) -> Result<Self, #core_crate::abi::Error> where Self: Sized {
#decode_log_impl
}

Expand Down Expand Up @@ -256,55 +261,57 @@ impl EventField {
// these indexed param types according to
// https://solidity.readthedocs.io/en/develop/abi-spec.html#encoding-of-indexed-event-parameters
fn topic_param_type_quote(kind: &ParamType) -> proc_macro2::TokenStream {
let core_crate = ethers_core_crate();
match kind {
ParamType::String
| ParamType::Bytes
| ParamType::Array(_)
| ParamType::FixedArray(_, _)
| ParamType::Tuple(_) => quote! {ethers_core::abi::ParamType::FixedBytes(32)},
| ParamType::Tuple(_) => quote! {#core_crate::abi::ParamType::FixedBytes(32)},
ty => param_type_quote(ty),
}
}

fn param_type_quote(kind: &ParamType) -> proc_macro2::TokenStream {
let core_crate = ethers_core_crate();
match kind {
ParamType::Address => {
quote! {ethers_core::abi::ParamType::Address}
quote! {#core_crate::abi::ParamType::Address}
}
ParamType::Bytes => {
quote! {ethers_core::abi::ParamType::Bytes}
quote! {#core_crate::abi::ParamType::Bytes}
}
ParamType::Int(size) => {
let size = Literal::usize_suffixed(*size);
quote! {ethers_core::abi::ParamType::Int(#size)}
quote! {#core_crate::abi::ParamType::Int(#size)}
}
ParamType::Uint(size) => {
let size = Literal::usize_suffixed(*size);
quote! {ethers_core::abi::ParamType::Uint(#size)}
quote! {#core_crate::abi::ParamType::Uint(#size)}
}
ParamType::Bool => {
quote! {ethers_core::abi::ParamType::Bool}
quote! {#core_crate::abi::ParamType::Bool}
}
ParamType::String => {
quote! {ethers_core::abi::ParamType::String}
quote! {#core_crate::abi::ParamType::String}
}
ParamType::Array(ty) => {
let ty = param_type_quote(&*ty);
quote! {ethers_core::abi::ParamType::Array(Box::new(#ty))}
quote! {#core_crate::abi::ParamType::Array(Box::new(#ty))}
}
ParamType::FixedBytes(size) => {
let size = Literal::usize_suffixed(*size);
quote! {ethers_core::abi::ParamType::FixedBytes(#size)}
quote! {#core_crate::abi::ParamType::FixedBytes(#size)}
}
ParamType::FixedArray(ty, size) => {
let ty = param_type_quote(&*ty);
let size = Literal::usize_suffixed(*size);
quote! {ethers_core::abi::ParamType::FixedArray(Box::new(#ty),#size)}
quote! {#core_crate::abi::ParamType::FixedArray(Box::new(#ty),#size)}
}
ParamType::Tuple(tuple) => {
let elements = tuple.iter().map(param_type_quote);
quote! {
ethers_core::abi::ParamType::Tuple(
#core_crate::abi::ParamType::Tuple(
::std::vec![
#( #elements ),*
]
Expand All @@ -318,6 +325,8 @@ fn derive_decode_from_log_impl(
input: &DeriveInput,
event: &Event,
) -> Result<proc_macro2::TokenStream, Error> {
let core_crate = ethers_core_crate();

let fields: Vec<_> = match input.data {
Data::Struct(ref data) => match data.fields {
Fields::Named(ref fields) => {
Expand Down Expand Up @@ -416,24 +425,24 @@ fn derive_decode_from_log_impl(
},
quote! {
if topic_tokens.len() != topics.len() {
return Err(ethers_core::abi::Error::InvalidData);
return Err(#core_crate::abi::Error::InvalidData);
}
},
)
} else {
(
quote! {
let event_signature = topics.get(0).ok_or(ethers_core::abi::Error::InvalidData)?;
let event_signature = topics.get(0).ok_or(#core_crate::abi::Error::InvalidData)?;
if event_signature != &Self::signature() {
return Err(ethers_core::abi::Error::InvalidData);
return Err(#core_crate::abi::Error::InvalidData);
}
},
quote! {
let flat_topics = topics.iter().skip(1).flat_map(|t| t.as_ref().to_vec()).collect::<Vec<u8>>();
},
quote! {
if topic_tokens.len() != topics.len() - 1 {
return Err(ethers_core::abi::Error::InvalidData);
return Err(#core_crate::abi::Error::InvalidData);
}
},
)
Expand All @@ -447,9 +456,9 @@ fn derive_decode_from_log_impl(
.all(|(idx, f)| f.index == idx)
{
quote! {
let topic_tokens = ethers_core::abi::decode(&topic_types, &flat_topics)?;
let topic_tokens = #core_crate::abi::decode(&topic_types, &flat_topics)?;
#topic_tokens_len_check
let data_tokens = ethers_core::abi::decode(&data_types, data)?;
let data_tokens = #core_crate::abi::decode(&data_types, data)?;
let tokens:Vec<_> = topic_tokens.into_iter().chain(data_tokens.into_iter()).collect();
}
} else {
Expand All @@ -462,17 +471,17 @@ fn derive_decode_from_log_impl(
});

quote! {
let mut topic_tokens = ethers_core::abi::decode(&topic_types, &flat_topics)?;
let mut topic_tokens = #core_crate::abi::decode(&topic_types, &flat_topics)?;
#topic_tokens_len_check
let mut data_tokens = ethers_core::abi::decode(&data_types, &data)?;
let mut data_tokens = #core_crate::abi::decode(&data_types, &data)?;
let mut tokens = Vec::with_capacity(topics.len() + data_tokens.len());
#( tokens.push(#swap_tokens); )*
}
};

Ok(quote! {

let ethers_core::abi::RawLog {data, topics} = log;
let #core_crate::abi::RawLog {data, topics} = log;

#signature_check

Expand All @@ -483,7 +492,7 @@ fn derive_decode_from_log_impl(

#tokens_init

ethers_core::abi::Detokenize::from_tokens(tokens).map_err(|_|ethers_core::abi::Error::InvalidData)
#core_crate::abi::Detokenize::from_tokens(tokens).map_err(|_|#core_crate::abi::Error::InvalidData)
})
}

Expand Down Expand Up @@ -669,8 +678,9 @@ fn parse_int_param_type(s: &str) -> Option<ParamType> {
}

fn signature(hash: &[u8]) -> proc_macro2::TokenStream {
let core_crate = ethers_core_crate();
let bytes = hash.iter().copied().map(Literal::u8_unsuffixed);
quote! {ethers_core::types::H256([#( #bytes ),*])}
quote! {#core_crate::types::H256([#( #bytes ),*])}
}

fn parse_event(abi: &str) -> Result<Event, String> {
Expand All @@ -695,6 +705,7 @@ pub fn derive_abi_type(input: TokenStream) -> TokenStream {
}

fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
let core_crate = ethers_core_crate();
let name = &input.ident;
let generic_params = input.generics.params.iter().map(|p| quote! { #p });
let generic_params = quote! { #(#generic_params,)* };
Expand All @@ -719,13 +730,13 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
Fields::Named(ref fields) => {
let tokenize_predicates = fields.named.iter().map(|f| {
let ty = &f.ty;
quote_spanned! { f.span() => #ty: ethers_core::abi::Tokenize }
quote_spanned! { f.span() => #ty: #core_crate::abi::Tokenize }
});
let tokenize_predicates = quote! { #(#tokenize_predicates,)* };

let assignments = fields.named.iter().map(|f| {
let name = f.ident.as_ref().expect("Named fields have names");
quote_spanned! { f.span() => #name: ethers_core::abi::Tokenizable::from_token(iter.next().expect("tokens size is sufficient qed").into_token())? }
quote_spanned! { f.span() => #name: #core_crate::abi::Tokenizable::from_token(iter.next().expect("tokens size is sufficient qed").into_token())? }
});
let init_struct_impl = quote! { Self { #(#assignments,)* } };

Expand All @@ -745,12 +756,12 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
Fields::Unnamed(ref fields) => {
let tokenize_predicates = fields.unnamed.iter().map(|f| {
let ty = &f.ty;
quote_spanned! { f.span() => #ty: ethers_core::abi::Tokenize }
quote_spanned! { f.span() => #ty: #core_crate::abi::Tokenize }
});
let tokenize_predicates = quote! { #(#tokenize_predicates,)* };

let assignments = fields.unnamed.iter().map(|f| {
quote_spanned! { f.span() => ethers_core::abi::Tokenizable::from_token(iter.next().expect("tokens size is sufficient qed").into_token())? }
quote_spanned! { f.span() => #core_crate::abi::Tokenizable::from_token(iter.next().expect("tokens size is sufficient qed").into_token())? }
});
let init_struct_impl = quote! { Self(#(#assignments,)* ) };

Expand Down Expand Up @@ -794,7 +805,7 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
// can't encode an empty struct
// TODO: panic instead?
quote! {
ethers_core::abi::Token::Tuple(Vec::new())
#core_crate::abi::Token::Tuple(Vec::new())
},
),
1 => {
Expand All @@ -819,9 +830,9 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
}
_ => {
let from_token = quote! {
if let ethers_core::abi::Token::Tuple(tokens) = token {
if let #core_crate::abi::Token::Tuple(tokens) = token {
if tokens.len() != #params_len {
return Err(ethers_core::abi::InvalidOutputType(::std::format!(
return Err(#core_crate::abi::InvalidOutputType(::std::format!(
"Expected {} tokens, got {}: {:?}",
#params_len,
tokens.len(),
Expand All @@ -833,15 +844,15 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {

Ok(#init_struct_impl)
} else {
Err(ethers_core::abi::InvalidOutputType(::std::format!(
Err(#core_crate::abi::InvalidOutputType(::std::format!(
"Expected Tuple, got {:?}",
token
)))
}
};

let into_token = quote! {
ethers_core::abi::Token::Tuple(
#core_crate::abi::Token::Tuple(
::std::vec![
#into_token_impl
]
Expand All @@ -852,23 +863,23 @@ fn derive_tokenizeable_impl(input: &DeriveInput) -> proc_macro2::TokenStream {
};

quote! {
impl<#generic_params> ethers_core::abi::Tokenizable for #name<#generic_args>
impl<#generic_params> #core_crate::abi::Tokenizable for #name<#generic_args>
where
#generic_predicates
#tokenize_predicates
{

fn from_token(token: ethers_core::abi::Token) -> Result<Self, ethers_core::abi::InvalidOutputType> where
fn from_token(token: #core_crate::abi::Token) -> Result<Self, #core_crate::abi::InvalidOutputType> where
Self: Sized {
#from_token_impl
}

fn into_token(self) -> ethers_core::abi::Token {
fn into_token(self) -> #core_crate::abi::Token {
#into_token_impl
}
}

impl<#generic_params> ethers_core::abi::TokenizableItem for #name<#generic_args>
impl<#generic_params> #core_crate::abi::TokenizableItem for #name<#generic_args>
where
#generic_predicates
#tokenize_predicates
Expand Down

0 comments on commit dd7fb51

Please sign in to comment.