use std::{cell::RefCell, collections::HashMap};
use regex::Regex;
#[derive(Debug, Default)]
pub struct RegexCache {
map: RefCell<HashMap<String, Result<Regex, String>>>,
}
impl RegexCache {
pub fn new() -> Self {
Self::default()
}
pub fn get(&self, pattern: &str) -> Result<Regex, String> {
if let Some(hit) = self.map.borrow().get(pattern) {
return hit.clone();
}
let compiled = Regex::new(pattern).map_err(|e| reason(&e));
self.map
.borrow_mut()
.insert(pattern.to_string(), compiled.clone());
compiled
}
}
pub(crate) fn reason(e: ®ex::Error) -> String {
let report = e.to_string();
let last = report.lines().rev().find(|l| !l.trim().is_empty());
last.unwrap_or(&report)
.trim()
.trim_start_matches("error: ")
.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compiles_once_and_remembers_failures() {
let cache = RegexCache::new();
let a = cache.get("^a+$").unwrap();
assert!(a.is_match("aaa"));
assert!(cache.get("^a+$").is_ok());
let e = cache.get("(").unwrap_err();
assert_eq!(cache.get("(").unwrap_err(), e);
assert!(!e.contains('\n'), "{e}");
assert_eq!(cache.map.borrow().len(), 2);
}
}