singleton_attr_proc_macro/
lib.rs

1#![feature(proc_macro_span)]
2extern crate proc_macro;
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, ItemStruct};
6
7#[proc_macro_derive(Singleton)]
8pub fn singleton_derive(item: TokenStream) -> TokenStream {
9    let input = parse_macro_input!(item as ItemStruct);
10    let name = &input.ident;
11
12    TokenStream::from(quote! {
13        const _: () = {
14            static mut __INSTANCE: *mut #name = std::ptr::null_mut();
15
16            impl singleton_attr::traits::Singleton for #name {
17                #[inline]
18                fn init_instance(instance: Self) {
19                    unsafe {
20                        __INSTANCE = std::alloc::alloc(std::alloc::Layout::new::<Self>()) as *mut Self;
21                        std::ptr::write_volatile(__INSTANCE, instance);
22                    }
23                }
24
25                #[inline]
26                fn get_instance() -> &'static mut Self {
27                    unsafe {
28                        if __INSTANCE.is_null() {
29                            Self::init_instance(Self::default());
30                        }
31                        &mut *__INSTANCE
32                    }
33                }
34            }
35
36            impl Drop for #name {
37                fn drop(&mut self) {
38                    unsafe { std::alloc::dealloc(__INSTANCE as *mut u8, std::alloc::Layout::new::<Self>()); }
39                }
40            }
41        };
42    })
43}
44
45#[proc_macro_derive(SafeSingleton)]
46pub fn singleton_safe_derive(item: TokenStream) -> TokenStream {
47    let input = parse_macro_input!(item as ItemStruct);
48    let name = &input.ident;
49
50    TokenStream::from(quote! {
51        const _: () = {
52            static mut __INSTANCE: Option<std::sync::Arc<std::sync::Mutex<#name>>> = None;
53
54            impl singleton_attr::traits::SafeSingleton for #name {
55                #[inline]
56                fn init_instance(instance: Self) {
57                    unsafe {
58                        __INSTANCE = Some(std::sync::Arc::new(std::sync::Mutex::new(instance)));
59                    }
60                }
61
62                #[inline]
63                fn get_instance() -> std::sync::LockResult<std::sync::MutexGuard<'static, Self>> {
64                    unsafe {
65                        if let None = __INSTANCE {
66                            Self::init_instance(Self::default());
67                        }
68
69                        __INSTANCE.as_ref().unwrap().lock()
70                    }
71                }
72            }
73        };
74    })
75}