#![doc = include_str!("../README.md")]
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields};
#[proc_macro_derive(Comparable)]
pub fn comparable_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
let methods = match &input.data {
Data::Struct(data_struct) => {
match &data_struct.fields {
Fields::Named(fields) => {
let field_methods = fields.named.iter().map(|field| {
let field_name = field.ident.as_ref().expect("Field should have a name");
let field_type = &field.ty;
let method_name = syn::Ident::new(
&format!("{}_differs_from", field_name),
field_name.span()
);
let method_name_ref = syn::Ident::new(
&format!("{}_differs_from_ref", field_name),
field_name.span()
);
let field_doc = format!("Vérifie si le champ `{}` diffère de la valeur donnée / Check if field `{}` differs from the given value", field_name, field_name);
let field_ref_doc = format!("Vérifie si le champ `{}` diffère de la référence donnée / Check if field `{}` differs from the given reference", field_name, field_name);
quote! {
#[doc = #field_doc]
pub fn #method_name(&self, other: #field_type) -> bool {
Self::compare_values(&self.#field_name, &other)
}
#[doc = #field_ref_doc]
pub fn #method_name_ref(&self, other: &#field_type) -> bool {
Self::compare_values(&self.#field_name, other)
}
}
});
let differs_from_checks = fields.named.iter().map(|field| {
let field_name = field.ident.as_ref().expect("Field should have a name");
quote! {
if Self::compare_values(&self.#field_name, &other.#field_name) {
return true;
}
}
});
quote! {
#(#field_methods)*
pub fn differs_from(&self, other: &Self) -> bool {
#(#differs_from_checks)*
false
}
fn compare_values<T: PartialEq>(a: &T, b: &T) -> bool {
a != b
}
}
}
Fields::Unnamed(_) => {
quote! {
compile_error!("Comparable ne peut être dérivé que pour les structures avec des champs nommés / Comparable can only be derived for structs with named fields");
}
}
Fields::Unit => {
quote! {
compile_error!("Comparable ne peut être dérivé que pour les structures avec des champs / Comparable can only be derived for structs with fields");
}
}
}
}
Data::Enum(_) => {
quote! {
compile_error!("Comparable ne peut être dérivé que pour les structures, pas les énumérations / Comparable can only be derived for structs, not enums");
}
}
Data::Union(_) => {
quote! {
compile_error!("Comparable ne peut être dérivé que pour les structures, pas les unions / Comparable can only be derived for structs, not unions");
}
}
};
let expanded = quote! {
impl #name {
#methods
}
};
TokenStream::from(expanded)
}