const_str_proc_macro/
lib.rs1#![forbid(unsafe_code)]
4#![deny(missing_docs, clippy::all, clippy::cargo)]
5#![allow(
6 clippy::missing_docs_in_private_items,
7 clippy::missing_inline_in_public_items,
8 clippy::implicit_return
9)]
10
11#[allow(unused_macros)]
12macro_rules! proc_error {
13 ($token:expr, $msg: expr) => {
14 TokenStream::from(syn::Error::new($token.span(), $msg).to_compile_error())
15 };
16}
17
18mod case;
19mod fmt;
20
21#[cfg(feature = "regex")]
22mod regex;
23
24use proc_macro::TokenStream;
25use quote::ToTokens;
26use syn::parse::Parse;
27use syn::spanned::Spanned;
28use syn::{parse_macro_input, LitStr};
29
30#[allow(dead_code)]
31fn direct_convert<T, E, F>(input: TokenStream, f: F) -> TokenStream
32where
33 T: Parse + Spanned,
34 E: ToString,
35 F: FnOnce(&T) -> Result<String, E>,
36{
37 let src_token: T = parse_macro_input!(input as T);
38 let s = match f(&src_token) {
39 Ok(s) => s,
40 Err(e) => return proc_error!(src_token, e.to_string()),
41 };
42 let dst_token = LitStr::new(&s, src_token.span());
43 dst_token.into_token_stream().into()
44}
45
46#[doc(hidden)]
47#[proc_macro]
48pub fn format_parts(input: TokenStream) -> TokenStream {
49 use crate::fmt::ConstFormat;
50 let m = parse_macro_input!(input as ConstFormat);
51 m.eval()
52}
53
54#[proc_macro]
56pub fn convert_case(input: TokenStream) -> TokenStream {
57 use crate::case::ConvertCase;
58 let m = parse_macro_input!(input as ConvertCase);
59 m.eval()
60}
61
62#[cfg(feature = "http")]
66#[proc_macro]
67pub fn verified_header_name(input: TokenStream) -> TokenStream {
68 use http::header::HeaderName;
69
70 direct_convert(input, |s: &LitStr| {
71 let s = s.value();
72 HeaderName::from_lowercase(s.as_bytes()).map(|_| s)
73 })
74}
75
76#[cfg(feature = "regex")]
80#[proc_macro]
81pub fn verified_regex(input: TokenStream) -> TokenStream {
82 direct_convert(input, |s: &LitStr| {
83 let s = s.value();
84 ::regex::Regex::new(&s).map(|_| s)
85 })
86}
87
88#[cfg(feature = "regex")]
90#[proc_macro]
91pub fn regex_assert_match(input: TokenStream) -> TokenStream {
92 use crate::regex::RegexAssertMatch;
93 let m = parse_macro_input!(input as RegexAssertMatch);
94 m.eval()
95}