use proc_macro2::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::{LitStr, Result};
pub struct RegexInput {
pub pattern: LitStr,
}
impl Parse for RegexInput {
fn parse(input: ParseStream) -> Result<Self> {
Ok(Self {
pattern: input.parse()?,
})
}
}
pub fn expand(input: RegexInput) -> TokenStream {
let pattern_str = input.pattern.value();
if let Err(e) = regex::Regex::new(&pattern_str) {
return syn::Error::new(input.pattern.span(), format!("invalid regex: {e}"))
.to_compile_error();
}
let lit = &input.pattern;
quote! {
{
static REGEX: std::sync::OnceLock<regex::Regex> = std::sync::OnceLock::new();
REGEX.get_or_init(|| {
regex::Regex::new(#lit).expect("regex was validated at compile time")
})
}
}
}
#[cfg(test)]
mod tests {
use syn::parse_quote;
use super::*;
#[test]
fn parse_simple_regex() {
let input: RegexInput = parse_quote! {
r"hello\s+world"
};
assert_eq!(input.pattern.value(), r"hello\s+world");
}
}