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 {
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 {
pub fn __substrate_new(
#( #field_idents: #field_tys, )*
) -> #struct_name {
#struct_name {
#( #field_idents, )*
}
}
pub fn __substrate_unpack(
self
) -> (
#( #field_tys, )*
) {
(
#( self.#field_idents, )*
)
}
}
})
}
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,
})
}
}