mod util;
extern crate proc_macro;
use crate::util::path::PathAttr;
use crate::util::stateful::expand_stateful;
use proc_macro::TokenStream as RawStream;
use proc_macro2::Ident;
use quote::quote;
use rand::Rng;
use std::env;
use syn::spanned::Spanned;
use syn::DeriveInput;
#[proc_macro_derive(InitAppState)]
pub fn init_app_state(input: RawStream) -> RawStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let name = input.ident;
#[cfg(feature = "log")]
let log = quote! {
log::debug!("Initializing app state {}", std::any::type_name::<#name>());
};
#[cfg(not(feature = "log"))]
let log = quote! {};
let gen = quote! {
impl InitAppState for #name {
fn init_app_state(self) {
#log
AppState::init(self);
}
}
};
gen.into()
}
#[proc_macro_derive(InitMutAppState)]
pub fn init_mut_app_state(input: RawStream) -> RawStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let name = input.ident;
#[cfg(feature = "log")]
let log = quote! {
log::debug!("Initializing mutable app state {}", std::any::type_name::<#name>());
};
#[cfg(not(feature = "log"))]
let log = quote! {};
let gen = quote! {
impl InitMutAppState for #name {
fn init_mut_app_state(self) {
#log
MutAppState::init(self);
}
}
};
gen.into()
}
#[proc_macro_attribute]
pub fn stateful(args: RawStream, input: RawStream) -> RawStream {
let args = syn::parse_macro_input!(args as PathAttr);
match expand_stateful(input.into(), args) {
Ok(stream) => {
if env::var("DEBUG_GENERATED_CODE").is_ok() {
println!("{}", stream.to_string());
}
stream.into()
}
Err(err) => err.to_compile_error().into(),
}
}
fn get_default_state_values(input: DeriveInput) -> syn::Result<(Ident, Ident)> {
let name = input.ident.clone();
let mut rng = rand::thread_rng();
let id = Ident::new(
&format!("__init_default_state_{}", rng.gen::<u32>()),
proc_macro2::Span::call_site(),
);
if let syn::Item::Struct(_) = input.clone().into() {
Ok((name, id))
} else {
Err(syn::Error::new(
input.span(),
"'init_default_state' can only be used on structs",
))
}
}
#[proc_macro_attribute]
pub fn init_default_state(_: RawStream, input: RawStream) -> RawStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let (name, id) = match get_default_state_values(input.clone()) {
Ok(res) => res,
Err(err) => return err.to_compile_error().into(),
};
#[cfg(feature = "log")]
let log = quote! {
log::debug!("Initializing app state {} before main", std::any::type_name::<#name>());
};
#[cfg(not(feature = "log"))]
let log = quote! {};
(quote! {
#input
#[ctor::ctor]
fn #id() {
#log
AppState::init(#name::default());
}
})
.into()
}
#[proc_macro_attribute]
pub fn init_default_mut_state(_: RawStream, input: RawStream) -> RawStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
let (name, id) = match get_default_state_values(input.clone()) {
Ok(res) => res,
Err(err) => return err.to_compile_error().into(),
};
#[cfg(feature = "log")]
let log = quote! {
log::debug!("Initializing mutable app state {} before main", std::any::type_name::<#name>());
};
#[cfg(not(feature = "log"))]
let log = quote! {};
(quote! {
#input
#[ctor::ctor]
fn #id() {
#log
MutAppState::init(#name::default());
}
})
.into()
}