feat: add ethabitype support for solidity style enums (#526)
* feat: tokenize solidity like enums * test: add enum test * rustfmt
This commit is contained in:
parent
b072b05515
commit
5779a3cdaf
|
@ -1,7 +1,7 @@
|
||||||
//! Helper functions for deriving `EthAbiType`
|
//! Helper functions for deriving `EthAbiType`
|
||||||
|
|
||||||
use ethers_contract_abigen::ethers_core_crate;
|
use ethers_contract_abigen::ethers_core_crate;
|
||||||
use proc_macro2::{Ident, TokenStream};
|
use proc_macro2::{Ident, Literal, TokenStream};
|
||||||
use quote::{quote, quote_spanned};
|
use quote::{quote, quote_spanned};
|
||||||
use syn::spanned::Spanned as _;
|
use syn::spanned::Spanned as _;
|
||||||
use syn::{parse::Error, Data, DeriveInput, Fields, Variant};
|
use syn::{parse::Error, Data, DeriveInput, Fields, Variant};
|
||||||
|
@ -198,6 +198,12 @@ fn tokenize_unit_type(name: &Ident) -> TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Derive for an enum
|
||||||
|
///
|
||||||
|
/// An enum can be a [solidity enum](https://docs.soliditylang.org/en/v0.5.3/types.html#enums) or a
|
||||||
|
/// bundled set of different types.
|
||||||
|
///
|
||||||
|
/// Decoding works like untagged decoding
|
||||||
fn tokenize_enum<'a>(
|
fn tokenize_enum<'a>(
|
||||||
enum_name: &Ident,
|
enum_name: &Ident,
|
||||||
variants: impl Iterator<Item = &'a Variant> + 'a,
|
variants: impl Iterator<Item = &'a Variant> + 'a,
|
||||||
|
@ -206,15 +212,24 @@ fn tokenize_enum<'a>(
|
||||||
|
|
||||||
let mut into_tokens = TokenStream::new();
|
let mut into_tokens = TokenStream::new();
|
||||||
let mut from_tokens = TokenStream::new();
|
let mut from_tokens = TokenStream::new();
|
||||||
for variant in variants {
|
for (idx, variant) in variants.into_iter().enumerate() {
|
||||||
|
let var_ident = &variant.ident;
|
||||||
if variant.fields.len() > 1 {
|
if variant.fields.len() > 1 {
|
||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
variant.span(),
|
variant.span(),
|
||||||
"EthAbiType cannot be derived for enum variants with multiple fields",
|
"EthAbiType cannot be derived for enum variants with multiple fields",
|
||||||
));
|
));
|
||||||
|
} else if variant.fields.is_empty() {
|
||||||
|
let value = Literal::u8_unsuffixed(idx as u8);
|
||||||
|
from_tokens.extend(quote! {
|
||||||
|
if let Ok(#value) = u8::from_token(token.clone()) {
|
||||||
|
return Ok(#enum_name::#var_ident)
|
||||||
}
|
}
|
||||||
let var_ident = &variant.ident;
|
});
|
||||||
if let Some(field) = variant.fields.iter().next() {
|
into_tokens.extend(quote! {
|
||||||
|
#enum_name::#var_ident => #value.into_token(),
|
||||||
|
});
|
||||||
|
} else if let Some(field) = variant.fields.iter().next() {
|
||||||
let ty = &field.ty;
|
let ty = &field.ty;
|
||||||
from_tokens.extend(quote! {
|
from_tokens.extend(quote! {
|
||||||
if let Ok(decoded) = #ty::from_token(token.clone()) {
|
if let Ok(decoded) = #ty::from_token(token.clone()) {
|
||||||
|
|
|
@ -489,3 +489,21 @@ fn can_derive_ethcall_with_nested_structs() {
|
||||||
assert_tokenizeable::<FooCall>();
|
assert_tokenizeable::<FooCall>();
|
||||||
assert_ethcall::<FooCall>();
|
assert_ethcall::<FooCall>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_derive_for_enum() {
|
||||||
|
#[derive(Debug, Clone, PartialEq, EthAbiType)]
|
||||||
|
enum ActionChoices {
|
||||||
|
GoLeft,
|
||||||
|
GoRight,
|
||||||
|
GoStraight,
|
||||||
|
SitStill,
|
||||||
|
}
|
||||||
|
assert_tokenizeable::<ActionChoices>();
|
||||||
|
|
||||||
|
let token = ActionChoices::GoLeft.into_token();
|
||||||
|
assert_eq!(
|
||||||
|
ActionChoices::GoLeft,
|
||||||
|
ActionChoices::from_token(token).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue