struct-patch-derive 0.12.3

A library that helps you implement partial updates for your structs.
Documentation
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use syn::{DeriveInput, Result};
use syn_serde::json;

pub(crate) struct Substrate {
    struct_name: Ident,
    fields: syn::Fields,
}

impl Substrate {
    /// Generate the token stream which provide expose for Substrate
    pub fn to_token_stream(&self) -> Result<TokenStream> {
        let Substrate {
            struct_name,
            fields,
        } = self;

        let mut field_idents = Vec::new();
        let mut field_tys = Vec::new();
        for field in fields.iter() {
            field_idents.push(field.ident.clone());
            field_tys.push(field.ty.clone());
        }

        let active_site = json::to_string(fields);

        Ok(quote! {
            impl struct_patch::traits::Substrate for #struct_name {
                fn expose_content() -> &'static str {
                    #active_site
                }
                fn expose() {
                    println!("cargo:rustc-env={}={}", stringify!(#struct_name), Self::expose_content());
                }
            }
            impl #struct_name {
                /// Support `decouple` of Complex with private fields, a new function generated by Substrate macro
                pub fn __substrate_new(
                    #( #field_idents: #field_tys, )*
                ) -> #struct_name {
                    #struct_name {
                        #( #field_idents, )*
                    }
                }

                /// Support `bind` of Catalyst with private fields, an unpack function generated by Substrate macro
                pub fn __substrate_unpack(
                    self
                ) -> (
                    #( #field_tys, )*
                ) {
                    (
                        #( self.#field_idents, )*
                    )
                }
            }
        })
    }
    /// Parse the substrate struct
    pub fn from_ast(DeriveInput { ident, data, .. }: syn::DeriveInput) -> Result<Substrate> {
        let fields = if let syn::Data::Struct(syn::DataStruct { fields, .. }) = data {
            fields
        } else {
            return Err(syn::Error::new(
                ident.span(),
                "Substrate derive only use for struct",
            ));
        };

        Ok(Substrate {
            struct_name: ident,
            fields,
        })
    }
}