owned_singleton_macros/
lib.rs

1extern crate proc_macro;
2extern crate proc_macro2;
3extern crate quote;
4extern crate rand;
5extern crate syn;
6
7use proc_macro::TokenStream;
8use std::{
9    sync::atomic::{AtomicUsize, Ordering},
10    time::{SystemTime, UNIX_EPOCH},
11};
12
13use proc_macro2::Span;
14use quote::quote;
15use rand::{Rng, SeedableRng};
16use syn::{
17    parse::{self, Parse, ParseStream},
18    parse_macro_input,
19    punctuated::Punctuated,
20    Ident, ItemStatic, Token,
21};
22
23/// Attribute to declare an owned singleton
24///
25/// This attribute must be applied to a `static [mut]` variable.
26///
27/// The attribute accepts two arguments: `Send` and `Sync` (e.g. `#[Singleton(Send, Sync)]`)
28///
29/// The expansion will produce a proxy struct whose name matches the identifier of the `static`
30/// variable.
31///
32/// For more information read the crate level documentation of the `owned-singleton` crate.
33#[allow(non_snake_case)]
34#[proc_macro_attribute]
35pub fn Singleton(args: TokenStream, input: TokenStream) -> TokenStream {
36    let item = parse_macro_input!(input as ItemStatic);
37    let args = parse_macro_input!(args as Args);
38
39    if let Err(e) = check(&item) {
40        return e.to_compile_error().into();
41    }
42
43    let attrs = &item.attrs;
44    let vis = &item.vis;
45    let ident = &item.ident;
46    let ty = &item.ty;
47    let expr = &item.expr;
48    let alias = mk_ident();
49
50    let mut items = vec![];
51    let symbol = format!("{}::{}", ident, alias);
52    items.push(quote!(
53        #(#attrs)*
54        #[export_name = #symbol]
55        static mut #alias: #ty = #expr;
56
57        #vis struct #ident { #alias: owned_singleton::export::NotSendOrSync }
58
59        unsafe impl owned_singleton::Singleton for #ident {
60            type Type = #ty;
61
62            #[inline]
63            unsafe fn new() -> Self {
64                #ident { #alias: owned_singleton::export::PhantomData }
65            }
66
67            #[inline]
68            fn get() -> *mut Self::Type {
69                unsafe { &mut #alias }
70            }
71        }
72
73        impl owned_singleton::export::Deref for #ident {
74            type Target = #ty;
75
76            #[inline]
77            fn deref(&self) -> &Self::Target {
78                unsafe { &#alias }
79            }
80        }
81
82        unsafe impl owned_singleton::export::StableDeref for #ident {}
83    ));
84
85    if args.send {
86        items.push(quote!(
87            unsafe impl Send for #ident where #ty: Send {}
88        ));
89    }
90
91    if args.sync {
92        items.push(quote!(
93            unsafe impl Sync for #ident where #ty: Sync {}
94        ));
95    }
96
97    if item.mutability.is_some() {
98        items.push(quote!(
99            impl owned_singleton::export::DerefMut for #ident {
100                #[inline]
101                fn deref_mut(&mut self) -> &mut Self::Target {
102                    unsafe { &mut #alias }
103                }
104            }
105        ));
106    }
107
108    quote!(#(#items)*).into()
109}
110
111struct Args {
112    send: bool,
113    sync: bool,
114}
115
116impl Parse for Args {
117    fn parse(input: ParseStream) -> parse::Result<Self> {
118        let mut send = false;
119        let mut sync = false;
120        let punctuated = Punctuated::<Ident, Token![,]>::parse_terminated(input)?;
121
122        for ident in punctuated {
123            match &*ident.to_string() {
124                "Send" => {
125                    if send {
126                        return Err(parse::Error::new(ident.span(), "this trait appears twice"));
127                    }
128
129                    send = true;
130                }
131                "Sync" => {
132                    if sync {
133                        return Err(parse::Error::new(ident.span(), "this trait appears twice"));
134                    }
135
136                    sync = true;
137                }
138                _ => {
139                    return Err(parse::Error::new(
140                        ident.span(),
141                        "expected one of: Send or Sync",
142                    ))
143                }
144            }
145        }
146
147        Ok(Args { send, sync })
148    }
149}
150
151fn check(_item: &ItemStatic) -> parse::Result<()> {
152    // TODO
153
154    Ok(())
155}
156
157fn mk_ident() -> Ident {
158    static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
159
160    let elapsed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
161
162    let secs = elapsed.as_secs();
163    let nanos = elapsed.subsec_nanos();
164
165    let count = CALL_COUNT.fetch_add(1, Ordering::SeqCst) as u32;
166    let mut seed: [u8; 16] = [0; 16];
167
168    for (i, v) in seed.iter_mut().take(8).enumerate() {
169        *v = ((secs >> (i * 8)) & 0xFF) as u8
170    }
171
172    for (i, v) in seed.iter_mut().skip(8).take(4).enumerate() {
173        *v = ((nanos >> (i * 8)) & 0xFF) as u8
174    }
175
176    for (i, v) in seed.iter_mut().skip(12).enumerate() {
177        *v = ((count >> (i * 8)) & 0xFF) as u8
178    }
179
180    let mut rng = rand::rngs::SmallRng::from_seed(seed);
181    Ident::new(
182        &(0..16)
183            .map(|i| {
184                if i == 0 || rng.gen() {
185                    ('a' as u8 + rng.gen::<u8>() % 25) as char
186                } else {
187                    ('0' as u8 + rng.gen::<u8>() % 10) as char
188                }
189            }).collect::<String>(),
190        Span::call_site(),
191    )
192}