1use core::fmt;
2use std::marker::PhantomData;
3use std::ops::Deref;
4
5use crate::{Error, Pattern, Patterns, PatternsBuilderConfigured};
6
7pub trait PatternConfig {
9 const CASE_INSENSITIVE: bool = false;
11 const MAX_COMPLEXITY: u64 = u64::MAX;
13}
14
15pub struct DefaultPatternConfig;
19
20impl PatternConfig for DefaultPatternConfig {}
21
22pub struct CaseInsensitive;
26
27impl PatternConfig for CaseInsensitive {
28 const CASE_INSENSITIVE: bool = true;
29}
30
31pub struct TypedPattern<C = DefaultPatternConfig> {
53 pattern: Pattern,
54 _phantom: PhantomData<C>,
55}
56
57impl<C: PatternConfig> TypedPattern<C> {
58 pub fn new(pattern: &str) -> Result<Self, Error> {
71 Pattern::builder(pattern)
72 .case_insensitive(C::CASE_INSENSITIVE)
73 .max_complexity(C::MAX_COMPLEXITY)
74 .build()
75 .map(|pattern| Self {
76 pattern,
77 _phantom: PhantomData,
78 })
79 }
80}
81
82#[cfg(feature = "serde")]
83impl<'de, C: PatternConfig> serde::Deserialize<'de> for TypedPattern<C> {
84 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
85 where
86 D: serde::Deserializer<'de>,
87 {
88 let pattern = <std::borrow::Cow<'_, str>>::deserialize(deserializer)?;
89 Self::new(&pattern).map_err(serde::de::Error::custom)
90 }
91}
92
93#[cfg(feature = "serde")]
94impl<C> serde::Serialize for TypedPattern<C> {
95 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
96 where
97 S: serde::Serializer,
98 {
99 serializer.collect_str(&self.pattern)
100 }
101}
102
103impl<C> PartialEq for TypedPattern<C> {
104 fn eq(&self, other: &Self) -> bool {
105 self.pattern.eq(other)
106 }
107}
108
109impl<C> Eq for TypedPattern<C> {}
110
111impl<C> From<TypedPattern<C>> for Pattern {
112 fn from(value: TypedPattern<C>) -> Self {
113 value.pattern
114 }
115}
116
117impl<C> AsRef<Pattern> for TypedPattern<C> {
118 fn as_ref(&self) -> &Pattern {
119 &self.pattern
120 }
121}
122
123impl<C> Deref for TypedPattern<C> {
124 type Target = Pattern;
125
126 fn deref(&self) -> &Self::Target {
127 &self.pattern
128 }
129}
130
131impl<C> fmt::Debug for TypedPattern<C> {
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 self.pattern.fmt(f)
134 }
135}
136
137pub struct TypedPatterns<C = DefaultPatternConfig> {
139 patterns: Patterns,
140 _phantom: PhantomData<C>,
141}
142
143impl<C: PatternConfig> TypedPatterns<C> {
144 pub fn builder() -> TypedPatternsBuilder<C> {
145 let builder = Patterns::builder()
146 .case_insensitive(C::CASE_INSENSITIVE)
147 .patterns();
148
149 TypedPatternsBuilder {
150 builder,
151 _phantom: PhantomData,
152 }
153 }
154}
155
156impl<C: PatternConfig> Default for TypedPatterns<C> {
157 fn default() -> Self {
158 Self::builder().build()
159 }
160}
161
162impl<C> PartialEq for TypedPatterns<C> {
163 fn eq(&self, other: &Self) -> bool {
164 self.patterns.eq(other)
165 }
166}
167
168impl<C> Eq for TypedPatterns<C> {}
169
170impl<C: PatternConfig> From<String> for TypedPatterns<C> {
171 fn from(value: String) -> Self {
172 [value].into_iter().collect()
173 }
174}
175
176impl<C: PatternConfig> From<Vec<String>> for TypedPatterns<C> {
177 fn from(value: Vec<String>) -> Self {
178 value.into_iter().collect()
179 }
180}
181
182impl<C: PatternConfig, const N: usize> From<[String; N]> for TypedPatterns<C> {
183 fn from(value: [String; N]) -> Self {
184 value.into_iter().collect()
185 }
186}
187
188impl<C: PatternConfig> FromIterator<String> for TypedPatterns<C> {
192 fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
193 let mut builder = Self::builder();
194 for pattern in iter.into_iter() {
195 let _err = builder.add(pattern);
196 #[cfg(debug_assertions)]
197 _err.expect("all patterns should be valid patterns");
198 }
199 builder.build()
200 }
201}
202
203impl<C> From<TypedPatterns<C>> for Patterns {
204 fn from(value: TypedPatterns<C>) -> Self {
205 value.patterns
206 }
207}
208
209impl<C> AsRef<Patterns> for TypedPatterns<C> {
210 fn as_ref(&self) -> &Patterns {
211 &self.patterns
212 }
213}
214
215impl<C> Deref for TypedPatterns<C> {
216 type Target = Patterns;
217
218 fn deref(&self) -> &Self::Target {
219 &self.patterns
220 }
221}
222
223impl<C> Clone for TypedPatterns<C> {
224 fn clone(&self) -> Self {
225 Self {
226 patterns: self.patterns.clone(),
227 _phantom: PhantomData,
228 }
229 }
230}
231
232impl<C> fmt::Debug for TypedPatterns<C> {
233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 self.patterns.fmt(f)
235 }
236}
237
238#[cfg(feature = "serde")]
242impl<'de, C: PatternConfig> serde::Deserialize<'de> for TypedPatterns<C> {
243 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
244 where
245 D: serde::Deserializer<'de>,
246 {
247 struct Visitor<C>(PhantomData<C>);
248
249 impl<'a, C: PatternConfig> serde::de::Visitor<'a> for Visitor<C> {
250 type Value = TypedPatterns<C>;
251
252 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
253 formatter.write_str("a sequence of patterns")
254 }
255
256 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
257 where
258 A: serde::de::SeqAccess<'a>,
259 {
260 let mut builder = TypedPatterns::<C>::builder();
261
262 while let Some(item) = seq.next_element()? {
263 let _err = builder.add(item);
265 #[cfg(debug_assertions)]
266 _err.expect("all patterns should be valid patterns");
267 }
268
269 Ok(builder.build())
270 }
271 }
272
273 deserializer.deserialize_seq(Visitor(PhantomData))
274 }
275}
276
277#[cfg(feature = "serde")]
278impl<C> serde::Serialize for TypedPatterns<C> {
279 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
280 where
281 S: serde::Serializer,
282 {
283 self.patterns.serialize(serializer)
284 }
285}
286
287pub struct TypedPatternsBuilder<C> {
288 builder: PatternsBuilderConfigured,
289 _phantom: PhantomData<C>,
290}
291
292impl<C: PatternConfig> TypedPatternsBuilder<C> {
293 pub fn add(&mut self, pattern: String) -> Result<&mut Self, Error> {
295 self.builder.add(&pattern)?;
296 Ok(self)
297 }
298
299 pub fn build(self) -> TypedPatterns<C> {
301 TypedPatterns {
302 patterns: self.builder.build(),
303 _phantom: PhantomData,
304 }
305 }
306
307 pub fn take(&mut self) -> TypedPatterns<C> {
309 TypedPatterns {
310 patterns: self.builder.take(),
311 _phantom: PhantomData,
312 }
313 }
314}
315
316#[cfg(test)]
317mod tests {
318 use crate::Gas;
319
320 use super::*;
321
322 #[test]
323 fn test_pattern_default() {
324 let pattern: TypedPattern = TypedPattern::new("*[rt]x").unwrap();
325 assert_eq!(pattern.is_match("f/o_rx", Gas::MAX), Ok(true));
326 assert_eq!(pattern.is_match("f/o_tx", Gas::MAX), Ok(true));
327 assert_eq!(pattern.is_match("F/o_tx", Gas::MAX), Ok(true));
328 assert_eq!(pattern.is_match("f/o_Tx", Gas::MAX), Ok(false));
330 assert_eq!(pattern.is_match("f/o_rX", Gas::MAX), Ok(false));
331 }
332
333 #[test]
334 fn test_pattern_case_insensitive() {
335 let pattern: TypedPattern<CaseInsensitive> = TypedPattern::new("*[rt]x").unwrap();
336 assert_eq!(pattern.is_match("f/o_Tx", Gas::MAX), Ok(true));
338 assert_eq!(pattern.is_match("f/o_rX", Gas::MAX), Ok(true));
339 }
340
341 #[test]
342 fn test_pattern_eq() {
343 let pattern1: TypedPattern<CaseInsensitive> = TypedPattern::new("Foo**").unwrap();
344 let pattern2: TypedPattern<CaseInsensitive> = TypedPattern::new("Foo**").unwrap();
345 let pattern3: TypedPattern<CaseInsensitive> = TypedPattern::new("foo*").unwrap();
346 assert_eq!(&pattern1, &pattern1);
347 assert_eq!(&pattern1, &pattern2);
348 assert_eq!(&pattern1, &pattern3);
349 assert_eq!(&pattern2, &pattern3);
350 }
351
352 #[test]
353 fn test_pattern_neq() {
354 let pattern1: TypedPattern = TypedPattern::new("Foo**").unwrap();
355 let pattern2: TypedPattern = TypedPattern::new("foo*").unwrap();
356 assert_ne!(&pattern1, &pattern2);
357 }
358
359 #[test]
360 #[cfg(feature = "serde")]
361 fn test_pattern_deserialize() {
362 let pattern: TypedPattern<CaseInsensitive> = serde_json::from_str(r#""*[rt]x""#).unwrap();
363 assert_eq!(pattern.is_match("foobar_rx", Gas::MAX), Ok(true));
364 }
365
366 #[test]
367 #[cfg(feature = "serde")]
368 fn test_deserialize_err() {
369 let r: Result<TypedPattern<CaseInsensitive>, _> = serde_json::from_str(r#""[invalid""#);
370 assert!(r.is_err());
371 }
372
373 #[test]
374 #[cfg(feature = "serde")]
375 fn test_pattern_deserialize_complexity() {
376 struct Test;
377 impl PatternConfig for Test {
378 const MAX_COMPLEXITY: u64 = 2;
379 }
380 let r: Result<TypedPattern<Test>, _> = serde_json::from_str(r#""{foo,bar}""#);
381 assert!(r.is_ok());
382 let r: Result<TypedPattern<Test>, _> = serde_json::from_str(r#""{foo,bar,baz}""#);
383 assert!(r.is_err());
384 }
385
386 #[test]
387 #[cfg(feature = "serde")]
388 fn test_pattern_serialize() {
389 let pattern: TypedPattern = TypedPattern::new("*[rt]x").unwrap();
390 assert_eq!(serde_json::to_string(&pattern).unwrap(), r#""*[rt]x""#);
391 let pattern: TypedPattern<CaseInsensitive> = TypedPattern::new("*[rt]x").unwrap();
392 assert_eq!(serde_json::to_string(&pattern).unwrap(), r#""*[rt]x""#);
393 }
394
395 #[test]
396 fn test_patterns_default() {
397 let patterns: TypedPatterns = TypedPatterns::builder()
398 .add("*[rt]x".to_owned())
399 .unwrap()
400 .add("foobar".to_owned())
401 .unwrap()
402 .take();
403 assert_eq!(patterns.is_match("f/o_rx", Gas::MAX), Ok(true));
404 assert_eq!(patterns.is_match("foobar", Gas::MAX), Ok(true));
405 assert_eq!(patterns.is_match("Foobar", Gas::MAX), Ok(false));
406 }
407
408 #[test]
409 fn test_patterns_case_insensitive() {
410 let patterns: TypedPatterns<CaseInsensitive> = TypedPatterns::builder()
411 .add("*[rt]x".to_owned())
412 .unwrap()
413 .add("foobar".to_owned())
414 .unwrap()
415 .take();
416 assert_eq!(patterns.is_match("f/o_rx", Gas::MAX), Ok(true));
417 assert_eq!(patterns.is_match("f/o_Rx", Gas::MAX), Ok(true));
418 assert_eq!(patterns.is_match("foobar", Gas::MAX), Ok(true));
419 assert_eq!(patterns.is_match("Foobar", Gas::MAX), Ok(true));
420 }
421
422 #[test]
423 #[cfg(feature = "serde")]
424 fn test_patterns_deserialize() {
425 let pattern: TypedPatterns<CaseInsensitive> =
426 serde_json::from_str(r#"["*[rt]x","foobar"]"#).unwrap();
427 assert_eq!(pattern.is_match("foobar_rx", Gas::MAX), Ok(true));
428 assert_eq!(pattern.is_match("FOOBAR", Gas::MAX), Ok(true));
429 }
430
431 #[test]
432 #[cfg(all(feature = "serde", not(debug_assertions)))]
433 fn test_patterns_deserialize_err() {
434 let r: TypedPatterns<CaseInsensitive> =
435 serde_json::from_str(r#"["[invalid","foobar"]"#).unwrap();
436 assert_eq!(r.is_match("foobar", Gas::MAX), Ok(true));
437 assert_eq!(r.is_match("FOOBAR", Gas::MAX), Ok(true));
438
439 assert_eq!(serde_json::to_string(&r).unwrap(), r#"["foobar"]"#);
441 }
442
443 #[test]
444 #[cfg(feature = "serde")]
445 fn test_patterns_serialize() {
446 let pattern: TypedPatterns = TypedPatterns::builder()
447 .add("*[rt]x".to_owned())
448 .unwrap()
449 .add("foobar".to_owned())
450 .unwrap()
451 .take();
452 assert_eq!(
453 serde_json::to_string(&pattern).unwrap(),
454 r#"["*[rt]x","foobar"]"#
455 );
456
457 let pattern: TypedPatterns<CaseInsensitive> = TypedPatterns::builder()
458 .add("*[rt]x".to_owned())
459 .unwrap()
460 .add("foobar".to_owned())
461 .unwrap()
462 .take();
463 assert_eq!(
464 serde_json::to_string(&pattern).unwrap(),
465 r#"["*[rt]x","foobar"]"#
466 );
467 }
468}