#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
mod builder;
mod env;
mod parse;
mod view;
use parse::OptionsInput;
use syn::{parse_macro_input, DeriveInput};
type Result<T> = ::std::result::Result<T, syn::Error>;
#[proc_macro_derive(CosmosOptions, attributes(options, option))]
pub fn derive_cosmos_options(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
match derive_cosmos_options_impl(ast) {
Ok(tokens) => tokens.into(),
Err(e) => e.to_compile_error().into(),
}
}
fn derive_cosmos_options_impl(ast: DeriveInput) -> Result<proc_macro2::TokenStream> {
let input = OptionsInput::from_derive_input(&ast)?;
let view_tokens = view::generate_view(&input)?;
let builder_tokens = builder::generate_builder(&input)?;
let env_tokens = env::generate_from_env(&input)?;
let default_tokens = generate_default(&input)?;
let gen = quote::quote! {
#view_tokens
#builder_tokens
#[doc(hidden)]
const _: () = {
#env_tokens
#default_tokens
};
};
Ok(gen)
}
fn generate_default(input: &OptionsInput) -> Result<proc_macro2::TokenStream> {
let name = &input.name;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let fields = input.fields.iter().map(|f| {
let field_name = &f.ident;
quote::quote! { #field_name: None }
});
Ok(quote::quote! {
#[automatically_derived]
impl #impl_generics Default for #name #ty_generics #where_clause {
fn default() -> Self {
Self {
#(#fields),*
}
}
}
})
}