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 super::{types, util, Context};
|
||||
use crate::contract::common::{
|
||||
expand_data_struct, expand_data_tuple, expand_param_type, expand_params,
|
||||
use crate::{
|
||||
contract::common::{expand_data_struct, expand_data_tuple, expand_param_type, expand_params},
|
||||
util::can_derive_defaults,
|
||||
};
|
||||
use ethers_core::{
|
||||
abi::{Function, FunctionExt, Param, ParamType},
|
||||
|
@ -134,9 +135,20 @@ impl Context {
|
|||
// use the same derives as for events
|
||||
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! {
|
||||
#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 )]
|
||||
pub #call_type_definition
|
||||
})
|
||||
|
@ -175,9 +187,20 @@ impl Context {
|
|||
// use the same derives as for events
|
||||
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! {
|
||||
#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
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use ethers_core::types::Address;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use ethers_core::{
|
||||
abi::{Param, ParamType},
|
||||
types::Address,
|
||||
};
|
||||
use eyre::Result;
|
||||
use inflector::Inflector;
|
||||
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
||||
use quote::quote;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use syn::{Ident as SynIdent, Path};
|
||||
|
||||
/// Expands a identifier string into a token.
|
||||
|
@ -185,10 +186,42 @@ pub fn json_files(root: impl AsRef<std::path::Path>) -> Vec<PathBuf> {
|
|||
.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)]
|
||||
mod tests {
|
||||
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]
|
||||
fn can_resolve_path() {
|
||||
let raw = "./$ENV_VAR";
|
||||
|
|
|
@ -11,10 +11,14 @@ use ethers_middleware::SignerMiddleware;
|
|||
use ethers_providers::{MockProvider, Provider};
|
||||
use ethers_signers::{LocalWallet, Signer};
|
||||
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_tokenizeable<T: Tokenizable>() {}
|
||||
fn assert_call<T: AbiEncode + AbiDecode + Default + Tokenizable>() {}
|
||||
|
||||
#[test]
|
||||
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, call.into());
|
||||
assert_eq!(encoded_call, contract_call.encode());
|
||||
|
||||
assert_call::<BarCall>();
|
||||
assert_call::<YeetCall>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -301,6 +308,10 @@ fn can_handle_overloaded_functions() {
|
|||
let _contract_call = SimpleContractCalls::SetValue0(call);
|
||||
let call = SetValue1Call("message".to_string(), "message".to_string());
|
||||
let _contract_call = SimpleContractCalls::SetValue1(call);
|
||||
|
||||
assert_call::<SetValue0Call>();
|
||||
assert_call::<SetValue1Call>();
|
||||
assert_call::<GetValueWithOtherValueAndAddrCall>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -695,3 +706,17 @@ fn gen_complex_function() {
|
|||
fn can_gen_large_tuple_types() {
|
||||
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