refactor(abigen): inline docs (#2090)

* refactor: abigen docs

* chore: doc

* refactor: final doc

* mergings

* fix: unremove Default
This commit is contained in:
DaniPopes 2023-01-31 06:28:57 +01:00 committed by GitHub
parent 93e1850646
commit fd02bbc418
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 73 deletions

View File

@ -62,7 +62,7 @@ where
} }
pub(crate) fn imports(name: &str) -> TokenStream { pub(crate) fn imports(name: &str) -> TokenStream {
let doc = util::expand_doc(&format!("{name} was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs")); let doc_str = format!("{name} was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs");
let ethers_core = ethers_core_crate(); let ethers_core = ethers_core_crate();
let ethers_providers = ethers_providers_crate(); let ethers_providers = ethers_providers_crate();
@ -73,7 +73,7 @@ pub(crate) fn imports(name: &str) -> TokenStream {
#![allow(dead_code)] #![allow(dead_code)]
#![allow(clippy::type_complexity)] #![allow(clippy::type_complexity)]
#![allow(unused_imports)] #![allow(unused_imports)]
#doc #![doc = #doc_str]
use std::sync::Arc; use std::sync::Arc;
use #ethers_core::{ use #ethers_core::{

View File

@ -59,13 +59,12 @@ impl Context {
expand_data_struct(&error_name, &fields) expand_data_struct(&error_name, &fields)
}; };
let doc = format!( let doc_str = format!(
"Custom Error type `{}` with signature `{}` and selector `0x{}`", "Custom Error type `{}` with signature `{}` and selector `0x{}`",
error.name, error.name,
abi_signature, abi_signature,
hex::encode(&error.selector()[..]) hex::encode(&error.selector()[..])
); );
let abi_signature_doc = util::expand_doc(&doc);
let ethers_contract = ethers_contract_crate(); let ethers_contract = ethers_contract_crate();
// use the same derives as for events // use the same derives as for events
let derives = util::expand_derives(&self.event_derives); let derives = util::expand_derives(&self.event_derives);
@ -73,9 +72,9 @@ impl Context {
let error_name = &error.name; let error_name = &error.name;
Ok(quote! { Ok(quote! {
#abi_signature_doc #[doc = #doc_str]
#[derive(Clone, Debug, Default, Eq, PartialEq, #ethers_contract::EthError, #ethers_contract::EthDisplay, #derives)] #[derive(Clone, Debug, Default, Eq, PartialEq, #ethers_contract::EthError, #ethers_contract::EthDisplay, #derives)]
#[etherror( name = #error_name, abi = #abi_signature )] #[etherror(name = #error_name, abi = #abi_signature)]
pub #data_type_definition pub #data_type_definition
}) })
} }

View File

@ -217,24 +217,25 @@ impl Context {
/// Expands into a single method for contracting an event stream. /// Expands into a single method for contracting an event stream.
fn expand_filter(&self, event: &Event) -> TokenStream { fn expand_filter(&self, event: &Event) -> TokenStream {
let ethers_contract = ethers_contract_crate(); let name = &event.name;
let alias = self.event_aliases.get(&event.abi_signature()).cloned(); let alias = self.event_aliases.get(&event.abi_signature()).cloned();
let name = if let Some(id) = alias.clone() { // append `filter` to disambiguate with potentially conflicting
// function names
let function_name = if let Some(id) = alias.clone() {
util::safe_ident(&format!("{}_filter", id.to_string().to_snake_case())) util::safe_ident(&format!("{}_filter", id.to_string().to_snake_case()))
} else { } else {
util::safe_ident(&format!("{}_filter", event.name.to_snake_case())) util::safe_ident(&format!("{}_filter", event.name.to_snake_case()))
}; };
let struct_name = event_struct_name(name, alias);
// append `filter` to disambiguate with potentially conflicting let doc_str = format!("Gets the contract's `{name}` event");
// function names
let result = event_struct_name(&event.name, alias); let ethers_contract = ethers_contract_crate();
let doc = util::expand_doc(&format!("Gets the contract's `{}` event", event.name));
quote! { quote! {
#doc #[doc = #doc_str]
pub fn #name(&self) -> #ethers_contract::builders::Event<M, #result> { pub fn #function_name(&self) -> #ethers_contract::builders::Event<M, #struct_name> {
self.0.event() self.0.event()
} }
} }

View File

@ -124,13 +124,11 @@ impl Context {
}; };
let function_name = &function.name; let function_name = &function.name;
let abi_signature = function.abi_signature(); let abi_signature = function.abi_signature();
let doc = format!( let doc_str = format!(
"Container type for all input parameters for the `{}` function with signature `{}` and selector `0x{}`", "Container type for all input parameters for the `{function_name}` function with signature `{abi_signature}` and selector `0x{}`",
function.name,
abi_signature,
hex::encode(&function.selector()[..]) hex::encode(&function.selector()[..])
); );
let abi_signature_doc = util::expand_doc(&doc);
let ethers_contract = ethers_contract_crate(); let ethers_contract = ethers_contract_crate();
// use the same derives as for events // use the same derives as for events
let derives = util::expand_derives(&self.event_derives); let derives = util::expand_derives(&self.event_derives);
@ -146,7 +144,7 @@ impl Context {
}; };
Ok(quote! { Ok(quote! {
#abi_signature_doc #[doc = #doc_str]
#[derive(Clone, Debug, Eq, PartialEq, #ethers_contract::EthCall, #ethers_contract::EthDisplay, #derives)] #[derive(Clone, Debug, Eq, PartialEq, #ethers_contract::EthCall, #ethers_contract::EthDisplay, #derives)]
#derive_default #derive_default
#[ethcall( name = #function_name, abi = #abi_signature )] #[ethcall( name = #function_name, abi = #abi_signature )]
@ -160,6 +158,7 @@ impl Context {
function: &Function, function: &Function,
alias: Option<&MethodAlias>, alias: Option<&MethodAlias>,
) -> Result<TokenStream> { ) -> Result<TokenStream> {
let name = &function.name;
let struct_name = expand_return_struct_name(function, alias); let struct_name = expand_return_struct_name(function, alias);
let fields = self.expand_output_params(function)?; let fields = self.expand_output_params(function)?;
// no point in having structs when there is no data returned // no point in having structs when there is no data returned
@ -176,13 +175,11 @@ impl Context {
expand_data_struct(&struct_name, &fields) expand_data_struct(&struct_name, &fields)
}; };
let abi_signature = function.abi_signature(); let abi_signature = function.abi_signature();
let doc = format!( let doc_str = format!(
"Container type for all return fields from the `{}` function with signature `{}` and selector `0x{}`", "Container type for all return fields from the `{name}` function with signature `{abi_signature}` and selector `0x{}`",
function.name,
abi_signature,
hex::encode(&function.selector()[..]) hex::encode(&function.selector()[..])
); );
let abi_signature_doc = util::expand_doc(&doc);
let ethers_contract = ethers_contract_crate(); let ethers_contract = ethers_contract_crate();
// use the same derives as for events // use the same derives as for events
let derives = util::expand_derives(&self.event_derives); let derives = util::expand_derives(&self.event_derives);
@ -198,7 +195,7 @@ impl Context {
}; };
Ok(quote! { Ok(quote! {
#abi_signature_doc #[doc = #doc_str]
#[derive(Clone, Debug,Eq, PartialEq, #ethers_contract::EthAbiType, #ethers_contract::EthAbiCodec, #derives)] #[derive(Clone, Debug,Eq, PartialEq, #ethers_contract::EthAbiType, #ethers_contract::EthAbiCodec, #derives)]
#derive_default #derive_default
pub #return_type_definition pub #return_type_definition
@ -436,10 +433,11 @@ impl Context {
function: &Function, function: &Function,
alias: Option<MethodAlias>, alias: Option<MethodAlias>,
) -> Result<TokenStream> { ) -> Result<TokenStream> {
let ethers_contract = ethers_contract_crate(); let name = &function.name;
let function_name = expand_function_name(function, alias.as_ref());
let selector = function.selector();
let name = expand_function_name(function, alias.as_ref()); let selector_tokens = expand_selector(selector);
let selector = expand_selector(function.selector());
let contract_args = self.expand_contract_call_args(function)?; let contract_args = self.expand_contract_call_args(function)?;
let function_params = let function_params =
@ -448,18 +446,15 @@ impl Context {
let outputs = self.expand_outputs(function)?; let outputs = self.expand_outputs(function)?;
let result = quote! { #ethers_contract::builders::ContractCall<M, #outputs> }; let doc_str =
format!("Calls the contract's `{name}` (0x{}) function", hex::encode(selector));
let ethers_contract = ethers_contract_crate();
let doc = util::expand_doc(&format!(
"Calls the contract's `{}` (0x{}) function",
function.name,
hex::encode(function.selector())
));
Ok(quote! { Ok(quote! {
#[doc = #doc_str]
#doc pub fn #function_name(&self #function_params) -> #ethers_contract::builders::ContractCall<M, #outputs> {
pub fn #name(&self #function_params) -> #result { self.0.method_hash(#selector_tokens, #contract_args)
self.0.method_hash(#selector, #contract_args)
.expect("method not found (this should never happen)") .expect("method not found (this should never happen)")
} }
}) })
@ -470,9 +465,10 @@ impl Context {
/// ///
/// In case of overloaded functions we would follow rust's general /// In case of overloaded functions we would follow rust's general
/// convention of suffixing the function name with _with /// convention of suffixing the function name with _with
// The first function or the function with the least amount of arguments should ///
// be named as in the ABI, the following functions suffixed with _with_ + /// The first function or the function with the least amount of arguments should
// additional_params[0].name + (_and_(additional_params[1+i].name))* /// be named as in the ABI, the following functions suffixed with _with_ +
/// additional_params[0].name + (_and_(additional_params[1+i].name))*
fn get_method_aliases(&self) -> Result<BTreeMap<String, MethodAlias>> { fn get_method_aliases(&self) -> Result<BTreeMap<String, MethodAlias>> {
let mut aliases = self.method_aliases.clone(); let mut aliases = self.method_aliases.clone();

View File

@ -123,22 +123,18 @@ impl Context {
} }
}; };
let sig = if let ParamType::Tuple(ref tokens) = tuple { let sig = match tuple {
tokens.iter().map(|kind| kind.to_string()).collect::<Vec<_>>().join(",") ParamType::Tuple(ref types) if !types.is_empty() => util::abi_signature_types(types),
} else { _ => String::new(),
"".to_string()
}; };
let doc_str = format!("`{name}({sig})`");
let abi_signature = format!("{name}({sig})",);
let abi_signature_doc = util::expand_doc(&format!("`{abi_signature}`"));
// use the same derives as for events // use the same derives as for events
let derives = util::expand_derives(&self.event_derives); let derives = util::expand_derives(&self.event_derives);
let ethers_contract = ethers_contract_crate(); let ethers_contract = ethers_contract_crate();
Ok(quote! { Ok(quote! {
#abi_signature_doc #[doc = #doc_str]
#[derive(Clone, Debug, Default, Eq, PartialEq, #ethers_contract::EthAbiType, #ethers_contract::EthAbiCodec, #derives)] #[derive(Clone, Debug, Default, Eq, PartialEq, #ethers_contract::EthAbiType, #ethers_contract::EthAbiCodec, #derives)]
#struct_def #struct_def
}) })
@ -178,13 +174,7 @@ impl Context {
} }
} }
let abi_signature = format!( let abi_signature = util::abi_signature(name, &param_types);
"{}({})",
name,
param_types.iter().map(|kind| kind.to_string()).collect::<Vec<_>>().join(","),
);
let abi_signature_doc = util::expand_doc(&format!("`{abi_signature}`"));
let name = util::ident(name); let name = util::ident(name);
@ -195,7 +185,7 @@ impl Context {
let ethers_contract = ethers_contract_crate(); let ethers_contract = ethers_contract_crate();
Ok(quote! { Ok(quote! {
#abi_signature_doc #[doc = #abi_signature]
#[derive(Clone, Debug, Default, Eq, PartialEq, #ethers_contract::EthAbiType, #ethers_contract::EthAbiCodec, #derives)] #[derive(Clone, Debug, Default, Eq, PartialEq, #ethers_contract::EthAbiType, #ethers_contract::EthAbiCodec, #derives)]
pub struct #name { pub struct #name {
#( #fields ),* #( #fields ),*

View File

@ -1,7 +1,7 @@
use ethers_core::abi::{Param, ParamType}; use ethers_core::abi::{Param, ParamType};
use eyre::Result; use eyre::Result;
use inflector::Inflector; use inflector::Inflector;
use proc_macro2::{Ident, Literal, Span, TokenStream}; use proc_macro2::{Ident, Span, TokenStream};
use quote::quote; use quote::quote;
use std::path::PathBuf; use std::path::PathBuf;
use syn::{Ident as SynIdent, Path}; use syn::{Ident as SynIdent, Path};
@ -81,14 +81,6 @@ pub fn expand_input_name(index: usize, name: &str) -> TokenStream {
quote! { #name } quote! { #name }
} }
/// Expands a doc string into an attribute token stream.
pub fn expand_doc(s: &str) -> TokenStream {
let doc = Literal::string(s);
quote! {
#[doc = #doc]
}
}
pub fn expand_derives(derives: &[Path]) -> TokenStream { pub fn expand_derives(derives: &[Path]) -> TokenStream {
quote! {#(#derives),*} quote! {#(#derives),*}
} }
@ -167,13 +159,16 @@ pub fn json_files(root: impl AsRef<std::path::Path>) -> Vec<PathBuf> {
.collect() .collect()
} }
/// rust-std derives `Default` automatically only for arrays len <= 32 /// Returns whether all the given parameters can derive [`Default`].
/// ///
/// Returns whether the corresponding struct can derive `Default` /// rust-std derives `Default` automatically only for arrays len <= 32
pub fn can_derive_defaults(params: &[Param]) -> bool { pub fn can_derive_defaults<'a>(params: impl IntoIterator<Item = &'a Param>) -> bool {
params.iter().map(|param| &param.kind).all(can_derive_default) params.into_iter().map(|param| &param.kind).all(can_derive_default)
} }
/// Returns whether the given type can derive [`Default`].
///
/// rust-std derives `Default` automatically only for arrays len <= 32
pub fn can_derive_default(param: &ParamType) -> bool { pub fn can_derive_default(param: &ParamType) -> bool {
const MAX_SUPPORTED_LEN: usize = 32; const MAX_SUPPORTED_LEN: usize = 32;
match param { match param {
@ -190,6 +185,21 @@ pub fn can_derive_default(param: &ParamType) -> bool {
} }
} }
/// Returns the formatted Solidity ABI signature.
pub fn abi_signature<'a, N, T>(name: N, types: T) -> String
where
N: std::fmt::Display,
T: IntoIterator<Item = &'a ParamType>,
{
let types = abi_signature_types(types);
format!("`{name}({types})`")
}
/// Returns the Solidity stringified ABI types joined by a single comma.
pub fn abi_signature_types<'a, T: IntoIterator<Item = &'a ParamType>>(types: T) -> String {
types.into_iter().map(ToString::to_string).collect::<Vec<_>>().join(",")
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;