s_macro/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
extern crate proc_macro;
use proc_macro::TokenStream;

use quote::quote;
use syn::{Expr, Lit};

/// Convenient way of making a `String`.
///
/// 1. `s!()`
/// 2. `s!(123 + 321)`
/// 3. `s!("hello, {}", "world")`
///
/// # Examples
///
/// ```
/// use s_macro::s;
///
/// assert!(s!()                   == String::new());
/// assert!(s!("hello, world")     == String::from("hello, world"));
/// assert!(s!(123 + 321)          == format!("{}", 123 + 321));
///
/// let world = "world";
/// assert!(s!("hello, {}", world) == format!("hello, {}", world));
/// assert!(s!("hello, {world}")   == format!("hello, {world}"));
/// ```
#[proc_macro]
pub fn s(input: TokenStream) -> TokenStream {
    if input.is_empty() {
        quote! { String::new() }.into()
    }

    else if let Ok(expr) = syn::parse::<Expr>(input.clone()) {
        if let Expr::Lit(ref lit) = expr {
            if let Lit::Str(_) = lit.lit {
                return quote! { format!(#expr) }.into();
            }
        }

        quote! { format!("{}", #expr) }.into()
    }

    else {
        let input = proc_macro2::TokenStream::from(input);
        quote! { format!(#input) }.into()
    }
}