use regex::Regex;
use std::collections::HashMap;
use std::sync::{Arc, LazyLock, RwLock};
static CACHE: LazyLock<RwLock<HashMap<String, Arc<Regex>>>> =
LazyLock::new(|| RwLock::new(HashMap::new()));
pub fn get_or_compile(pattern: &str) -> Result<Arc<Regex>, regex::Error> {
if let Some(cached) = CACHE.read().unwrap().get(pattern) {
return Ok(cached.clone());
}
let mut guard = CACHE.write().unwrap();
if let Some(cached) = guard.get(pattern) {
return Ok(cached.clone());
}
let compiled = Arc::new(Regex::new(pattern)?);
guard.insert(pattern.to_string(), compiled.clone());
Ok(compiled)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compiles_and_caches() {
let re1 = get_or_compile(r"^\d+$").unwrap();
let re2 = get_or_compile(r"^\d+$").unwrap();
assert!(Arc::ptr_eq(&re1, &re2));
assert!(re1.is_match("12345"));
assert!(!re1.is_match("abc"));
}
#[test]
fn invalid_pattern_errors_cleanly() {
let r = get_or_compile(r"(?P<bad");
assert!(r.is_err());
}
#[test]
fn flags_inline_work() {
let re = get_or_compile(r"(?i)hello").unwrap();
assert!(re.is_match("HELLO"));
assert!(re.is_match("Hello"));
assert!(re.is_match("hello"));
}
}