1extern crate proc_macro;
3use proc_macro::{token_stream::IntoIter, *};
4
5fn concat(ts: &mut IntoIter, end: Option<char>) -> Ident {
6 let mut ident = String::new();
7 for x in ts {
8 if let TokenTree::Ident(x) = x {
9 ident = ident + &x.to_string();
10 } else if matches!(end, Some(e) if matches!(x, TokenTree::Punct(x) if x == e)) {
11 break;
12 }
13 }
14 Ident::new(&ident, Span::call_site())
15}
16
17#[proc_macro]
18pub fn ident(ts: TokenStream) -> TokenStream {
25 TokenStream::from(TokenTree::Ident(concat(&mut ts.into_iter(), None)))
26}
27
28fn convert_replace(tt: TokenTree, to_replace: &TokenTree, ident: &Ident) -> TokenTree {
29 match (&tt, to_replace) {
30 (TokenTree::Ident(x), TokenTree::Ident(to_replace))
31 if x.to_string() == to_replace.to_string() =>
32 {
33 TokenTree::Ident(ident.clone())
34 }
35 (TokenTree::Group(x), _) => TokenTree::Group(Group::new(
36 x.delimiter(),
37 TokenStream::from_iter(
38 x.stream()
39 .into_iter()
40 .map(|x| convert_replace(x, to_replace, ident)),
41 ),
42 )),
43 _ => tt,
44 }
45}
46
47#[proc_macro]
48pub fn replace(ts: TokenStream) -> TokenStream {
57 let mut iter = ts.into_iter();
58 let to_replace = iter
59 .next()
60 .expect("syntax: replace!(to_replace with _this: to_replace) => with_this");
61 let ident = concat(&mut iter, Some(':'));
62 TokenStream::from_iter(iter.map(|x| convert_replace(x, &to_replace, &ident)))
63}