structural-typing-macros 0.1.2

Procedural macros for structural-typing crate
Documentation
use proc_macro2::TokenStream;
use quote::quote;

use crate::parsing::StructInfo;

pub fn generate(info: &StructInfo) -> TokenStream {
    let struct_name = &info.name;
    let struct_vis = &info.vis;
    let module_name = &info.module_name;
    let other_attrs = &info.other_attrs;

    let has_serialize = info.derives.iter().any(|d| d == "Serialize");
    let has_deserialize = info.derives.iter().any(|d| d == "Deserialize");
    let has_serde = has_serialize || has_deserialize;

    let field_defs: Vec<_> = info.fields.iter().map(|field| {
        let field_name = &field.name;
        let field_ty = &field.ty;
        let field_vis = &field.vis;

        let serde_attr = if has_serde {
            quote! { #[serde(skip_serializing_if = "::structural_typing::access::is_absent")] }
        } else {
            quote! {}
        };

        quote! {
            #serde_attr
            #field_vis #field_name: <F::#field_name as ::structural_typing::presence::Presence>::Output<#field_ty>
        }
    }).collect();

    let derive_bounds: Vec<_> = info
        .fields
        .iter()
        .map(|field| {
            let field_name = &field.name;
            let field_ty = &field.ty;
            quote! {
                <F::#field_name as ::structural_typing::presence::Presence>::Output<#field_ty>
            }
        })
        .collect();

    let derives = &info.derives;
    let derive_clause = if derives.is_empty() {
        quote! {}
    } else {
        quote! {
            #[::derive_where::derive_where(#(#derives),*; #(#derive_bounds),*)]
        }
    };

    quote! {
        #derive_clause
        #(#other_attrs)*
        #struct_vis struct #struct_name<F: #module_name::Fields = #module_name::with::all::Absent> {
            #(#field_defs),*
        }
    }
}