owned_singleton_macros/
lib.rs1extern 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#[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 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}