fix(abigen): only derive default of no arrays len > 32 (#1653)
* fix(abigen): only derive default of no arrays len > 32 * impl default
This commit is contained in:
parent
13a0144aba
commit
430c56ee4a
|
@ -1,8 +1,9 @@
|
||||||
use std::collections::{btree_map::Entry, BTreeMap, HashMap};
|
use std::collections::{btree_map::Entry, BTreeMap, HashMap};
|
||||||
|
|
||||||
use super::{types, util, Context};
|
use super::{types, util, Context};
|
||||||
use crate::contract::common::{
|
use crate::{
|
||||||
expand_data_struct, expand_data_tuple, expand_param_type, expand_params,
|
contract::common::{expand_data_struct, expand_data_tuple, expand_param_type, expand_params},
|
||||||
|
util::can_derive_defaults,
|
||||||
};
|
};
|
||||||
use ethers_core::{
|
use ethers_core::{
|
||||||
abi::{Function, FunctionExt, Param, ParamType},
|
abi::{Function, FunctionExt, Param, ParamType},
|
||||||
|
@ -134,9 +135,20 @@ impl Context {
|
||||||
// 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);
|
||||||
|
|
||||||
|
// rust-std only derives default automatically for arrays len <= 32
|
||||||
|
// for large array types we skip derive(Default) <https://github.com/gakonst/ethers-rs/issues/1640>
|
||||||
|
let derive_default = if can_derive_defaults(&function.inputs) {
|
||||||
|
quote! {
|
||||||
|
#[derive(Default)]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#abi_signature_doc
|
#abi_signature_doc
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, #ethers_contract::EthCall, #ethers_contract::EthDisplay, #derives)]
|
#[derive(Clone, Debug, Eq, PartialEq, #ethers_contract::EthCall, #ethers_contract::EthDisplay, #derives)]
|
||||||
|
#derive_default
|
||||||
#[ethcall( name = #function_name, abi = #abi_signature )]
|
#[ethcall( name = #function_name, abi = #abi_signature )]
|
||||||
pub #call_type_definition
|
pub #call_type_definition
|
||||||
})
|
})
|
||||||
|
@ -175,9 +187,20 @@ impl Context {
|
||||||
// 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);
|
||||||
|
|
||||||
|
// rust-std only derives default automatically for arrays len <= 32
|
||||||
|
// for large array types we skip derive(Default) <https://github.com/gakonst/ethers-rs/issues/1640>
|
||||||
|
let derive_default = if can_derive_defaults(&function.outputs) {
|
||||||
|
quote! {
|
||||||
|
#[derive(Default)]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#abi_signature_doc
|
#abi_signature_doc
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, #ethers_contract::EthAbiType, #ethers_contract::EthAbiCodec, #derives)]
|
#[derive(Clone, Debug,Eq, PartialEq, #ethers_contract::EthAbiType, #ethers_contract::EthAbiCodec, #derives)]
|
||||||
|
#derive_default
|
||||||
pub #return_type_definition
|
pub #return_type_definition
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use ethers_core::types::Address;
|
use ethers_core::{
|
||||||
use std::path::PathBuf;
|
abi::{Param, ParamType},
|
||||||
|
types::Address,
|
||||||
|
};
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
use inflector::Inflector;
|
use inflector::Inflector;
|
||||||
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
use std::path::PathBuf;
|
||||||
use syn::{Ident as SynIdent, Path};
|
use syn::{Ident as SynIdent, Path};
|
||||||
|
|
||||||
/// Expands a identifier string into a token.
|
/// Expands a identifier string into a token.
|
||||||
|
@ -185,10 +186,42 @@ 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 the corresponding struct can derive `Default`
|
||||||
|
pub fn can_derive_defaults(params: &[Param]) -> bool {
|
||||||
|
params.iter().map(|param| ¶m.kind).all(can_derive_default)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn can_derive_default(param: &ParamType) -> bool {
|
||||||
|
const MAX_SUPPORTED_LEN: usize = 32;
|
||||||
|
match param {
|
||||||
|
ParamType::FixedBytes(len) => *len <= MAX_SUPPORTED_LEN,
|
||||||
|
ParamType::FixedArray(ty, len) => {
|
||||||
|
if *len > MAX_SUPPORTED_LEN {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
can_derive_default(ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ParamType::Tuple(params) => params.iter().all(can_derive_default),
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_detect_non_default() {
|
||||||
|
let param = ParamType::FixedArray(Box::new(ParamType::Uint(64)), 128);
|
||||||
|
assert!(!can_derive_default(¶m));
|
||||||
|
|
||||||
|
let param = ParamType::FixedArray(Box::new(ParamType::Uint(64)), 32);
|
||||||
|
assert!(can_derive_default(¶m));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_resolve_path() {
|
fn can_resolve_path() {
|
||||||
let raw = "./$ENV_VAR";
|
let raw = "./$ENV_VAR";
|
||||||
|
|
|
@ -11,10 +11,14 @@ use ethers_middleware::SignerMiddleware;
|
||||||
use ethers_providers::{MockProvider, Provider};
|
use ethers_providers::{MockProvider, Provider};
|
||||||
use ethers_signers::{LocalWallet, Signer};
|
use ethers_signers::{LocalWallet, Signer};
|
||||||
use ethers_solc::Solc;
|
use ethers_solc::Solc;
|
||||||
use std::{convert::TryFrom, sync::Arc};
|
use std::{
|
||||||
|
convert::{TryFrom, TryInto},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
fn assert_codec<T: AbiDecode + AbiEncode>() {}
|
fn assert_codec<T: AbiDecode + AbiEncode>() {}
|
||||||
fn assert_tokenizeable<T: Tokenizable>() {}
|
fn assert_tokenizeable<T: Tokenizable>() {}
|
||||||
|
fn assert_call<T: AbiEncode + AbiDecode + Default + Tokenizable>() {}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_gen_human_readable() {
|
fn can_gen_human_readable() {
|
||||||
|
@ -237,6 +241,9 @@ fn can_gen_human_readable_with_structs() {
|
||||||
assert_eq!(contract_call, decoded_enum);
|
assert_eq!(contract_call, decoded_enum);
|
||||||
assert_eq!(contract_call, call.into());
|
assert_eq!(contract_call, call.into());
|
||||||
assert_eq!(encoded_call, contract_call.encode());
|
assert_eq!(encoded_call, contract_call.encode());
|
||||||
|
|
||||||
|
assert_call::<BarCall>();
|
||||||
|
assert_call::<YeetCall>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -301,6 +308,10 @@ fn can_handle_overloaded_functions() {
|
||||||
let _contract_call = SimpleContractCalls::SetValue0(call);
|
let _contract_call = SimpleContractCalls::SetValue0(call);
|
||||||
let call = SetValue1Call("message".to_string(), "message".to_string());
|
let call = SetValue1Call("message".to_string(), "message".to_string());
|
||||||
let _contract_call = SimpleContractCalls::SetValue1(call);
|
let _contract_call = SimpleContractCalls::SetValue1(call);
|
||||||
|
|
||||||
|
assert_call::<SetValue0Call>();
|
||||||
|
assert_call::<SetValue1Call>();
|
||||||
|
assert_call::<GetValueWithOtherValueAndAddrCall>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -695,3 +706,17 @@ fn gen_complex_function() {
|
||||||
fn can_gen_large_tuple_types() {
|
fn can_gen_large_tuple_types() {
|
||||||
abigen!(LargeTuple, "./tests/solidity-contracts/large_tuple.json");
|
abigen!(LargeTuple, "./tests/solidity-contracts/large_tuple.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_gen_large_tuple_array() {
|
||||||
|
abigen!(LargeTuple, "./tests/solidity-contracts/large-array.json");
|
||||||
|
|
||||||
|
impl Default for CallWithLongArrayCall {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { long_array: [0; 128] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _call = CallWithLongArrayCall::default();
|
||||||
|
assert_call::<CallWithLongArrayCall>();
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint64[128]",
|
||||||
|
"name": "longArray",
|
||||||
|
"type": "uint64[128]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "callWithLongArray",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]
|
Loading…
Reference in New Issue