From fd02bbc418b0e7915f60a43457589e0430b6b6ef Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Tue, 31 Jan 2023 06:28:57 +0100 Subject: [PATCH] refactor(abigen): inline docs (#2090) * refactor: abigen docs * chore: doc * refactor: final doc * mergings * fix: unremove Default --- .../src/contract/common.rs | 4 +- .../src/contract/errors.rs | 7 ++- .../src/contract/events.rs | 17 +++--- .../src/contract/methods.rs | 54 +++++++++---------- .../src/contract/structs.rs | 24 +++------ .../ethers-contract-abigen/src/util.rs | 36 ++++++++----- 6 files changed, 69 insertions(+), 73 deletions(-) diff --git a/ethers-contract/ethers-contract-abigen/src/contract/common.rs b/ethers-contract/ethers-contract-abigen/src/contract/common.rs index afea146a..c48e306d 100644 --- a/ethers-contract/ethers-contract-abigen/src/contract/common.rs +++ b/ethers-contract/ethers-contract-abigen/src/contract/common.rs @@ -62,7 +62,7 @@ where } 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_providers = ethers_providers_crate(); @@ -73,7 +73,7 @@ pub(crate) fn imports(name: &str) -> TokenStream { #![allow(dead_code)] #![allow(clippy::type_complexity)] #![allow(unused_imports)] - #doc + #![doc = #doc_str] use std::sync::Arc; use #ethers_core::{ diff --git a/ethers-contract/ethers-contract-abigen/src/contract/errors.rs b/ethers-contract/ethers-contract-abigen/src/contract/errors.rs index e8c3d3fb..4462386e 100644 --- a/ethers-contract/ethers-contract-abigen/src/contract/errors.rs +++ b/ethers-contract/ethers-contract-abigen/src/contract/errors.rs @@ -59,13 +59,12 @@ impl Context { expand_data_struct(&error_name, &fields) }; - let doc = format!( + let doc_str = format!( "Custom Error type `{}` with signature `{}` and selector `0x{}`", error.name, abi_signature, hex::encode(&error.selector()[..]) ); - let abi_signature_doc = util::expand_doc(&doc); let ethers_contract = ethers_contract_crate(); // use the same derives as for events let derives = util::expand_derives(&self.event_derives); @@ -73,9 +72,9 @@ impl Context { let error_name = &error.name; Ok(quote! { - #abi_signature_doc + #[doc = #doc_str] #[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 }) } diff --git a/ethers-contract/ethers-contract-abigen/src/contract/events.rs b/ethers-contract/ethers-contract-abigen/src/contract/events.rs index bae8ca66..f0e1d778 100644 --- a/ethers-contract/ethers-contract-abigen/src/contract/events.rs +++ b/ethers-contract/ethers-contract-abigen/src/contract/events.rs @@ -217,24 +217,25 @@ impl Context { /// Expands into a single method for contracting an event stream. 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 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())) } else { 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 - // function names + let doc_str = format!("Gets the contract's `{name}` event"); - 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! { - #doc - pub fn #name(&self) -> #ethers_contract::builders::Event { + #[doc = #doc_str] + pub fn #function_name(&self) -> #ethers_contract::builders::Event { self.0.event() } } diff --git a/ethers-contract/ethers-contract-abigen/src/contract/methods.rs b/ethers-contract/ethers-contract-abigen/src/contract/methods.rs index e2d048ad..b4d1ed21 100644 --- a/ethers-contract/ethers-contract-abigen/src/contract/methods.rs +++ b/ethers-contract/ethers-contract-abigen/src/contract/methods.rs @@ -124,13 +124,11 @@ impl Context { }; let function_name = &function.name; let abi_signature = function.abi_signature(); - let doc = format!( - "Container type for all input parameters for the `{}` function with signature `{}` and selector `0x{}`", - function.name, - abi_signature, + let doc_str = format!( + "Container type for all input parameters for the `{function_name}` function with signature `{abi_signature}` and selector `0x{}`", hex::encode(&function.selector()[..]) ); - let abi_signature_doc = util::expand_doc(&doc); + let ethers_contract = ethers_contract_crate(); // use the same derives as for events let derives = util::expand_derives(&self.event_derives); @@ -146,7 +144,7 @@ impl Context { }; Ok(quote! { - #abi_signature_doc + #[doc = #doc_str] #[derive(Clone, Debug, Eq, PartialEq, #ethers_contract::EthCall, #ethers_contract::EthDisplay, #derives)] #derive_default #[ethcall( name = #function_name, abi = #abi_signature )] @@ -160,6 +158,7 @@ impl Context { function: &Function, alias: Option<&MethodAlias>, ) -> Result { + let name = &function.name; let struct_name = expand_return_struct_name(function, alias); let fields = self.expand_output_params(function)?; // no point in having structs when there is no data returned @@ -176,13 +175,11 @@ impl Context { expand_data_struct(&struct_name, &fields) }; let abi_signature = function.abi_signature(); - let doc = format!( - "Container type for all return fields from the `{}` function with signature `{}` and selector `0x{}`", - function.name, - abi_signature, + let doc_str = format!( + "Container type for all return fields from the `{name}` function with signature `{abi_signature}` and selector `0x{}`", hex::encode(&function.selector()[..]) ); - let abi_signature_doc = util::expand_doc(&doc); + let ethers_contract = ethers_contract_crate(); // use the same derives as for events let derives = util::expand_derives(&self.event_derives); @@ -198,9 +195,9 @@ impl Context { }; Ok(quote! { - #abi_signature_doc + #[doc = #doc_str] #[derive(Clone, Debug,Eq, PartialEq, #ethers_contract::EthAbiType, #ethers_contract::EthAbiCodec, #derives)] - #derive_default + #derive_default pub #return_type_definition }) } @@ -436,10 +433,11 @@ impl Context { function: &Function, alias: Option, ) -> Result { - 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 = expand_selector(function.selector()); + let selector_tokens = expand_selector(selector); let contract_args = self.expand_contract_call_args(function)?; let function_params = @@ -448,18 +446,15 @@ impl Context { let outputs = self.expand_outputs(function)?; - let result = quote! { #ethers_contract::builders::ContractCall }; + 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! { - - #doc - pub fn #name(&self #function_params) -> #result { - self.0.method_hash(#selector, #contract_args) + #[doc = #doc_str] + pub fn #function_name(&self #function_params) -> #ethers_contract::builders::ContractCall { + self.0.method_hash(#selector_tokens, #contract_args) .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 /// 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_ + - // additional_params[0].name + (_and_(additional_params[1+i].name))* + /// + /// 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_ + + /// additional_params[0].name + (_and_(additional_params[1+i].name))* fn get_method_aliases(&self) -> Result> { let mut aliases = self.method_aliases.clone(); diff --git a/ethers-contract/ethers-contract-abigen/src/contract/structs.rs b/ethers-contract/ethers-contract-abigen/src/contract/structs.rs index 661e9e37..4002e7b6 100644 --- a/ethers-contract/ethers-contract-abigen/src/contract/structs.rs +++ b/ethers-contract/ethers-contract-abigen/src/contract/structs.rs @@ -123,22 +123,18 @@ impl Context { } }; - let sig = if let ParamType::Tuple(ref tokens) = tuple { - tokens.iter().map(|kind| kind.to_string()).collect::>().join(",") - } else { - "".to_string() + let sig = match tuple { + ParamType::Tuple(ref types) if !types.is_empty() => util::abi_signature_types(types), + _ => String::new(), }; - - let abi_signature = format!("{name}({sig})",); - - let abi_signature_doc = util::expand_doc(&format!("`{abi_signature}`")); + let doc_str = format!("`{name}({sig})`"); // use the same derives as for events let derives = util::expand_derives(&self.event_derives); let ethers_contract = ethers_contract_crate(); Ok(quote! { - #abi_signature_doc + #[doc = #doc_str] #[derive(Clone, Debug, Default, Eq, PartialEq, #ethers_contract::EthAbiType, #ethers_contract::EthAbiCodec, #derives)] #struct_def }) @@ -178,13 +174,7 @@ impl Context { } } - let abi_signature = format!( - "{}({})", - name, - param_types.iter().map(|kind| kind.to_string()).collect::>().join(","), - ); - - let abi_signature_doc = util::expand_doc(&format!("`{abi_signature}`")); + let abi_signature = util::abi_signature(name, ¶m_types); let name = util::ident(name); @@ -195,7 +185,7 @@ impl Context { let ethers_contract = ethers_contract_crate(); Ok(quote! { - #abi_signature_doc + #[doc = #abi_signature] #[derive(Clone, Debug, Default, Eq, PartialEq, #ethers_contract::EthAbiType, #ethers_contract::EthAbiCodec, #derives)] pub struct #name { #( #fields ),* diff --git a/ethers-contract/ethers-contract-abigen/src/util.rs b/ethers-contract/ethers-contract-abigen/src/util.rs index 92c4c4dc..48f9c6d5 100644 --- a/ethers-contract/ethers-contract-abigen/src/util.rs +++ b/ethers-contract/ethers-contract-abigen/src/util.rs @@ -1,7 +1,7 @@ use ethers_core::abi::{Param, ParamType}; use eyre::Result; use inflector::Inflector; -use proc_macro2::{Ident, Literal, Span, TokenStream}; +use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; use std::path::PathBuf; use syn::{Ident as SynIdent, Path}; @@ -81,14 +81,6 @@ pub fn expand_input_name(index: usize, name: &str) -> TokenStream { 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 { quote! {#(#derives),*} } @@ -167,13 +159,16 @@ pub fn json_files(root: impl AsRef) -> Vec { .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` -pub fn can_derive_defaults(params: &[Param]) -> bool { - params.iter().map(|param| ¶m.kind).all(can_derive_default) +/// rust-std derives `Default` automatically only for arrays len <= 32 +pub fn can_derive_defaults<'a>(params: impl IntoIterator) -> bool { + params.into_iter().map(|param| ¶m.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 { const MAX_SUPPORTED_LEN: usize = 32; 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, +{ + 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>(types: T) -> String { + types.into_iter().map(ToString::to_string).collect::>().join(",") +} + #[cfg(test)] mod tests { use super::*;