jsonpath_rust/path/config/
cache.rs
1use regex::{Error, Regex};
2use serde_json::Value;
3use std::collections::HashMap;
4use std::sync::{Arc, Mutex, PoisonError};
5
6#[derive(Clone)]
21pub enum RegexCache<T = DefaultRegexCacheInst>
22where
23 T: Clone + RegexCacheInst,
24{
25 Absent,
26 Implemented(T),
27}
28
29impl<T> RegexCache<T>
30where
31 T: Clone + RegexCacheInst,
32{
33 pub fn is_implemented(&self) -> bool {
34 match self {
35 RegexCache::Absent => false,
36 RegexCache::Implemented(_) => true,
37 }
38 }
39 pub fn get_instance(&self) -> Result<&T, RegexCacheError> {
40 match self {
41 RegexCache::Absent => Err(RegexCacheError::new("the instance is absent".to_owned())),
42 RegexCache::Implemented(inst) => Ok(inst),
43 }
44 }
45
46 pub fn instance(instance: T) -> Self {
47 RegexCache::Implemented(instance)
48 }
49}
50#[allow(clippy::derivable_impls)]
51impl Default for RegexCache {
52 fn default() -> Self {
53 RegexCache::Absent
54 }
55}
56
57pub trait RegexCacheInst {
59 fn validate(&self, regex: &str, values: Vec<&Value>) -> Result<bool, RegexCacheError>;
60}
61
62#[derive(Default, Debug, Clone)]
65pub struct DefaultRegexCacheInst {
66 cache: Arc<Mutex<HashMap<String, Regex>>>,
67}
68
69impl RegexCacheInst for DefaultRegexCacheInst {
70 fn validate(&self, regex: &str, values: Vec<&Value>) -> Result<bool, RegexCacheError> {
71 let mut cache = self.cache.lock()?;
72 if cache.contains_key(regex) {
73 let r = cache.get(regex).unwrap();
74 Ok(validate(r, values))
75 } else {
76 let new_reg = Regex::new(regex)?;
77 let result = validate(&new_reg, values);
78 cache.insert(regex.to_owned(), new_reg);
79 Ok(result)
80 }
81 }
82}
83
84fn validate(r: &Regex, values: Vec<&Value>) -> bool {
85 for el in values.iter() {
86 if let Some(v) = el.as_str() {
87 if r.is_match(v) {
88 return true;
89 }
90 }
91 }
92 false
93}
94
95pub struct RegexCacheError {
96 pub reason: String,
97}
98
99impl From<Error> for RegexCacheError {
100 fn from(value: Error) -> Self {
101 RegexCacheError::new(value.to_string())
102 }
103}
104
105impl<T> From<PoisonError<T>> for RegexCacheError {
106 fn from(value: PoisonError<T>) -> Self {
107 RegexCacheError::new(value.to_string())
108 }
109}
110
111impl RegexCacheError {
112 pub fn new(reason: String) -> Self {
113 Self { reason }
114 }
115}