comn_pms/
lib.rs

1use chrono::prelude::*;
2use proc_macro::TokenStream;
3use proc_macro2::Span;
4use quote::ToTokens;
5use std::{str::FromStr, sync::atomic::AtomicI64};
6use syn::{
7    parse::{Parse, ParseStream},
8    Block, Ident, LitInt, LitStr, Token, TypePath,
9};
10
11#[proc_macro]
12pub fn compile_time(_: TokenStream) -> TokenStream {
13    let dt = Local::now();
14
15    let current = format!(
16        "{}{:02}{:02}.{:02}{:02}{:02}",
17        dt.year(),
18        dt.month(),
19        dt.day(),
20        dt.hour(),
21        dt.minute(),
22        dt.second()
23    );
24
25    let expanded = quote::quote! {
26         #current
27    };
28    expanded.into()
29}
30
31enum Parser {
32    _Block(Block),
33    _Ident(Ident),
34}
35
36impl Parser {
37    fn parse_ident(input: ParseStream) -> syn::Result<Ident> {
38        let mut symbol = String::new();
39        let ident: Ident = input.parse()?;
40        input.parse::<Token![,]>()?;
41        let n: LitInt = input.parse()?;
42
43        symbol.push_str(ident.to_string().trim_start_matches("r#"));
44        symbol.push('_');
45        symbol.push_str(n.to_string().as_str());
46        Ok(Ident::new(symbol.as_str(), ident.span()))
47    }
48}
49
50impl Parse for Parser {
51    fn parse(input: ParseStream) -> syn::Result<Self> {
52        if !input.peek(Ident) {
53            return Ok(Parser::_Block(input.parse()?));
54        }
55        Ok(Parser::_Ident(Parser::parse_ident(input)?))
56    }
57}
58
59fn id64() -> i64 {
60    static N: AtomicI64 = AtomicI64::new(0);
61    N.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
62}
63
64#[proc_macro]
65pub fn int64(input: TokenStream) -> TokenStream {
66    struct MacroLiteral(i64);
67    impl Parse for MacroLiteral {
68        fn parse(input: ParseStream) -> syn::Result<Self> {
69            if !input.peek(LitInt) {
70                return Ok(MacroLiteral(0));
71            }
72            let n: LitInt = input.parse()?;
73            Ok(MacroLiteral(n.to_string().parse().unwrap()))
74        }
75    }
76    let MacroLiteral(n) = syn::parse_macro_input!(input as MacroLiteral);
77    let mut mask: i64 = -1;
78    if n != 0 {
79        mask = 0xfff << 52;
80    }
81
82    let id = n << 52 | id64() & mask;
83    let expanded = quote::quote! {
84        #id
85    };
86    expanded.into()
87}
88
89#[proc_macro]
90pub fn str64(input: TokenStream) -> TokenStream {
91    struct MacroLiteral(String);
92    impl Parse for MacroLiteral {
93        fn parse(input: ParseStream) -> syn::Result<Self> {
94            if !input.peek(LitStr) {
95                return Ok(MacroLiteral("".to_owned()));
96            }
97            let s: LitStr = input.parse()?;
98            Ok(MacroLiteral(s.value()))
99        }
100    }
101    let MacroLiteral(s) = syn::parse_macro_input!(input as MacroLiteral);
102
103    let id = format!("{}{}", s, id64());
104    let expanded = quote::quote! {
105        #id
106    };
107    expanded.into()
108}
109
110#[proc_macro]
111pub fn _suffix(input: TokenStream) -> TokenStream {
112    let input = syn::parse_macro_input!(input as Parser);
113    match input {
114        Parser::_Block(b) => {
115            let stmts = b.stmts;
116            let seq = LitInt::new(&id64().to_string(), Span::call_site());
117            let expanded = quote::quote! {
118                macro_rules! n {
119                    ($iden:ident) => {
120                        $crate::_suffix!($iden, #seq)
121                    }
122                }
123                #(#stmts)*
124            };
125            expanded.into()
126        }
127
128        Parser::_Ident(i) => {
129            let expanded = quote::quote! {
130                 #i
131            };
132            expanded.into()
133        }
134    }
135}
136
137#[proc_macro]
138pub fn make(input: TokenStream) -> TokenStream {
139    fn gen_code(code: &mut String, template: &str, typename: &str, iface: &str) {
140        match iface {
141            "Send" | "Sync" => code.push_str(
142                format!("unsafe impl{} {} for {} {{}}\n", template, iface, typename).as_str(),
143            ),
144            "Default" => code.push_str(
145                format!(
146                    "impl{} {} for {} {{ fn default() -> Self {{ Self::new() }} }}\n",
147                    template, iface, typename
148                )
149                .as_str(),
150            ),
151            _ => panic!("only Send, Sync, Default is allowed"),
152        };
153    }
154
155    struct MacroLiteral(String);
156    impl Parse for MacroLiteral {
157        fn parse(input: ParseStream) -> syn::Result<Self> {
158            let symbol: TypePath = input.parse()?;
159            input.parse::<Token!(:)>()?;
160
161            let mut typename = symbol.to_token_stream().to_string();
162            typename.retain(|c| !c.is_whitespace());
163            let template = match typename.find('<') {
164                Some(idx) => &typename[idx..],
165                None => "",
166            };
167
168            fn keep() -> impl FnMut(&char) -> bool {
169                let mut level = 0;
170                let mut inner: Option<Box<dyn FnMut(&char) -> bool>> = None;
171                move |c: &char| -> bool {
172                    match inner {
173                        Some(ref mut fptr) => {
174                            if *c == '<' {
175                                level += 1;
176                            } else if *c == '>' {
177                                level -= 1;
178                                if level == -1 {
179                                    inner.take();
180                                    return true;
181                                }
182                            }
183                            fptr(c)
184                        }
185                        None => {
186                            if level == 0 {
187                                if *c == ':' {
188                                    level = 1;
189                                } else if *c == '<' {
190                                    inner = Some(Box::new(keep()));
191                                }
192                            } else if *c == ',' || *c == '>' {
193                                level -= 1;
194                            } else if *c == '<' {
195                                level += 1;
196                            }
197                            level == 0
198                        }
199                    }
200                }
201            }
202            let typename: String = typename.chars().filter(keep()).collect();
203
204            let mut code = String::new();
205            loop {
206                let symbol: TypePath = input.parse()?;
207                let iface = symbol.path.get_ident().take().unwrap().to_string();
208                gen_code(&mut code, template, &typename, &iface);
209
210                if !input.peek(Token!(,)) {
211                    break;
212                }
213                input.parse::<Token!(,)>()?;
214            }
215            Ok(MacroLiteral(code))
216        }
217    }
218
219    let input = syn::parse_macro_input!(input as MacroLiteral);
220    TokenStream::from_str(input.0.as_str()).unwrap()
221}