2021-10-16 13:42:17 +00:00
|
|
|
//! Helper functions for deriving `Display`
|
|
|
|
|
|
|
|
use proc_macro2::TokenStream;
|
2021-10-16 16:45:42 +00:00
|
|
|
use quote::quote;
|
2021-10-29 12:29:35 +00:00
|
|
|
use syn::{parse::Error, spanned::Spanned as _, Data, DeriveInput, Fields, Index};
|
2021-10-16 13:42:17 +00:00
|
|
|
|
2021-11-05 13:00:01 +00:00
|
|
|
use ethers_core::{abi::ParamType, macros::ethers_core_crate};
|
2021-10-16 13:42:17 +00:00
|
|
|
|
|
|
|
use crate::utils;
|
|
|
|
|
|
|
|
/// Derive `fmt::Display` for the given type
|
|
|
|
pub(crate) fn derive_eth_display_impl(input: DeriveInput) -> Result<TokenStream, Error> {
|
|
|
|
let fields: Vec<_> = match input.data {
|
|
|
|
Data::Struct(ref data) => match data.fields {
|
|
|
|
Fields::Named(ref fields) => fields.named.iter().collect(),
|
|
|
|
Fields::Unnamed(ref fields) => fields.unnamed.iter().collect(),
|
|
|
|
Fields::Unit => {
|
|
|
|
vec![]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Data::Enum(_) => {
|
2021-10-29 12:29:35 +00:00
|
|
|
return Err(Error::new(input.span(), "Enum types are not supported by EthDisplay"))
|
2021-10-16 13:42:17 +00:00
|
|
|
}
|
|
|
|
Data::Union(_) => {
|
2021-10-29 12:29:35 +00:00
|
|
|
return Err(Error::new(input.span(), "Union types are not supported by EthDisplay"))
|
2021-10-16 13:42:17 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
let core_crate = ethers_core_crate();
|
|
|
|
let hex_encode = quote! {#core_crate::utils::hex::encode};
|
|
|
|
let mut fmts = TokenStream::new();
|
|
|
|
for (idx, field) in fields.iter().enumerate() {
|
2021-10-29 12:29:35 +00:00
|
|
|
let ident = field.ident.clone().map(|id| quote! {#id}).unwrap_or_else(|| {
|
|
|
|
let idx = Index::from(idx);
|
|
|
|
quote! {#idx}
|
|
|
|
});
|
2021-10-16 13:42:17 +00:00
|
|
|
let tokens = if let Ok(param) = utils::find_parameter_type(&field.ty) {
|
|
|
|
match param {
|
|
|
|
ParamType::Address | ParamType::Uint(_) | ParamType::Int(_) => {
|
|
|
|
quote! {
|
|
|
|
write!(f, "{:?}", self.#ident)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ParamType::Bytes => {
|
|
|
|
quote! {
|
|
|
|
write!(f, "0x{}", #hex_encode(self.#ident))?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ParamType::Bool | ParamType::String => {
|
|
|
|
quote! {
|
|
|
|
self.#ident.fmt(f)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ParamType::Tuple(_) => {
|
|
|
|
quote! {
|
|
|
|
write!(f, "{:?}", &self.#ident)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ParamType::Array(ty) | ParamType::FixedArray(ty, _) => {
|
|
|
|
if *ty == ParamType::Uint(8) {
|
|
|
|
// `u8`
|
|
|
|
quote! {
|
|
|
|
write!(f, "0x{}", #hex_encode(&self.#ident[..]))?;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// format as array with `[arr[0].display, arr[1].display,...]`
|
|
|
|
quote! {
|
|
|
|
write!(f, "[")?;
|
|
|
|
for (idx, val) in self.#ident.iter().enumerate() {
|
2021-10-24 14:02:06 +00:00
|
|
|
write!(f, "{:?}", val)?;
|
2021-10-16 13:42:17 +00:00
|
|
|
if idx < self.#ident.len() - 1 {
|
|
|
|
write!(f, ", ")?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
write!(f, "]")?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ParamType::FixedBytes(_) => {
|
|
|
|
quote! {
|
|
|
|
write!(f, "0x{}", #hex_encode(&self.#ident))?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// could not detect the parameter type and rely on using debug fmt
|
|
|
|
quote! {
|
|
|
|
write!(f, "{:?}", &self.#ident)?;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
fmts.extend(tokens);
|
|
|
|
if idx < fields.len() - 1 {
|
|
|
|
fmts.extend(quote! { write!(f, ", ")?;});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let name = &input.ident;
|
|
|
|
Ok(quote! {
|
|
|
|
impl ::std::fmt::Display for #name {
|
|
|
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
|
|
|
#fmts
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|