Skip to content

Instantly share code, notes, and snippets.

@tylerreisinger
Created November 23, 2018 19:52
Show Gist options
  • Save tylerreisinger/886e56379beffabddaff7bad6a232f06 to your computer and use it in GitHub Desktop.
Save tylerreisinger/886e56379beffabddaff7bad6a232f06 to your computer and use it in GitHub Desktop.
#[macro_use]
extern crate syn;
#[macro_use]
extern crate quote;
extern crate approx;
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_derive(AbsDiffEq)]
pub fn derive_relative_eq(tokens: TokenStream) -> TokenStream {
let input = parse_macro_input!(tokens as syn::DeriveInput);
let generic_params = &input.generics;
let where_clause = &generic_params.where_clause;
let ident = &input.ident;
if let syn::Data::Struct(ref obj) = input.data {
let fields = &obj.fields;
let epsilon_ty = get_epsilon_type(fields.iter());
let mut statements = syn::punctuated::Punctuated::<_, Token![&&]>::new();
for field in fields {
let ident = field.ident.as_ref().unwrap();
let field_ty = &field.ty;
let field_statement: syn::Expr = parse_quote! {
approx::AbsDiffEq::abs_diff_eq(&self.#ident, &other.#ident, epsilon.clone() as <#field_ty as approx::AbsDiffEq>::Epsilon)
};
statements.push(field_statement);
}
let out = quote! {
#[automatically_derived]
#[allow(unused_qualifications)]
impl<#generic_params> approx::AbsDiffEq for #ident
#where_clause
{
type Epsilon = <#epsilon_ty as approx::AbsDiffEq>::Epsilon;
#[inline]
fn default_epsilon() -> Self::Epsilon {
<#epsilon_ty as approx::AbsDiffEq>::default_epsilon()
}
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
#statements
}
}
};
out.into()
} else {
let out = quote! {};
out.into()
}
}
fn get_epsilon_type(fields: syn::punctuated::Iter<syn::Field>) -> syn::Type {
let f32_ty: syn::Type = parse_quote! {f32};
let f64_ty: syn::Type = parse_quote! {f64};
let mut out_type: syn::Type = f32_ty.clone();
for field in fields {
let ty = &field.ty;
if *ty == f64_ty && out_type == f32_ty {
out_type = ty.clone();
}
}
out_type
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment