Add new CompareFields trait and derive

This commit is contained in:
Paul Hauner 2019-05-22 17:22:12 +10:00
parent 30d582f40d
commit 7a99654f89
No known key found for this signature in database
GPG Key ID: 5E2CFF9B75FA63DF
8 changed files with 144 additions and 2 deletions

View File

@ -7,6 +7,8 @@ members = [
"eth2/utils/bls",
"eth2/utils/boolean-bitfield",
"eth2/utils/cached_tree_hash",
"eth2/utils/compare_fields",
"eth2/utils/compare_fields_derive",
"eth2/utils/fixed_len_vec",
"eth2/utils/hashing",
"eth2/utils/honey-badger-split",

View File

@ -8,6 +8,8 @@ edition = "2018"
bls = { path = "../utils/bls" }
boolean-bitfield = { path = "../utils/boolean-bitfield" }
cached_tree_hash = { path = "../utils/cached_tree_hash" }
compare_fields = { path = "../utils/compare_fields" }
compare_fields_derive = { path = "../utils/compare_fields_derive" }
dirs = "1.0"
derivative = "1.0"
ethereum-types = "0.5"

View File

@ -3,11 +3,11 @@ use self::exit_cache::ExitCache;
use crate::test_utils::TestRandom;
use crate::*;
use cached_tree_hash::{Error as TreeHashCacheError, TreeHashCache};
use compare_fields_derive::CompareFields;
use fixed_len_vec::{typenum::Unsigned, FixedLenVec};
use hashing::hash;
use int_to_bytes::{int_to_bytes32, int_to_bytes8};
use pubkey_cache::PubkeyCache;
use fixed_len_vec::{typenum::Unsigned, FixedLenVec};
use serde_derive::{Deserialize, Serialize};
use ssz::ssz_encode;
use ssz_derive::{Decode, Encode};
@ -74,6 +74,7 @@ pub enum Error {
Decode,
TreeHash,
CachedTreeHash,
CompareFields,
)]
pub struct BeaconState<T>
where

View File

@ -0,0 +1,10 @@
[package]
name = "compare_fields"
version = "0.1.0"
authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"
[dev-dependencies]
compare_fields_derive = { path = "../compare_fields_derive" }
[dependencies]

View File

@ -0,0 +1,11 @@
#[derive(Debug, PartialEq, Clone)]
pub struct FieldComparison {
pub equal: bool,
pub field_name: String,
pub a: String,
pub b: String,
}
pub trait CompareFields {
fn compare_fields(&self, b: &Self) -> Vec<FieldComparison>;
}

View File

@ -0,0 +1,46 @@
use compare_fields::{CompareFields, FieldComparison};
use compare_fields_derive::CompareFields;
#[derive(Clone, Debug, CompareFields)]
pub struct Simple {
a: u64,
b: u16,
c: Vec<u8>,
}
#[test]
fn compare() {
let foo = Simple {
a: 42,
b: 12,
c: vec![1, 2],
};
let mut bar = foo.clone();
let comparisons = foo.compare_fields(&bar);
assert!(!comparisons.iter().any(|c| c.equal == false));
assert_eq!(
comparisons[0],
FieldComparison {
equal: true,
field_name: "a".to_string(),
a: "42".to_string(),
b: "42".to_string(),
}
);
bar.a = 30;
assert_eq!(
foo.compare_fields(&bar)[0],
FieldComparison {
equal: false,
field_name: "a".to_string(),
a: "42".to_string(),
b: "30".to_string(),
}
);
}

View File

@ -0,0 +1,12 @@
[package]
name = "compare_fields_derive"
version = "0.1.0"
authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"
[lib]
proc-macro = true
[dependencies]
syn = "0.15"
quote = "0.6"

View File

@ -0,0 +1,58 @@
#![recursion_limit = "256"]
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(CompareFields)]
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 idents_a = vec![];
let mut field_names = vec![];
for field in struct_data.fields.iter() {
let ident = match &field.ident {
Some(ref ident) => ident,
_ => panic!("compare_fields_derive only supports named struct fields."),
};
field_names.push(format!("{:}", ident));
idents_a.push(ident);
}
let idents_b = idents_a.clone();
let idents_c = idents_a.clone();
let idents_d = idents_a.clone();
let output = quote! {
impl #impl_generics compare_fields::CompareFields for #name #ty_generics #where_clause {
fn compare_fields(&self, b: &Self) -> Vec<compare_fields::FieldComparison> {
let mut comparisons = vec![];
#(
comparisons.push(
compare_fields::FieldComparison {
equal: self.#idents_a == b.#idents_b,
field_name: #field_names.to_string(),
a: format!("{:?}", self.#idents_c),
b: format!("{:?}", b.#idents_d),
}
);
)*
comparisons
}
}
};
output.into()
}