string_literal_const_replace/
lib.rs1#![feature(proc_macro_expand)]
9
10use proc_macro::{Literal, Span, TokenStream, TokenTree};
11
12#[proc_macro]
29pub fn string_literal_replace(input: TokenStream) -> TokenStream {
30 let ParsedInput {
31 original_string,
32 replacements,
33 } = syn::parse_macro_input!(input as ParsedInput);
34 let mut processed_str = original_string.clone();
35 for (from, to) in replacements {
36 processed_str = processed_str.replace(&from, &to);
37 }
38 let mut lit = Literal::string(&processed_str);
39 lit.set_span(Span::call_site());
40 TokenTree::Literal(lit).into()
41}
42
43struct ParsedInput {
45 original_string: String,
47 replacements: Vec<(String, String)>,
49}
50
51impl syn::parse::Parse for ParsedInput {
52 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
53 let original_string = input.parse::<StringExpander>()?.into();
54 let mut replacements = Vec::new();
55 while let Ok(group) = input.parse::<proc_macro2::Group>() {
56 let Replacement { from, to } = syn::parse2(group.stream())?;
57 replacements.push((from, to));
58 }
59 Ok(Self {
60 original_string,
61 replacements,
62 })
63 }
64}
65
66struct Replacement {
68 from: String,
70 to: String,
72}
73impl syn::parse::Parse for Replacement {
74 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
75 let from = input.parse::<StringExpander>()?.into();
76 input.parse::<syn::Token![->]>()?;
77 let to = input.parse::<StringExpander>()?.into();
78 Ok(Self { from, to })
79 }
80}
81
82struct StringExpander {
84 expanded: String,
86}
87impl From<StringExpander> for String {
88 fn from(value: StringExpander) -> Self {
89 value.expanded
90 }
91}
92impl syn::parse::Parse for StringExpander {
93 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
94 use quote::ToTokens;
95
96 if let Ok(expr) = input.parse::<syn::ExprMacro>() {
97 let expression = TokenStream::from(expr.into_token_stream());
98 Ok(Self {
99 expanded: syn::parse::<syn::LitStr>(
100 expression.expand_expr().map_err(|e| input.error(e))?,
101 )?
102 .value(),
103 })
104 } else {
105 Ok(Self {
106 expanded: input.parse::<syn::LitStr>()?.value(),
107 })
108 }
109 }
110}