inline_tweak_derive/
lib.rs1extern crate proc_macro;
2use proc_macro::TokenStream;
3use proc_macro2::{Ident, Span};
4use quote::ToTokens;
5use syn::punctuated::Punctuated;
6use syn::visit_mut::VisitMut;
7use syn::{
8 parse_macro_input, Attribute, Expr, ExprBreak, ExprConst, ExprMacro, ItemConst, ItemStatic,
9 Lit, LitInt, LitStr, Macro, MacroDelimiter, Path, PathSegment, Token, Type,
10};
11
12struct LiteralReplacer {
13 nth: usize,
14 fname: Ident,
15 release_tweak: bool,
16}
17
18impl LiteralReplacer {
19 fn replace(&mut self, i: &mut Expr) {
20 let expr = std::mem::replace(
21 i,
22 Expr::Break(ExprBreak {
23 attrs: vec![],
24 break_token: Default::default(),
25 label: None,
26 expr: None,
27 }),
28 );
29
30 *i = Expr::Macro(ExprMacro {
31 attrs: vec![],
32 mac: Macro {
33 path: Path {
34 segments: [
35 PathSegment::from(Ident::new("inline_tweak", Span::call_site())),
36 PathSegment::from(Ident::new(
37 if self.release_tweak {
38 "derive_release_tweak"
39 } else {
40 "derive_tweak"
41 },
42 Span::call_site(),
43 )),
44 ]
45 .into_iter()
46 .collect(),
47 leading_colon: Some(Default::default()),
48 },
49 bang_token: Default::default(),
50 delimiter: MacroDelimiter::Paren(Default::default()),
51 tokens: [
52 expr,
53 Expr::Lit(syn::ExprLit {
54 attrs: vec![],
55 lit: Lit::Str(LitStr::new(&self.fname.to_string(), Span::call_site())),
56 }),
57 Expr::Lit(syn::ExprLit {
58 attrs: vec![],
59 lit: Lit::Int(LitInt::new(&self.nth.to_string(), Span::call_site())),
60 }),
61 ]
62 .into_iter()
63 .collect::<Punctuated<Expr, Token![,]>>()
64 .into_token_stream(),
65 },
66 });
67
68 self.nth += 1;
69 }
70}
71
72impl VisitMut for LiteralReplacer {
73 fn visit_expr_mut(&mut self, i: &mut Expr) {
74 match *i {
75 Expr::Lit(syn::ExprLit {
76 lit: Lit::Char(_) | Lit::Int(_) | Lit::Float(_) | Lit::Bool(_) | Lit::Str(_),
77 ..
78 }) => {
79 self.replace(i);
80 }
81 Expr::Unary(syn::ExprUnary {
82 op: syn::UnOp::Neg(_),
83 ref expr,
84 ..
85 }) if matches!(
86 &**expr,
87 Expr::Lit(syn::ExprLit {
88 lit: Lit::Int(_) | Lit::Float(_),
89 ..
90 })
91 ) =>
92 {
93 self.replace(i);
94 }
95 _ => syn::visit_mut::visit_expr_mut(self, i),
96 }
97 }
98
99 fn visit_expr_const_mut(&mut self, _: &mut ExprConst) {}
100
101 fn visit_item_const_mut(&mut self, _: &mut ItemConst) {}
102
103 fn visit_item_static_mut(&mut self, _: &mut ItemStatic) {}
104
105 fn visit_type_mut(&mut self, _: &mut Type) {}
106
107 fn visit_attribute_mut(&mut self, _: &mut Attribute) {}
108}
109
110#[proc_macro_attribute]
127pub fn tweak_fn(_attr: TokenStream, item: TokenStream) -> TokenStream {
128 do_fn(item, false)
129}
130
131#[proc_macro_attribute]
148pub fn release_tweak_fn(_attr: TokenStream, item: TokenStream) -> TokenStream {
149 do_fn(item, true)
150}
151
152fn do_fn(item: TokenStream, release_tweak: bool) -> TokenStream {
153 let mut v: syn::ItemFn = parse_macro_input!(item as syn::ItemFn);
154
155 let fname = v.sig.ident.clone();
156
157 LiteralReplacer {
158 nth: 0,
159 fname,
160 release_tweak,
161 }
162 .visit_item_fn_mut(&mut v);
163
164 v.into_token_stream().into()
165}