0866b739d0
## Proposed Changes Clippy 1.67.0 put us on blast for the size of some of our errors, most of them written by me ( 👀 ). This PR shrinks the size of `BeaconChainError` by dropping some extraneous info and boxing an inner error which should only occur infrequently anyway. For the `AttestationSlashInfo` and `BlockSlashInfo` I opted to ignore the lint as they are always used in a `Result<A, Info>` where `A` is a similar size. This means they don't bloat the size of the `Result`, so it's a bit annoying for Clippy to report this as an issue. I also chose to ignore `clippy::uninlined-format-args` because I think the benefit-to-churn ratio is too low. E.g. sometimes we have long identifiers in `format!` args and IMO the non-inlined form is easier to read: ```rust // I prefer this... format!( "{} did {} to {}", REALLY_LONG_CONSTANT_NAME, ANOTHER_REALLY_LONG_CONSTANT_NAME, regular_long_identifier_name ); // To this format!("{REALLY_LONG_CONSTANT_NAME} did {ANOTHER_REALLY_LONG_CONSTANT_NAME} to {regular_long_identifier_name}"); ``` I tried generating an automatic diff with `cargo clippy --fix` but it came out at: ``` 250 files changed, 1209 insertions(+), 1469 deletions(-) ``` Which seems like a bad idea when we'd have to back-merge it to `capella` and `eip4844` 😱
76 lines
2.1 KiB
Rust
76 lines
2.1 KiB
Rust
#![recursion_limit = "256"]
|
|
extern crate proc_macro;
|
|
|
|
use proc_macro::TokenStream;
|
|
use quote::quote;
|
|
use syn::{parse_macro_input, DeriveInput};
|
|
|
|
fn is_slice(field: &syn::Field) -> bool {
|
|
field.attrs.iter().any(|attr| {
|
|
attr.path.is_ident("compare_fields")
|
|
&& attr.tokens.to_string().replace(' ', "") == "(as_slice)"
|
|
})
|
|
}
|
|
|
|
#[proc_macro_derive(CompareFields, attributes(compare_fields))]
|
|
pub fn compare_fields_derive(input: TokenStream) -> TokenStream {
|
|
let item = parse_macro_input!(input as DeriveInput);
|
|
|
|
let name = &item.ident;
|
|
let (impl_generics, ty_generics, where_clause) = &item.generics.split_for_impl();
|
|
|
|
let struct_data = match &item.data {
|
|
syn::Data::Struct(s) => s,
|
|
_ => panic!("compare_fields_derive only supports structs."),
|
|
};
|
|
|
|
let mut quotes = vec![];
|
|
|
|
for field in struct_data.fields.iter() {
|
|
let ident_a = match &field.ident {
|
|
Some(ref ident) => ident,
|
|
_ => panic!("compare_fields_derive only supports named struct fields."),
|
|
};
|
|
|
|
let field_name = ident_a.to_string();
|
|
let ident_b = ident_a.clone();
|
|
|
|
let quote = if is_slice(field) {
|
|
quote! {
|
|
comparisons.push(compare_fields::Comparison::from_slice(
|
|
#field_name.to_string(),
|
|
&self.#ident_a,
|
|
&b.#ident_b)
|
|
);
|
|
}
|
|
} else {
|
|
quote! {
|
|
comparisons.push(
|
|
compare_fields::Comparison::child(
|
|
#field_name.to_string(),
|
|
&self.#ident_a,
|
|
&b.#ident_b
|
|
)
|
|
);
|
|
}
|
|
};
|
|
|
|
quotes.push(quote);
|
|
}
|
|
|
|
let output = quote! {
|
|
impl #impl_generics compare_fields::CompareFields for #name #ty_generics #where_clause {
|
|
fn compare_fields(&self, b: &Self) -> Vec<compare_fields::Comparison> {
|
|
let mut comparisons = vec![];
|
|
|
|
#(
|
|
#quotes
|
|
)*
|
|
|
|
comparisons
|
|
}
|
|
}
|
|
};
|
|
output.into()
|
|
}
|