utf32_lit/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{
4    parse_macro_input, parse_quote_spanned,
5    visit_mut::{self, VisitMut},
6    Expr, Lit,
7};
8
9/// Converts `&str` literals to `&[char]`.
10///
11/// ```rust
12/// use utf32_lit::utf32;
13/// let s = utf32!("æbc");
14/// assert_eq!(s, &['æ', 'b', 'c']);
15///
16/// let s_array = utf32!(&["foo", "bubble", "baz"]);
17/// let expected: &[&[char]] = &[&['f', 'o', 'o'], &['b', 'u', 'b', 'b', 'l', 'e'], &['b', 'a', 'z']];
18/// assert_eq!(s_array, expected);
19/// ```
20#[proc_macro]
21pub fn utf32(input: TokenStream) -> TokenStream {
22    let mut expr = parse_macro_input!(input as Expr);
23    Utf32Replace.visit_expr_mut(&mut expr);
24    quote!(#expr).into()
25}
26
27struct Utf32Replace;
28
29impl VisitMut for Utf32Replace {
30    fn visit_expr_mut(&mut self, node: &mut Expr) {
31        if let Expr::Lit(expr) = &node {
32            if let Lit::Str(s) = &expr.lit {
33                let string = s.value();
34                let chars = string.chars();
35                *node = parse_quote_spanned!(s.span()=> &[#(#chars),*] as &[char]);
36            }
37        }
38        visit_mut::visit_expr_mut(self, node);
39    }
40}
41
42/// Converts all `&str` literals to `&[char]`.
43///
44/// ```rust
45/// use utf32_lit::utf32_all_strings;
46/// #[utf32_all_strings]
47/// mod strings {
48///     pub const NAME: &[char] = "hello";
49/// }
50///
51/// assert_eq!(strings::NAME, &['h', 'e', 'l', 'l', 'o']);
52/// ```
53#[proc_macro_attribute]
54pub fn utf32_all_strings(_attr: TokenStream, input: TokenStream) -> TokenStream {
55    let mut item = parse_macro_input!(input);
56    Utf32Replace.visit_item_mut(&mut item);
57    quote!(#item).into()
58}