mod derive_static;
mod derive_trait;
mod facade_fn;
mod impl_fn;
mod lock;
mod singleton_fns;
use convert_case::Case;
use convert_case::Casing;
use darling::FromDeriveInput;
use proc_macro2::Ident;
use proc_macro2::TokenStream;
use quote::format_ident;
use quote::quote;
use syn::DeriveInput;
use syn::ItemFn;
use std::convert::TryFrom;
use crate::factory::Factory;
use self::derive_static::SingletonStaticFactory;
use self::derive_trait::SingletonTraitFactory;
use self::facade_fn::FacadeFnFactory;
use self::impl_fn::ImplFnFactory;
use self::lock::SingletonLock;
use self::singleton_fns::SingletonFnType;
const SINGLETON_STATIC_PREFIX: &str = "BLOCKZ_SINGLETON_STATIC_";
pub(crate) struct SingletonFactory<'i> {
input: &'i DeriveInput,
opts: SingletonOpts,
}
#[derive(FromDeriveInput)]
#[darling(attributes(singleton))]
pub(crate) struct SingletonOpts {
#[darling(default)]
lock: SingletonLock,
}
pub(crate) struct SingletonFnFactory<'f> {
base: &'f ItemFn,
fn_type: SingletonFnType<'f>,
}
impl<'i> SingletonFactory<'i> {
pub fn new(input: &'i DeriveInput) -> Result<Self, darling::Error> {
Ok(Self {
input,
opts: SingletonOpts::from_derive_input(input)?,
})
}
fn create_static_ident(src: &Ident) -> Ident {
let type_name_upper = src.to_string().to_case(Case::UpperSnake);
format_ident!("{}{}", SINGLETON_STATIC_PREFIX, type_name_upper)
}
}
impl<'i> Factory for SingletonFactory<'i> {
type Product = syn::Result<TokenStream>;
fn build(self) -> Self::Product {
let static_ident = Self::create_static_ident(&self.input.ident);
let singleton_static =
SingletonStaticFactory::new(&static_ident, &self.input.ident, &self.opts.lock)
.build()?;
let singleton_trait =
SingletonTraitFactory::new(&static_ident, &self.input.ident, &self.opts.lock).build();
Ok(quote! {
#singleton_static
#singleton_trait
})
}
}
impl<'f> SingletonFnFactory<'f> {
pub fn new(base: &'f ItemFn) -> syn::Result<Self> {
Ok(Self {
base,
fn_type: SingletonFnType::try_from(base)?,
})
}
}
impl<'f> Factory for SingletonFnFactory<'f> {
type Product = syn::Result<TokenStream>;
fn build(self) -> Self::Product {
let impl_fn = ImplFnFactory::new(self.base, &self.fn_type).build()?;
let facade_fn = FacadeFnFactory::new(self.base, &self.fn_type, &impl_fn).build()?;
Ok(quote! {
#facade_fn
#impl_fn
})
}
}