1use std::fmt::{self, Write};
41use std::num::NonZeroUsize;
42
43mod typed;
44mod wildmatch;
45
46pub use typed::*;
47
48#[derive(Debug)]
50pub struct Error {
51 pattern: String,
52 kind: ErrorKind,
53}
54
55#[derive(Debug)]
56enum ErrorKind {
57 InvalidRange(char, char),
60 UnbalancedCharacterClass,
62 InvalidCharacterClass,
64 NestedAlternates,
66 UnbalancedAlternates,
68 DanglingEscape,
70 Complexity {
72 complexity: u64,
73 max_complexity: u64,
74 },
75}
76
77impl std::error::Error for Error {}
78
79impl fmt::Display for Error {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 write!(f, "Error parsing pattern '{}': ", self.pattern)?;
82 match &self.kind {
83 ErrorKind::InvalidRange(start, end) => {
84 write!(f, "Invalid character range `{start}-{end}`")
85 }
86 ErrorKind::UnbalancedCharacterClass => write!(f, "Unbalanced character class"),
87 ErrorKind::InvalidCharacterClass => write!(f, "Invalid character class"),
88 ErrorKind::NestedAlternates => write!(f, "Nested alternates"),
89 ErrorKind::UnbalancedAlternates => write!(f, "Unbalanced alternates"),
90 ErrorKind::DanglingEscape => write!(f, "Dangling escape"),
91 ErrorKind::Complexity {
92 complexity,
93 max_complexity,
94 } => write!(
95 f,
96 "Pattern complexity ({complexity}) exceeds maximum allowed complexity ({max_complexity})"
97 ),
98 }
99 }
100}
101
102#[derive(Debug, PartialEq, Eq)]
104pub struct OutOfGas(u64);
105
106impl std::error::Error for OutOfGas {}
107
108impl fmt::Display for OutOfGas {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 write!(f, "Pattern could not be matched with {} ops", self.0)
111 }
112}
113
114#[derive(Clone, PartialEq, Eq)]
142pub struct Pattern {
143 case_sensitive: CaseSensitive,
144 strategy: MatchStrategy,
145}
146
147impl Pattern {
148 pub fn new(pattern: &str) -> Result<Self, Error> {
150 Self::builder(pattern).build()
151 }
152
153 pub fn builder(pattern: &str) -> PatternBuilder<'_> {
156 PatternBuilder {
157 pattern,
158 case_sensitive: CaseSensitive(true),
159 max_complexity: u64::MAX,
160 }
161 }
162
163 pub fn is_match(&self, haystack: &str, gas: Gas) -> Result<bool, OutOfGas> {
165 let opts = MatchOptions {
166 case_sensitive: self.case_sensitive,
167 gas: &mut gas.clone(),
168 };
169 self.strategy
170 .is_match(haystack, opts)
171 .map_err(|_| OutOfGas(gas.0))
172 }
173}
174
175impl fmt::Debug for Pattern {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 f.debug_struct("Pattern")
178 .field("<pattern>", &self.to_string())
179 .field("case_sensitive", &self.case_sensitive)
180 .field("strategy", &self.strategy)
181 .finish()
182 }
183}
184
185impl fmt::Display for Pattern {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 self.strategy.fmt(f)
188 }
189}
190
191#[cfg(feature = "serde")]
192impl serde::Serialize for Pattern {
193 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
194 where
195 S: serde::Serializer,
196 {
197 serializer.collect_str(&self)
198 }
199}
200
201#[cfg(feature = "serde")]
202impl<'de> serde::Deserialize<'de> for Pattern {
203 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
204 where
205 D: serde::Deserializer<'de>,
206 {
207 let pattern = String::deserialize(deserializer)?;
208 Pattern::new(&pattern).map_err(serde::de::Error::custom)
209 }
210}
211
212#[derive(Debug, Clone, PartialEq, Eq)]
214pub struct Patterns {
215 strategies: Box<[MatchStrategy]>,
216 case_sensitive: CaseSensitive,
217}
218
219impl Patterns {
220 pub fn empty() -> Self {
230 Self {
231 strategies: Default::default(),
232 case_sensitive: CaseSensitive(true),
233 }
234 }
235
236 pub fn builder() -> PatternsBuilder {
238 PatternsBuilder {
239 case_sensitive: CaseSensitive(true),
240 }
241 }
242
243 pub fn is_match(&self, haystack: &str, gas: Gas) -> Result<bool, OutOfGas> {
245 let remaining_gas = &mut gas.clone();
246 for strategy in &self.strategies {
247 let opts = MatchOptions {
248 case_sensitive: self.case_sensitive,
249 gas: remaining_gas,
250 };
251 if strategy
252 .is_match(haystack, opts)
253 .map_err(|_| OutOfGas(gas.0))?
254 {
255 return Ok(true);
256 }
257 }
258 Ok(false)
259 }
260
261 pub fn is_empty(&self) -> bool {
265 self.strategies.is_empty()
266 }
267}
268
269#[cfg(feature = "serde")]
270impl serde::Serialize for Patterns {
271 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
272 where
273 S: serde::Serializer,
274 {
275 struct AsDisplay<'a>(&'a MatchStrategy);
276 impl serde::Serialize for AsDisplay<'_> {
277 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
278 serializer.collect_str(self.0)
279 }
280 }
281
282 serializer.collect_seq(self.strategies.iter().map(AsDisplay))
283 }
284}
285
286#[cfg(feature = "serde")]
287impl<'de> serde::Deserialize<'de> for Patterns {
288 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
289 where
290 D: serde::Deserializer<'de>,
291 {
292 struct Visitor;
293
294 impl<'de> serde::de::Visitor<'de> for Visitor {
295 type Value = Patterns;
296
297 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
298 formatter.write_str("a sequence of patterns")
299 }
300
301 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
302 where
303 A: serde::de::SeqAccess<'de>,
304 {
305 let mut builder = Patterns::builder().patterns();
306 while let Some(pattern) = seq.next_element::<std::borrow::Cow<'_, str>>()? {
307 builder.add(&pattern).map_err(serde::de::Error::custom)?;
308 }
309 Ok(builder.build())
310 }
311 }
312
313 deserializer.deserialize_seq(Visitor)
314 }
315}
316
317#[derive(Debug)]
319pub struct PatternBuilder<'a> {
320 pattern: &'a str,
321 max_complexity: u64,
322 case_sensitive: CaseSensitive,
323}
324
325impl PatternBuilder<'_> {
326 pub fn case_insensitive(&mut self, enabled: bool) -> &mut Self {
330 self.case_sensitive = CaseSensitive(!enabled);
331 self
332 }
333
334 pub fn max_complexity(&mut self, max_complexity: u64) -> &mut Self {
344 self.max_complexity = max_complexity;
345 self
346 }
347
348 pub fn build(&self) -> Result<Pattern, Error> {
350 let mut parser = Parser::new(self.pattern, self.case_sensitive);
351 parser.parse().map_err(|kind| Error {
352 pattern: self.pattern.to_owned(),
353 kind,
354 })?;
355
356 if parser.complexity > self.max_complexity {
357 return Err(Error {
358 pattern: self.pattern.to_owned(),
359 kind: ErrorKind::Complexity {
360 complexity: parser.complexity,
361 max_complexity: self.max_complexity,
362 },
363 });
364 }
365
366 let strategy = MatchStrategy::from_tokens(parser.tokens).map_err(|kind| Error {
367 pattern: self.pattern.to_owned(),
368 kind,
369 })?;
370
371 Ok(Pattern {
372 case_sensitive: self.case_sensitive,
373 strategy,
374 })
375 }
376}
377
378#[derive(Debug)]
380pub struct PatternsBuilder {
381 case_sensitive: CaseSensitive,
382}
383
384impl PatternsBuilder {
385 pub fn case_insensitive(&mut self, enabled: bool) -> &mut Self {
389 self.case_sensitive = CaseSensitive(!enabled);
390 self
391 }
392
393 pub fn patterns(&mut self) -> PatternsBuilderConfigured {
395 PatternsBuilderConfigured {
396 strategies: Vec::new(),
397 case_sensitive: self.case_sensitive,
398 }
399 }
400
401 pub fn add(&mut self, pattern: &str) -> Result<PatternsBuilderConfigured, Error> {
403 let mut builder = PatternsBuilderConfigured {
404 strategies: Vec::with_capacity(1),
405 case_sensitive: self.case_sensitive,
406 };
407 builder.add(pattern)?;
408 Ok(builder)
409 }
410}
411
412#[derive(Debug)]
416pub struct PatternsBuilderConfigured {
417 strategies: Vec<MatchStrategy>,
418 case_sensitive: CaseSensitive,
419}
420
421impl PatternsBuilderConfigured {
422 pub fn add(&mut self, pattern: &str) -> Result<&mut Self, Error> {
424 let mut parser = Parser::new(pattern, self.case_sensitive);
425 parser.parse().map_err(|kind| Error {
426 pattern: pattern.to_owned(),
427 kind,
428 })?;
429
430 let strategy = MatchStrategy::from_tokens(parser.tokens).map_err(|kind| Error {
431 pattern: pattern.to_owned(),
432 kind,
433 })?;
434
435 self.strategies.push(strategy);
436
437 Ok(self)
438 }
439
440 pub fn build(self) -> Patterns {
442 Patterns {
443 strategies: self.strategies.into_boxed_slice(),
444 case_sensitive: self.case_sensitive,
445 }
446 }
447
448 pub fn take(&mut self) -> Patterns {
452 Patterns {
453 strategies: std::mem::take(&mut self.strategies).into_boxed_slice(),
454 case_sensitive: self.case_sensitive,
455 }
456 }
457}
458
459#[derive(Debug, Clone, Copy, PartialEq, Eq)]
463struct CaseSensitive(pub bool);
464
465#[derive(Debug, Clone, Copy, PartialEq, Eq)]
469pub struct Gas(u64);
470
471impl Gas {
472 pub const MAX: Self = Gas(u64::MAX);
474
475 pub const CONSTRAINED: Self = Gas(50_000);
479
480 pub const fn new(gas: u64) -> Self {
482 Self(gas)
483 }
484
485 fn try_consume(&mut self) -> Result<(), OutOfGas> {
489 self.0 = self.0.checked_sub(1).ok_or(OutOfGas(0))?;
490 Ok(())
491 }
492}
493
494#[derive(Debug)]
496struct MatchOptions<'a> {
497 pub case_sensitive: CaseSensitive,
502 pub gas: &'a mut Gas,
506}
507
508#[derive(Debug, Clone, PartialEq, Eq)]
513enum MatchStrategy {
514 Literal(Literal),
520 Prefix(Literal),
527 Suffix(Literal),
534 Contains(Literal),
541 Static(bool),
545 Wildmatch(Tokens),
547 }
550
551impl MatchStrategy {
552 fn from_tokens(mut tokens: Tokens) -> Result<Self, ErrorKind> {
554 let s = match tokens.as_mut_slice() {
555 [] => Self::Static(false),
556 [Token::Wildcard] => Self::Static(true),
557 [Token::Literal(literal)] => Self::Literal(std::mem::take(literal)),
558 [Token::Literal(literal), Token::Wildcard] => Self::Prefix(std::mem::take(literal)),
559 [Token::Wildcard, Token::Literal(literal)] => Self::Suffix(std::mem::take(literal)),
560 [Token::Wildcard, Token::Literal(literal), Token::Wildcard] => {
561 Self::Contains(std::mem::take(literal))
562 }
563 _ => Self::Wildmatch(tokens),
564 };
565
566 Ok(s)
567 }
568
569 pub fn is_match(&self, haystack: &str, options: MatchOptions) -> Result<bool, OutOfGas> {
571 match &self {
572 MatchStrategy::Literal(literal) => Ok(match_literal(literal, haystack, options)),
573 MatchStrategy::Prefix(prefix) => Ok(match_prefix(prefix, haystack, options)),
574 MatchStrategy::Suffix(suffix) => Ok(match_suffix(suffix, haystack, options)),
575 MatchStrategy::Contains(contains) => Ok(match_contains(contains, haystack, options)),
576 MatchStrategy::Static(matches) => Ok(*matches),
577 MatchStrategy::Wildmatch(tokens) => wildmatch::is_match(haystack, tokens, options),
578 }
579 }
580}
581
582impl fmt::Display for MatchStrategy {
583 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
584 match self {
585 MatchStrategy::Literal(literal) => literal.fmt(f),
586 MatchStrategy::Prefix(literal) => {
587 literal.fmt(f)?;
588 f.write_char('*')
589 }
590 MatchStrategy::Suffix(literal) => {
591 f.write_char('*')?;
592 literal.fmt(f)
593 }
594 MatchStrategy::Contains(literal) => {
595 f.write_char('*')?;
596 literal.fmt(f)?;
597 f.write_char('*')
598 }
599 MatchStrategy::Static(true) => f.write_char('*'),
600 MatchStrategy::Static(false) => Ok(()),
602 MatchStrategy::Wildmatch(tokens) => tokens.fmt(f),
603 }
604 }
605}
606
607#[inline(always)]
608fn match_literal(literal: &Literal, haystack: &str, options: MatchOptions) -> bool {
609 if options.case_sensitive == CaseSensitive(false) {
610 wildmatch::is_prefix_case_insensitive(haystack, literal)
615 .is_some_and(|len| len == haystack.len())
616 } else {
617 literal.as_case_converted_str() == haystack
618 }
619}
620
621#[inline(always)]
622fn match_prefix(prefix: &Literal, haystack: &str, options: MatchOptions) -> bool {
623 if options.case_sensitive == CaseSensitive(false) {
624 wildmatch::is_prefix_case_insensitive(haystack, prefix).is_some()
625 } else {
626 haystack.starts_with(prefix.as_case_converted_str())
627 }
628}
629
630#[inline(always)]
631fn match_suffix(suffix: &Literal, haystack: &str, options: MatchOptions) -> bool {
632 if options.case_sensitive == CaseSensitive(false) {
633 let mut suffix = suffix.as_case_converted_str().chars().rev();
634 let mut haystack = haystack.chars().flat_map(|c| c.to_lowercase()).rev();
635
636 loop {
637 match (suffix.next(), haystack.next()) {
638 (None, _) => break true,
640 (Some(_), None) => break false,
642 (Some(s), Some(h)) if s != h => break false,
643 _ => {}
644 }
645 }
646 } else {
647 haystack.ends_with(suffix.as_case_converted_str())
648 }
649}
650
651#[inline(always)]
652fn match_contains(contains: &Literal, haystack: &str, options: MatchOptions) -> bool {
653 if options.case_sensitive == CaseSensitive(false) {
654 let haystack = haystack.to_lowercase();
655 memchr::memmem::find(haystack.as_bytes(), contains.as_case_converted_bytes()).is_some()
656 } else {
657 memchr::memmem::find(haystack.as_bytes(), contains.as_case_converted_bytes()).is_some()
658 }
659}
660
661struct Parser<'a> {
662 chars: std::iter::Peekable<std::str::Chars<'a>>,
663 tokens: Tokens,
664 alternates: Option<Vec<Tokens>>,
665 current_literal: Option<String>,
666 case_sensitive: CaseSensitive,
667 complexity: u64,
668}
669
670impl<'a> Parser<'a> {
671 fn new(pattern: &'a str, case_sensitive: CaseSensitive) -> Self {
672 Self {
673 chars: pattern.chars().peekable(),
674 tokens: Default::default(),
675 alternates: None,
676 current_literal: None,
677 case_sensitive,
678 complexity: 0,
679 }
680 }
681
682 fn parse(&mut self) -> Result<(), ErrorKind> {
683 while let Some(c) = self.advance() {
684 match c {
685 '?' => self.push_token(Token::Any(NonZeroUsize::MIN)),
686 '*' => self.push_token(Token::Wildcard),
687 '[' => self.parse_class()?,
688 ']' => return Err(ErrorKind::UnbalancedCharacterClass),
689 '{' => self.start_alternates()?,
690 '}' => self.end_alternates()?,
691 '\\' => match self.advance() {
692 Some(c) => self.push_literal(c),
693 None => return Err(ErrorKind::DanglingEscape),
694 },
695 ',' if self.alternates.is_some() => {
696 self.finish_literal();
697 let alternates = self.alternates.as_mut().unwrap();
699 alternates.push(Tokens::default());
700 }
701 c => self.push_literal(c),
702 }
703 }
704
705 self.finish_literal();
707
708 Ok(())
709 }
710
711 fn start_alternates(&mut self) -> Result<(), ErrorKind> {
712 if self.alternates.is_some() {
713 return Err(ErrorKind::NestedAlternates);
714 }
715 self.finish_literal();
716 self.alternates = Some(vec![Tokens::default()]);
717 Ok(())
718 }
719
720 fn end_alternates(&mut self) -> Result<(), ErrorKind> {
721 self.finish_literal();
722 match self.alternates.take() {
723 None => return Err(ErrorKind::UnbalancedAlternates),
724 Some(alternates) => {
725 if !alternates.is_empty() {
726 self.complexity = self
727 .complexity
728 .max(1)
729 .saturating_mul(alternates.len() as u64);
730 self.push_token(Token::Alternates(alternates));
731 }
732 }
733 }
734
735 Ok(())
736 }
737
738 fn parse_class(&mut self) -> Result<(), ErrorKind> {
739 let negated = self.advance_if(|c| c == '!');
740
741 let mut ranges = Ranges::default();
742
743 let mut first = true;
744 let mut in_range = false;
745 loop {
746 let Some(c) = self.advance() else {
747 return Err(ErrorKind::UnbalancedCharacterClass);
748 };
749
750 match c {
751 '[' => return Err(ErrorKind::InvalidCharacterClass),
753 ']' => break,
754 '-' => {
755 if first {
756 ranges.push(Range::single('-'));
757 } else if in_range {
758 ranges.last_mut().unwrap().set_end('-')?;
761 in_range = false;
762 } else {
763 assert!(!ranges.is_empty());
764 in_range = true;
765 }
766 }
767 c => {
768 let c = match c {
769 '\\' => self.advance().ok_or(ErrorKind::DanglingEscape)?,
770 c => c,
771 };
772
773 if in_range {
774 ranges.last_mut().unwrap().set_end(c)?;
777 in_range = false;
778 } else {
779 ranges.push(Range::single(c))
780 }
781 }
782 }
783
784 first = false;
785 }
786
787 if in_range {
788 ranges.push(Range::single('-'));
790 }
791
792 self.push_token(Token::Class { negated, ranges });
793
794 Ok(())
795 }
796
797 fn push_literal(&mut self, c: char) {
801 self.current_literal.get_or_insert_with(String::new).push(c);
802 }
803
804 fn finish_literal(&mut self) {
806 if let Some(literal) = self.current_literal.take() {
807 self.push_token(Token::Literal(Literal::new(literal, self.case_sensitive)));
808 }
809 }
810
811 fn push_token(&mut self, token: Token) {
813 self.finish_literal();
814 match self.alternates.as_mut() {
815 Some(alternates) => match alternates.last_mut() {
816 Some(tokens) => tokens.push(token),
817 None => {
818 let mut tokens = Tokens::default();
819 tokens.push(token);
820 alternates.push(tokens);
821 }
822 },
823 None => self.tokens.push(token),
824 }
825 }
826
827 fn advance(&mut self) -> Option<char> {
828 self.chars.next()
829 }
830
831 fn advance_if(&mut self, matcher: impl FnOnce(char) -> bool) -> bool {
832 if self.peek().is_some_and(matcher) {
833 let _ = self.advance();
834 true
835 } else {
836 false
837 }
838 }
839
840 fn peek(&mut self) -> Option<char> {
841 self.chars.peek().copied()
842 }
843}
844
845#[derive(Clone, Debug, Default, PartialEq, Eq)]
855struct Tokens(Vec<Token>);
856
857impl Tokens {
858 fn push(&mut self, mut token: Token) {
859 if let Token::Alternates(mut alternates) = token {
861 let mut contains_empty = false;
862 let mut contains_wildcard = false;
863 alternates.retain_mut(|alternate| {
864 if alternate.0.is_empty() {
865 contains_empty = true;
866 return false;
867 }
868
869 if matches!(alternate.0.as_slice(), [Token::Wildcard]) {
870 contains_wildcard = true;
871 }
872
873 true
874 });
875
876 if contains_wildcard {
883 token = Token::Wildcard;
885 } else if alternates.len() == 1 {
886 if contains_empty {
887 token = Token::Optional(alternates.remove(0));
889 } else {
890 for t in alternates.remove(0).0 {
893 self.push(t);
894 }
895 return;
896 }
897 } else if alternates.len() > 1 {
898 if contains_empty {
899 token = Token::OptionalAlternates(alternates);
901 } else {
902 token = Token::Alternates(alternates);
904 }
905 } else {
906 return;
908 }
909 }
910
911 match (self.0.last_mut(), token) {
912 (Some(Token::Any(n)), Token::Any(n2)) => *n = n.saturating_add(n2.get()),
914 (Some(Token::Wildcard), Token::Wildcard) => {}
917 (Some(Token::Wildcard), Token::Optional(_) | Token::OptionalAlternates(_)) => {}
919 (Some(Token::Optional(_) | Token::OptionalAlternates(_)), Token::Wildcard) => {
920 self.0.pop();
921 while let Some(Token::Optional(_) | Token::OptionalAlternates(_)) = self.0.last() {
923 self.0.pop();
924 }
925 self.0.push(Token::Wildcard);
926 }
927 (Some(Token::Literal(last)), Token::Literal(s)) => last.push(&s),
929 (_, Token::Class { negated: _, ranges }) if ranges.is_empty() => {}
931 (_, token) => self.0.push(token),
933 }
934 }
935
936 fn as_mut_slice(&mut self) -> &mut [Token] {
937 self.0.as_mut_slice()
938 }
939
940 fn as_slice(&self) -> &[Token] {
941 self.0.as_slice()
942 }
943}
944
945impl fmt::Display for Tokens {
946 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
947 for token in &self.0 {
948 token.fmt(f)?;
949 }
950
951 Ok(())
952 }
953}
954
955#[derive(Clone, Debug, PartialEq, Eq)]
957enum Token {
958 Literal(Literal),
960 Any(NonZeroUsize),
962 Wildcard,
964 Class { negated: bool, ranges: Ranges },
966 Alternates(Vec<Tokens>),
968 OptionalAlternates(Vec<Tokens>),
973 Optional(Tokens),
978}
979
980impl fmt::Display for Token {
981 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
982 match self {
983 Token::Literal(literal) => literal.fmt(f),
984 Token::Any(num) => {
985 for _ in 0..num.get() {
986 f.write_char('?')?;
987 }
988 Ok(())
989 }
990 Token::Wildcard => f.write_char('*'),
991 Token::Class { negated, ranges } => {
992 f.write_char('[')?;
993 if *negated {
994 f.write_char('!')?;
995 }
996 ranges.fmt(f)?;
997 f.write_char(']')
998 }
999 Token::Alternates(items) => {
1000 f.write_char('{')?;
1001 let mut is_first = true;
1002 for item in items {
1003 if !is_first {
1004 f.write_char(',')?;
1005 } else {
1006 is_first = false;
1007 }
1008 item.fmt(f)?;
1009 }
1010 f.write_char('}')
1011 }
1012 Token::OptionalAlternates(items) => {
1013 f.write_char('{')?;
1014 for item in items {
1015 item.fmt(f)?;
1016 f.write_char(',')?;
1019 }
1020 f.write_char('}')
1021 }
1022 Token::Optional(tokens) => {
1023 f.write_char('{')?;
1024 tokens.fmt(f)?;
1025 f.write_char(',')?;
1026 f.write_char('}')
1027 }
1028 }
1029 }
1030}
1031
1032#[derive(Clone, Debug, Default, PartialEq, Eq)]
1038struct Literal(String);
1039
1040impl Literal {
1041 fn new(s: String, case_sensitive: CaseSensitive) -> Self {
1043 match case_sensitive {
1044 CaseSensitive(true) => Self(s),
1045 CaseSensitive(false) => Self(s.to_lowercase()),
1046 }
1047 }
1048
1049 fn push(&mut self, Literal(other): &Literal) {
1053 self.0.push_str(other);
1054 }
1055
1056 fn as_case_converted_str(&self) -> &str {
1058 &self.0
1059 }
1060
1061 fn as_case_converted_bytes(&self) -> &[u8] {
1063 self.as_case_converted_str().as_bytes()
1064 }
1065}
1066
1067impl fmt::Display for Literal {
1068 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1069 fn print_escaped_char(c: char, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1070 if matches!(c, '*' | '?' | '[' | ']' | '{' | '}' | '\\' | ',') {
1073 f.write_char('\\')?;
1074 }
1075 f.write_char(c)
1076 }
1077
1078 for c in self.0.chars() {
1079 print_escaped_char(c, f)?;
1080 }
1081 Ok(())
1082 }
1083}
1084
1085#[derive(Clone, Debug, Default, PartialEq, Eq)]
1091enum Ranges {
1092 #[default]
1096 Empty,
1097 Single(Range),
1101 Multiple(Vec<Range>),
1106}
1107
1108impl Ranges {
1109 fn push(&mut self, range: Range) {
1114 match self {
1115 Self::Empty => *self = Self::Single(range),
1116 Self::Single(single) => *self = Self::Multiple(vec![*single, range]),
1117 Self::Multiple(v) => v.push(range),
1118 }
1119 }
1120
1121 fn last_mut(&mut self) -> Option<&mut Range> {
1123 match self {
1124 Ranges::Empty => None,
1125 Ranges::Single(range) => Some(range),
1126 Ranges::Multiple(ranges) => ranges.last_mut(),
1127 }
1128 }
1129
1130 fn is_empty(&self) -> bool {
1132 match self {
1133 Ranges::Empty => true,
1134 Ranges::Single(_) => false,
1135 Ranges::Multiple(ranges) => {
1136 debug_assert!(!ranges.is_empty());
1138 ranges.is_empty()
1139 }
1140 }
1141 }
1142
1143 #[inline(always)]
1145 fn contains(&self, c: char) -> bool {
1146 match self {
1149 Self::Empty => false,
1150 Self::Single(range) => range.contains(c),
1151 Self::Multiple(ranges) => ranges.iter().any(|range| range.contains(c)),
1152 }
1153 }
1154}
1155
1156impl fmt::Display for Ranges {
1157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1158 match self {
1159 Ranges::Empty => Ok(()),
1160 Ranges::Single(range) => range.fmt(f),
1161 Ranges::Multiple(ranges) => {
1162 for range in ranges {
1163 range.fmt(f)?;
1164 }
1165 Ok(())
1166 }
1167 }
1168 }
1169}
1170
1171#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1173struct Range {
1174 start: char,
1175 end: char,
1176}
1177
1178impl Range {
1179 fn single(c: char) -> Self {
1181 Self { start: c, end: c }
1182 }
1183
1184 fn set_end(&mut self, end: char) -> Result<(), ErrorKind> {
1189 if self.start > end {
1190 return Err(ErrorKind::InvalidRange(self.start, end));
1191 }
1192 self.end = end;
1193 Ok(())
1194 }
1195
1196 #[inline(always)]
1198 fn contains(&self, c: char) -> bool {
1199 self.start <= c && c <= self.end
1200 }
1201}
1202
1203impl fmt::Display for Range {
1204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1205 fn print_escaped_char(c: char, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1206 if matches!(c, '[' | ']' | '\\' | '!' | '-') {
1210 f.write_char('\\')?;
1211 }
1212 f.write_char(c)
1213 }
1214
1215 print_escaped_char(self.start, f)?;
1216 if self.start != self.end {
1217 f.write_char('-')?;
1218 print_escaped_char(self.end, f)?;
1219 }
1220 Ok(())
1221 }
1222}
1223
1224#[cfg(test)]
1225mod tests {
1226 use super::*;
1227
1228 #[track_caller]
1229 fn build_pattern(p: &str, options: &str) -> Pattern {
1230 let mut pattern = Pattern::builder(p);
1231 for opt in options.chars() {
1232 match opt {
1233 'i' => drop(pattern.case_insensitive(true)),
1234 _ => unimplemented!("{opt} not implemented"),
1235 }
1236 }
1237 pattern.build().unwrap()
1238 }
1239
1240 #[track_caller]
1241 fn build_patterns(patterns: &[&str], options: &str) -> Patterns {
1242 let mut builder = Patterns::builder();
1243 for opt in options.chars() {
1244 match opt {
1245 'i' => drop(builder.case_insensitive(true)),
1246 _ => unimplemented!("{opt} not implemented"),
1247 }
1248 }
1249 let mut builder = builder.patterns();
1250 for pattern in patterns {
1251 builder.add(pattern).unwrap();
1252 }
1253 builder.build()
1254 }
1255
1256 macro_rules! pattern {
1257 ($pattern:expr $(,$options:tt)?) => {
1258 build_pattern($pattern, stringify!($($options)?))
1259 };
1260 }
1261
1262 macro_rules! patterns {
1263 ($($pattern:expr),* $(,)?) => {
1264 build_patterns(&[$($pattern),*], "")
1265 };
1266 ($($pattern:expr,)* @ $options:tt) => {
1267 build_patterns(&[$($pattern),*], stringify!($options))
1268 };
1269 }
1270
1271 macro_rules! assert_pattern {
1272 ($pattern:expr, $s:expr $(,$options:tt)?) => {{
1273 let pattern = pattern!($pattern $(,$options)?);
1274 assert!(
1275 pattern.is_match($s, Gas::MAX).unwrap(),
1276 "expected pattern '{}' to match '{}' - {pattern:?}",
1277 $pattern,
1278 $s
1279 );
1280 let pattern = pattern!(&pattern.to_string() $(,$options)?);
1281 assert!(
1282 pattern.is_match($s, Gas::MAX).unwrap(),
1283 "expected round-tripped pattern '{}' to match '{}' - {pattern:?}",
1284 $pattern,
1285 $s
1286 );
1287 }};
1288 ($pattern:expr, NOT $s:expr $(,$options:tt)?) => {{
1289 let pattern = pattern!($pattern $(,$options)?);
1290 assert!(
1291 !pattern.is_match($s, Gas::MAX).unwrap(),
1292 "expected pattern '{}' to not match '{}' - {pattern:?}",
1293 $pattern,
1294 $s
1295 );
1296 let pattern = pattern!(&pattern.to_string() $(,$options)?);
1297 assert!(
1298 !pattern.is_match($s, Gas::MAX).unwrap(),
1299 "expected round-tripped pattern '{}' to not match '{}' - {pattern:?}",
1300 $pattern,
1301 $s
1302 );
1303 }};
1304 }
1305
1306 macro_rules! assert_strategy {
1307 ($pattern:expr, $expected:pat) => {{
1308 let pattern = Pattern::new($pattern).unwrap();
1309 let kind = match &pattern.strategy {
1310 MatchStrategy::Literal(_) => "Literal",
1311 MatchStrategy::Prefix(_) => "Prefix",
1312 MatchStrategy::Suffix(_) => "Suffix",
1313 MatchStrategy::Contains(_) => "Contains",
1314 MatchStrategy::Static(_) => "Static",
1315 MatchStrategy::Wildmatch(_) => "Wildmatch",
1316 };
1317 assert_eq!(
1318 kind,
1319 stringify!($expected),
1320 "expected pattern '{}' to have strategy '{}' - {pattern:?}",
1321 $pattern,
1322 stringify!($expected)
1323 );
1324 }};
1325 }
1326
1327 macro_rules! assert_invalid {
1328 ($pattern:expr) => {{
1329 if let Ok(pattern) = Pattern::new($pattern) {
1330 assert!(
1331 false,
1332 "expected pattern '{}' to not compile - {pattern:?}",
1333 $pattern
1334 );
1335 }
1336 }};
1337 }
1338
1339 #[test]
1340 fn test_empty() {
1341 assert_pattern!("", NOT "");
1342 assert_pattern!("", NOT "foo");
1343 }
1344
1345 #[test]
1346 fn test_literal() {
1347 assert_pattern!("foo", "foo");
1348 assert_pattern!("foo", NOT "fOo");
1349 assert_pattern!("foo", NOT "FOO");
1350 assert_pattern!(r"f\{\}o", "f{}o");
1351 assert_pattern!(r"f\}o", "f}o");
1352 assert_pattern!(r"f\{o", "f{o");
1353 assert_pattern!(r"f\{b,a,r\}o", "f{b,a,r}o");
1354 assert_pattern!(r"f\\o", r"f\o");
1355 assert_pattern!("fඞo", "fඞo");
1356 }
1357
1358 #[test]
1359 fn test_literal_case_insensitive() {
1360 assert_pattern!("foo", "foo", i);
1361 assert_pattern!("foo", "fOo", i);
1362 assert_pattern!("fOo", "Foo", i);
1363 assert_pattern!("İ", "i\u{307}", i);
1364 assert_pattern!("İ", "i̇", i);
1365 assert_pattern!("İ", NOT "i", i);
1366 assert_pattern!("i", NOT "İ", i);
1367 assert_pattern!("kelvin", "\u{212A}elvin", i);
1368 assert_pattern!("\u{212A}elvin", "kelvin", i);
1369 assert_pattern!("ß", "ẞ", i);
1370 assert_pattern!("straße", "straẞe", i);
1371 assert_pattern!("strasse", NOT "straẞe", i);
1372 assert_pattern!("ΑΣ", NOT "ΑΣ", i);
1373 assert_pattern!("ΑΣ", "ας", i);
1374 assert_pattern!("ΑΣ", NOT "ασ", i);
1375 assert_pattern!("ασ", "ΑΣ", i);
1376 }
1377
1378 #[test]
1379 fn test_literal_strategy() {
1380 assert_strategy!("foo", Literal);
1381 assert_strategy!(r"f\{b,a,r\}o", Literal);
1382 assert_strategy!(r"f\\o", Literal);
1383 assert_strategy!("fඞo", Literal);
1384 }
1385
1386 #[test]
1387 fn test_prefix() {
1388 assert_pattern!("foo*", "foo___");
1389 assert_pattern!("foo*", "foo");
1390 assert_pattern!(r"foo\?*", "foo?___");
1391 assert_pattern!(r"foo\?*", NOT "foox___");
1392 assert_pattern!("foo**", "foo");
1393 assert_pattern!("foo*?*", NOT "foo");
1394 assert_pattern!("foo*?*", "foo_");
1395 assert_pattern!("foo*?*?", "foo_____");
1396 assert_pattern!("foo*?*?", NOT "foo");
1397 assert_pattern!("foo*?*?", "foo__");
1398 assert_pattern!("foo*?*?", "foo_____");
1399 assert_pattern!("foo**", "foo___");
1400 assert_pattern!("foo*?*", "foo___");
1401 assert_pattern!("foo*?*?", "foo___");
1402 assert_pattern!("foo*", "fooඞ");
1403 assert_pattern!("ඞ*", "ඞfoo");
1404 assert_pattern!("foo*", NOT "___");
1405 assert_pattern!("foo*", NOT "fo");
1406 assert_pattern!("foo*", NOT "fob");
1407 assert_pattern!("foo*", NOT "boo");
1408 assert_pattern!("foo*", NOT "Foo");
1409 assert_pattern!("foo*", NOT "FOO___");
1410
1411 assert_pattern!("foo/bar*", "foo/bar___");
1413 assert_pattern!("foo*", "foo/bar___");
1414 assert_pattern!("foo*", NOT "/foo");
1415 }
1416
1417 #[test]
1418 fn test_prefix_case_insensitive() {
1419 assert_pattern!("foo*", "foo___", i);
1420 assert_pattern!("foo*", "fOo___", i);
1421 assert_pattern!("foo*", "FOO___", i);
1422 assert_pattern!("fOo*", "FOO___", i);
1423 assert_pattern!("fOo*", "Foo___", i);
1424
1425 assert_pattern!("İ*", "İ___", i);
1426 assert_pattern!("İ*", "İ", i);
1427 assert_pattern!("İ*", "i̇", i);
1428 assert_pattern!("İ*", "i\u{307}___", i);
1429 assert_pattern!("İ*", NOT "i____", i);
1430
1431 assert_pattern!("kelvin*", "\u{212A}elvin___", i);
1432 assert_pattern!("\u{212A}elvin*", "kelvin___", i);
1433 assert_pattern!("ΑΣ*", NOT "ΑΣ", i);
1434 assert_pattern!("ΑΣ*", "ας___", i);
1435 assert_pattern!("ΑΣ*", NOT "ασ___", i);
1436 assert_pattern!("ασ*", "ΑΣ___", i);
1437 }
1438
1439 #[test]
1440 fn test_prefix_strategy() {
1441 assert_strategy!("foo*", Prefix);
1442 assert_strategy!("foo**", Prefix);
1443 assert_strategy!("foo?*", Wildmatch);
1444 }
1445
1446 #[test]
1447 fn test_suffix() {
1448 assert_pattern!("*foo", "___foo");
1449 assert_pattern!("*foo", "foo");
1450 assert_pattern!(r"*\?foo", "___?foo");
1451 assert_pattern!(r"*\?foo", NOT "___xfoo");
1452 assert_pattern!("**foo", "foo");
1453 assert_pattern!("*?*foo", NOT "foo");
1454 assert_pattern!("*?*foo", "_foo");
1455 assert_pattern!("*?*foo", "_____foo");
1456 assert_pattern!("?*?*foo", NOT "foo");
1457 assert_pattern!("?*?*foo", NOT "_foo");
1458 assert_pattern!("?*?*foo", "__foo");
1459 assert_pattern!("?*?*foo", "_____foo");
1460 assert_pattern!("**foo", "___foo");
1461 assert_pattern!("*?*foo", "___foo");
1462 assert_pattern!("*?*?foo", "__foo");
1463 assert_pattern!("*foo", "ඞfoo");
1464 assert_pattern!("*ඞ", "fooඞ");
1465 assert_pattern!("*foo", NOT "bar");
1466 assert_pattern!("*foo", NOT "fo");
1467 assert_pattern!("*foo", NOT "fob");
1468 assert_pattern!("*foo", NOT "boo");
1469 assert_pattern!("*foo", NOT "Foo");
1470 assert_pattern!("*foo", NOT "___FOO");
1471
1472 assert_pattern!("*foo/bar", "___foo/bar");
1474 assert_pattern!("*bar", "___foo/bar");
1475 assert_pattern!("*foo", NOT "foo/");
1476 }
1477
1478 #[test]
1479 fn test_suffix_case_insensitive() {
1480 assert_pattern!("foo*", "foo___", i);
1481 assert_pattern!("foo*", "fOo___", i);
1482 assert_pattern!("foo*", "FOO___", i);
1483 assert_pattern!("fOo*", "FOO___", i);
1484 assert_pattern!("fOo*", "Foo___", i);
1485
1486 assert_pattern!("*İ", "___İ", i);
1487 assert_pattern!("*İ", "İ", i);
1488 assert_pattern!("*İ", "i̇", i);
1489 assert_pattern!("*İ", "___i\u{307}", i);
1490 assert_pattern!("*İ", NOT "___i", i);
1491 }
1492
1493 #[test]
1494 fn test_suffix_strategy() {
1495 assert_strategy!("*foo", Suffix);
1496 assert_strategy!("**foo", Suffix);
1497 assert_strategy!("*?foo", Wildmatch);
1498 }
1499
1500 #[test]
1501 fn test_contains() {
1502 assert_pattern!("*foo*", "foo");
1503 assert_pattern!(r"*\?foo*", "___?foo___");
1504 assert_pattern!(r"*\?foo*", NOT "___xfoo___");
1505 assert_pattern!("*foo*", "foo___");
1506 assert_pattern!("*foo*", "___foo");
1507 assert_pattern!("*foo*", "___foo___");
1508 assert_pattern!("*foo*", NOT "___fo");
1509 assert_pattern!("*foo*", NOT "oo___");
1510 assert_pattern!("*foo*", NOT "___fo___");
1511 assert_pattern!("*foo*", NOT "fඞo");
1512 assert_pattern!("*foo*", NOT "___fOo___");
1513 assert_pattern!("*foo*", NOT "___FOO___");
1514
1515 assert_pattern!("*foo*", "foo");
1517 assert_pattern!("*foo*", "foo_/_");
1518 assert_pattern!("*foo*", "_/_foo");
1519 assert_pattern!("*foo*", "_/_foo_/_");
1520 assert_pattern!("*f/o*", "_/_f/o_/_");
1521 }
1522
1523 #[test]
1524 fn test_contains_case_insensitive() {
1525 assert_pattern!("*foo*", "foo", i);
1526 assert_pattern!("*foo*", "fOo", i);
1527 assert_pattern!("*fOo*", "Foo", i);
1528 assert_pattern!("*foo*", "___foo___", i);
1529 assert_pattern!("*foo*", "___fOo___", i);
1530 assert_pattern!("*foo*", "___FOO___", i);
1531 assert_pattern!("*fOo*", "___FOO___", i);
1532 assert_pattern!("*fOo*", "___Foo___", i);
1533
1534 assert_pattern!("*İ*", "___İ___", i);
1535 assert_pattern!("*İ*", "İ", i);
1536 assert_pattern!("*İ*", "___İ", i);
1537 assert_pattern!("*İ*", "İ___", i);
1538 assert_pattern!("*İ*", "___İ___", i);
1539 assert_pattern!("*İ*", "i̇", i);
1540 assert_pattern!("*İ*", "___i̇", i);
1541 assert_pattern!("*İ*", "i̇___", i);
1542 assert_pattern!("*İ*", "___i̇___", i);
1543 assert_pattern!("*İ*", "___i\u{307}", i);
1544 assert_pattern!("*İ*", "i\u{307}___", i);
1545 assert_pattern!("*İ*", "___i\u{307}___", i);
1546 assert_pattern!("*İ*", NOT "i", i);
1547 assert_pattern!("*İ*", NOT "i___", i);
1548 assert_pattern!("*İ*", NOT "___i", i);
1549 assert_pattern!("*İ*", NOT "___i___", i);
1550 }
1551
1552 #[test]
1553 fn test_contains_strategy() {
1554 assert_strategy!("*foo*", Contains);
1555 assert_strategy!("**foo**", Contains);
1556 assert_strategy!("*?foo*", Wildmatch);
1557 assert_strategy!("*foo?*", Wildmatch);
1558 assert_strategy!("*foo*?", Wildmatch);
1559 assert_strategy!("?*foo*", Wildmatch);
1560 }
1561
1562 #[test]
1563 fn test_wildcard() {
1564 assert_pattern!("*", "");
1565 assert_pattern!("*", "a");
1566 assert_pattern!("*", "\n");
1567 assert_pattern!("*", "\n\n");
1568 assert_pattern!("*", "\na\n");
1569 assert_pattern!("*", "\na\nb\nc");
1570 assert_pattern!("*", "ඞfooඞfooඞ");
1571
1572 assert_pattern!("*", "/");
1574 assert_pattern!("*", "_/");
1575 assert_pattern!("*", "/_");
1576 assert_pattern!("*", "_/_");
1577 assert_pattern!("*", "/?/?/");
1578 }
1579
1580 #[test]
1581 fn test_wildcard_strategy() {
1582 assert_strategy!("*", Static);
1583 assert_strategy!("{*}", Static);
1584 assert_strategy!("{*,}", Static);
1585 assert_strategy!("{foo,*}", Static);
1586 assert_strategy!("{foo,*}?{*,bar}", Wildmatch);
1587 assert_strategy!("{*,}?{*,}", Wildmatch);
1588 }
1589
1590 #[test]
1591 fn test_any() {
1592 assert_pattern!("?", NOT "");
1593 assert_pattern!("?", "ඞ");
1594 assert_pattern!("?", "?");
1595 assert_pattern!("?", "\n");
1596 assert_pattern!("?", "_");
1597 assert_pattern!("?", NOT "aa");
1598 assert_pattern!("?", NOT "aaaaaaaaaaaaaaaaaa");
1599 assert_pattern!("??", "aa");
1600 assert_pattern!("??", NOT "aaa");
1601 assert_pattern!("a?a?a", "aaaaa");
1602 assert_pattern!("a?a?a", "abaca");
1603 assert_pattern!("a?a?a", NOT "ab_ca");
1604 assert_pattern!("a?a?a", NOT "aaAaa");
1605 assert_pattern!("???????????x???????????", "???????????x???????????");
1606 assert_pattern!("???????????x???????????", "??______???x?????_?????");
1607 assert_pattern!("???????????x???????????", NOT "?______???x?????_?????");
1608 assert_pattern!("???????????x???????????", NOT "??______???_?????_?????");
1609 assert_pattern!(
1610 "??????????????????????????????????????????????????",
1611 "?????????????????????????????????????????????????!"
1612 );
1613 assert_pattern!("foo?bar", "foo?bar");
1614 assert_pattern!("foo?bar", "foo!bar");
1615 assert_pattern!("a??a", "aඞඞa");
1616
1617 assert_pattern!("?", "/");
1619 }
1620
1621 #[test]
1622 fn test_any_wildcard() {
1623 assert_pattern!("??*", NOT "");
1624 assert_pattern!("??*", NOT "a");
1625 assert_pattern!("??*", "ab");
1626 assert_pattern!("??*", "abc");
1627 assert_pattern!("??*", "abcde");
1628
1629 assert_pattern!("*??", NOT "");
1630 assert_pattern!("*??", NOT "a");
1631 assert_pattern!("*??", "ab");
1632 assert_pattern!("*??", "abc");
1633 assert_pattern!("*??", "abcde");
1634
1635 assert_pattern!("*??*", NOT "");
1636 assert_pattern!("*??*", NOT "a");
1637 assert_pattern!("*??*", "ab");
1638 assert_pattern!("*??*", "abc");
1639 assert_pattern!("*??*", "abcde");
1640
1641 assert_pattern!("*?*?*", NOT "");
1642 assert_pattern!("*?*?*", NOT "a");
1643 assert_pattern!("*?*?*", "ab");
1644 assert_pattern!("*?*?*", "abc");
1645 assert_pattern!("*?*?*", "abcde");
1646 }
1647
1648 #[test]
1649 fn test_escapes() {
1650 assert_pattern!(r"f\\o", r"f\o");
1651 assert_pattern!(r"f\*o", r"f*o");
1652 assert_pattern!(r"f\*o", NOT r"f\*o");
1653 assert_pattern!(r"f\?o", "f?o");
1654 assert_pattern!(r"f\?o", NOT "fao");
1655 assert_pattern!(r"f\\*o", r"f\*o");
1656 assert_pattern!(r"f\\*o", r"f\o");
1657 assert_pattern!(r"f\\*o", r"f\___o");
1658 assert_pattern!(r"f\\\*o", r"f\*o");
1659 assert_pattern!(r"f\[\]o", r"f[]o");
1660 assert_pattern!(r"f\[?\]o", r"f[?]o");
1661 assert_pattern!(r"f\[a-z\]o", r"f[a-z]o");
1662 assert_pattern!(r"f\[o", r"f[o");
1663 assert_pattern!(r"f\]o", r"f]o");
1664 assert_pattern!(r"f\,o", "f,o");
1665 assert_pattern!(r"\[", r"[");
1666 }
1667
1668 #[test]
1669 fn test_invalid() {
1670 assert_invalid!(r"\");
1671 assert_invalid!(r"f\");
1672 assert_invalid!(r"*\");
1673 assert_invalid!("[");
1674 assert_invalid!("[a-z");
1675 assert_invalid!(r"[a-z\");
1676 assert_invalid!("[[]");
1677 assert_invalid!("[]]");
1678 assert_invalid!("]");
1679 assert_invalid!("[a-z");
1680 assert_invalid!("[b-a]");
1681 assert_invalid!("[a-A]");
1682 assert_invalid!("{a,b,{c,d}}");
1683 }
1684
1685 #[test]
1686 fn test_classes() {
1687 assert_pattern!("[]", NOT "");
1688 assert_pattern!("[]", NOT "_");
1689 assert_pattern!("[a]", "a");
1690 assert_pattern!("[a]", NOT "[a]");
1691 assert_pattern!("[a]", NOT "b");
1692 assert_pattern!("[a]", NOT "A");
1693 assert_pattern!("[ඞ]", "ඞ");
1694 assert_pattern!("[ඞ]", NOT "a");
1695 assert_pattern!("[ඞa]", "a");
1696 assert_pattern!("[aඞ]", "ඞ");
1697 assert_pattern!("[ඞa]", NOT "b");
1698 assert_pattern!("[ab]", "a");
1699 assert_pattern!("[ab]", "b");
1700 assert_pattern!("[ab]", NOT "c");
1701 assert_pattern!("x[ab]x", "xax");
1702 assert_pattern!("x[ab]x", "xbx");
1703 assert_pattern!("x[ab]x", NOT "xBx");
1704 assert_pattern!("x[ab]x", NOT "xcx");
1705 assert_pattern!("x[ab]x", NOT "aax");
1706 assert_pattern!("x[ab]x", NOT "xaa");
1707 assert_pattern!("x[ab]x", NOT "xaax");
1708 assert_pattern!("x[ab]x", NOT "xxax");
1709 assert_pattern!("x[ab]x", NOT "xaxx");
1710 assert_pattern!("[a-b]", "a");
1711 assert_pattern!("[a-b]", "b");
1712 assert_pattern!("[a-b]", NOT "c");
1713 assert_pattern!("[a-c]", "a");
1714 assert_pattern!("[a-c]", "b");
1715 assert_pattern!("[a-c]", "c");
1716 assert_pattern!("[a-c]", NOT "d");
1717 assert_pattern!("[a-c]", NOT "1");
1718 assert_pattern!("[a-c]", NOT "ඞ");
1719 assert_pattern!("[A-z]", "a");
1720 assert_pattern!("[A-z]", "z");
1721 assert_pattern!("[A-z]", "["); assert_pattern!("[A-z]", "A");
1723 assert_pattern!("[A-z]", "Z");
1724 assert_pattern!("[A-z]", NOT "0");
1725 assert_pattern!("[0-9]", "0");
1726 assert_pattern!("[0-9]", "1");
1727 assert_pattern!("[0-9]", "2");
1728 assert_pattern!("[0-9]", "3");
1729 assert_pattern!("[0-9]", "4");
1730 assert_pattern!("[0-9]", "5");
1731 assert_pattern!("[0-9]", "6");
1732 assert_pattern!("[0-9]", "7");
1733 assert_pattern!("[0-9]", "8");
1734 assert_pattern!("[0-9]", "9");
1735 assert_pattern!(
1736 "[0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF]",
1737 "3bYf"
1738 );
1739 assert_pattern!(
1740 "[0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF]",
1741 NOT "3cYf"
1742 );
1743 assert_pattern!(
1744 "[0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF][0-9a-bX-ZfF]",
1745 NOT "3ඞYf"
1746 );
1747 assert_pattern!("[0-9]", NOT "a9");
1748 assert_pattern!("[0-9]", NOT "9a");
1749 assert_pattern!("[0-9]", NOT "a9a");
1750 assert_pattern!("[0-9]", NOT "");
1751 assert_pattern!("[0-9!]", "!");
1752 assert_pattern!("[0-9][a-b]", NOT "");
1753 assert_pattern!("[0-9][a-b]", NOT "a");
1754 assert_pattern!("[0-9][a-b]", NOT "a0");
1755 assert_pattern!("[0-9][a-b]", "0a");
1756 assert_pattern!(r"a[\]a\-]b", "aab");
1757
1758 assert_pattern!(r"[\\]", r"\");
1766 assert_pattern!(r"[\\]", NOT "a");
1767 assert_pattern!(r"[\]]", "]");
1768 assert_pattern!(r"[\]]", NOT "a");
1769 assert_pattern!(r"[\[]", "[");
1770 assert_pattern!(r"[\[]", NOT "a");
1771 assert_pattern!(r"[\]]", NOT r"\");
1772 assert_pattern!(r"[\!]", "!");
1773 assert_pattern!(r"[\!]", NOT "a");
1774 assert_pattern!(r"[a\-c]", "-");
1775 assert_pattern!(r"[a\-c]", NOT "b");
1776 assert_pattern!(r"[\!--]", "!");
1777 assert_pattern!(r"[\!--]", "-");
1778 assert_pattern!(r"[\!--]", NOT "a");
1779 assert_pattern!(r"[\[-a]", "[");
1780 assert_pattern!(r"[\[-a]", "a");
1781 assert_pattern!(r"[\[-a]", NOT "b");
1782 assert_pattern!(r"[A-\]]", "]");
1783 assert_pattern!(r"[A-\]]", "Z");
1784 assert_pattern!(r"[A-\]]", NOT "a");
1785 assert_pattern!(r"[A-\\]", r"\");
1786 assert_pattern!(r"[A-\\]", NOT "a");
1787 assert_pattern!(r"[\]-z]", "]");
1788 assert_pattern!(r"[\]-z]", "z");
1789 assert_pattern!(r"[\]-z]", NOT r"\");
1790 assert_pattern!(r"[\\-z]", r"\");
1791 assert_pattern!(r"[\\-z]", "z");
1792 assert_pattern!(r"[\\-z]", NOT "[");
1793 assert_pattern!(r"[\--z]", "-");
1794 assert_pattern!(r"[\--z]", "z");
1795 assert_pattern!(r"[\--z]", NOT "!");
1796 assert_pattern!("[*?{},]", "*");
1797 assert_pattern!("[*?{},]", "?");
1798 assert_pattern!("[*?{},]", "{");
1799 assert_pattern!("[*?{},]", "}");
1800 assert_pattern!("[*?{},]", ",");
1801 assert_pattern!("[*?{},]", NOT "a");
1802
1803 assert_pattern!("a[X-]b", "a-b");
1804 assert_pattern!("a[X-]b", "aXb");
1805 }
1806
1807 #[test]
1808 fn test_classes_case_insensitive() {
1809 assert_pattern!("[a]", "a", i);
1810 assert_pattern!("[a]", "A", i);
1811 assert_pattern!("x[ab]x", "xAX", i);
1812 assert_pattern!("x[ab]x", "XBx", i);
1813 assert_pattern!("x[ab]x", NOT "Xcx", i);
1814 assert_pattern!("x[ab]x", NOT "aAx", i);
1815 assert_pattern!("x[ab]x", NOT "xAa", i);
1816 assert_pattern!("[ǧ]", "Ǧ", i);
1817 assert_pattern!("[Ǧ]", "ǧ", i);
1818 }
1819
1820 #[test]
1821 fn test_classes_negated() {
1822 assert_pattern!("[!]", NOT "");
1823 assert_pattern!(r"[!\!]", "a");
1824 assert_pattern!(r"[!\!]", NOT "!");
1825 assert_pattern!("[!a]", "b");
1826 assert_pattern!("[!a]", "A");
1827 assert_pattern!("[!a]", "B");
1828 assert_pattern!("[!b]", NOT "b");
1829 assert_pattern!("[!ab]", NOT "a");
1830 assert_pattern!("[!ab]", NOT "b");
1831 assert_pattern!("[!ab]", "c");
1832 assert_pattern!("x[!ab]x", "xcx");
1833 assert_pattern!("x[!ab]x", NOT "xax");
1834 assert_pattern!("x[!ab]x", NOT "xbx");
1835 assert_pattern!("x[!ab]x", NOT "xxcx");
1836 assert_pattern!("x[!ab]x", NOT "xcxx");
1837 assert_pattern!("x[!ab]x", NOT "xc");
1838 assert_pattern!("x[!ab]x", NOT "cx");
1839 assert_pattern!("x[!ab]x", NOT "x");
1840 assert_pattern!("[!a-c]", NOT "a");
1841 assert_pattern!("[!a-c]", NOT "b");
1842 assert_pattern!("[!a-c]", NOT "c");
1843 assert_pattern!("[!a-c]", "d");
1844 assert_pattern!("[!a-c]", "A");
1845 assert_pattern!("[!a-c]", "ඞ");
1846 assert_pattern!(r"[!a-c\\]", "d");
1847 assert_pattern!(r"[!a-c\\]", NOT r"\");
1848 assert_pattern!(r"[!\]]", "a");
1849 assert_pattern!(r"[!\]]", NOT "]");
1850 assert_pattern!(r"[!!]", "a");
1851 assert_pattern!(r"[!!]", NOT "!");
1852 }
1853
1854 #[test]
1855 fn test_classes_negated_case_insensitive() {
1856 assert_pattern!("[!a]", "b", i);
1857 assert_pattern!("[!a]", "B", i);
1858 assert_pattern!("[!b]", NOT "b", i);
1859 assert_pattern!("[!b]", NOT "B", i);
1860 assert_pattern!("[!ab]", NOT "a", i);
1861 assert_pattern!("[!ab]", NOT "A", i);
1862 assert_pattern!("[!ab]", NOT "b", i);
1863 assert_pattern!("[!ab]", NOT "B", i);
1864 assert_pattern!("[!ab]", "c", i);
1865 assert_pattern!("[!ab]", "C", i);
1866 }
1867
1868 #[test]
1869 fn test_alternates() {
1870 assert_pattern!("{}foo{}", "foo");
1871 assert_pattern!("foo{}bar", "foobar");
1872 assert_pattern!("foo{}{}bar", "foobar");
1873 assert_pattern!("{foo}", "foo");
1874 assert_pattern!("{foo}", NOT "fOo");
1875 assert_pattern!("{foo}", NOT "bar");
1876 assert_pattern!("{foo,bar}", "foo");
1877 assert_pattern!("{foo,bar}", "bar");
1878 assert_pattern!(r"{foo,bar,baz\,}", "foo");
1879 assert_pattern!(r"{foo,bar,baz\,}", "baz,");
1880 assert_pattern!(r"{foo,bar,baz\,}", NOT "baz");
1881 assert_pattern!(r"{foo,bar,baz\,}", NOT "");
1882 assert_pattern!(r"{foo\,,}", "foo,");
1883 assert_pattern!(r"{foo\,,}", "");
1884 assert_pattern!(r"{foo\,,}", NOT "foo");
1885 assert_pattern!(r"{foo,bar\,,}", "bar,");
1886 assert_pattern!(r"{foo,bar\,,}", "");
1887 assert_pattern!(r"{foo,bar\,,}", NOT "bar");
1888 assert_pattern!("{foo,bar}", NOT "Foo");
1889 assert_pattern!("{foo,bar}", NOT "fOo");
1890 assert_pattern!("{foo,bar}", NOT "BAR");
1891 assert_pattern!("{foo,bar}", NOT "fooo");
1892 assert_pattern!("{foo,bar}", NOT "baar");
1893 assert_pattern!("{foo,bar,}baz", "foobaz");
1894 assert_pattern!("{foo,bar,}baz", "barbaz");
1895 assert_pattern!("{foo,bar,}baz", "baz");
1896 assert_pattern!("{foo,,bar}baz", "foobaz");
1897 assert_pattern!("{foo,,bar}baz", "barbaz");
1898 assert_pattern!("{foo,,bar}baz", "baz");
1899 assert_pattern!("{,foo,bar}baz", "foobaz");
1900 assert_pattern!("{,foo,bar}baz", "barbaz");
1901 assert_pattern!("{,foo,bar}baz", "baz");
1902 assert_pattern!("{foo*bar}", "foobar");
1903 assert_pattern!("{foo*bar}", "fooooobar");
1904 assert_pattern!("{foo*bar}", NOT "");
1905 assert_pattern!("{foo*bar,}", "foobar");
1906 assert_pattern!("{foo*bar,}", "fooooobar");
1907 assert_pattern!("{foo*bar,}", "");
1908 assert_pattern!("{foo*bar,baz}", "foobar");
1909 assert_pattern!("{foo*bar,baz}", "fooooobar");
1910 assert_pattern!("{foo*bar,baz}", "baz");
1911 assert_pattern!("{foo*bar,baz}", NOT "");
1912 assert_pattern!("{foo*bar,baz,}", "foobar");
1913 assert_pattern!("{foo*bar,baz,}", "fooooobar");
1914 assert_pattern!("{foo*bar,baz,}", "baz");
1915 assert_pattern!("{foo*bar,baz,}", "");
1916 assert_pattern!("{,,,,}", NOT "");
1917 assert_pattern!("{[fb][oa][or]}", "foo");
1918 assert_pattern!("{[fb][oa][or]}", "bar");
1919 assert_pattern!("{[fb][oa][or],baz}", "foo");
1920 assert_pattern!("{[fb][oa][or],baz}", "bar");
1921 assert_pattern!("{[fb][oa][or],baz}", "baz");
1922 assert_pattern!("{baz,[fb][oa][or]}", "baz");
1923 assert_pattern!("{baz,[fb][oa][or]}", "foo");
1924 assert_pattern!("{baz,[fb][oa][or]}", "bar");
1925 assert_pattern!("{baz,[fb][oa][or]}", "bor");
1926 assert_pattern!("{baz,[fb][oa][or]}", NOT "barr");
1927 assert_pattern!("{baz,[fb][oa][or]}", NOT "boz");
1928 assert_pattern!("{baz,[fb][oa][or]}", NOT "fbar");
1929 assert_pattern!("{baz,[fb][oa][or]}", NOT "bAr");
1930 assert_pattern!("{baz,[fb][oa][or]}", NOT "Foo");
1931 assert_pattern!("{baz,[fb][oa][or]}", NOT "Bar");
1932 assert_pattern!("{baz,b[aA]r}", NOT "bAz");
1933 assert_pattern!("{baz,b[!aA]r}", NOT "bar");
1934 assert_pattern!("{baz,b[!aA]r}", "bXr");
1935 assert_pattern!("{[a-z],[0-9]}", "a");
1936 assert_pattern!("{[a-z],[0-9]}", "3");
1937 assert_pattern!("a{[a-z],[0-9]}a", "a3a");
1938 assert_pattern!("a{[a-z],[0-9]}a", "aba");
1939 assert_pattern!("a{[a-z],[0-9]}a", NOT "aAa");
1940 assert_pattern!("a{[a-z],?}a", "aXa");
1941 assert_pattern!(r"a{[a-z],\?}a", "a?a");
1942 assert_pattern!(r"a{[a-z],\?}a", NOT "aXa");
1943 assert_pattern!(r"a{[a-z],\?}a", NOT r"a\a");
1944 assert_pattern!(r"a{\[\],\{\}}a", "a[]a");
1945 assert_pattern!(r"a{\[\],\{\}}a", "a{}a");
1946 assert_pattern!(r"a{\[\],\{\}}a", NOT "a[}a");
1947 assert_pattern!(r"a{\[\],\{\}}a", NOT "a{]a");
1948 assert_pattern!(r"a{\[\],\{\}}a", NOT "a[a");
1949 assert_pattern!(r"a{\[\],\{\}}a", NOT "a]a");
1950 assert_pattern!(r"a{\[\],\{\}}a", NOT "a{a");
1951 assert_pattern!(r"a{\[\],\{\}}a", NOT "a}a");
1952 assert_pattern!("foo/{*.js,*.html}", "foo/.js");
1953 assert_pattern!("foo/{*.js,*.html}", "foo/.html");
1954 assert_pattern!("foo/{*.js,*.html}", "foo/bar.js");
1955 assert_pattern!("foo/{*.js,*.html}", "foo/bar.html");
1956 assert_pattern!("foo/{*.js,*.html}", NOT "foo/bar.png");
1957 assert_pattern!("foo/{*.js,*.html}", NOT "bar/bar.js");
1958 assert_pattern!("{foo,abc}{def,bar}", "foodef");
1959 assert_pattern!("{foo,abc}{def,bar}", "foobar");
1960 assert_pattern!("{foo,abc}{def,bar}", "abcdef");
1961 assert_pattern!("{foo,abc}{def,bar}", "abcbar");
1962 assert_pattern!("{foo,abc}{def,bar}", NOT "foofoo");
1963 assert_pattern!("{foo,abc}{def,bar}", NOT "fooabc");
1964 assert_pattern!("{foo,abc}{def,bar}", NOT "defdef");
1965 assert_pattern!("{foo,abc}{def,bar}", NOT "defabc");
1966 }
1967
1968 #[test]
1969 fn test_alternates_many() {
1970 const N: usize = 100_000;
1971
1972 let pattern = Pattern::new(&"{ab,ba}".repeat(N)).unwrap();
1973 assert_eq!(pattern.is_match(&"ab".repeat(N), Gas::MAX), Ok(true));
1974 assert_eq!(pattern.is_match(&"ba".repeat(N), Gas::MAX), Ok(true));
1975 assert_eq!(pattern.is_match(&"abba".repeat(N / 2), Gas::MAX), Ok(true));
1976 assert_eq!(pattern.is_match(&"ab".repeat(N - 1), Gas::MAX), Ok(false));
1977 assert_eq!(
1978 pattern.is_match(&format!("{}aa", "ab".repeat(N - 1)), Gas::MAX),
1979 Ok(false)
1980 );
1981 }
1982
1983 #[test]
1984 fn test_alternates_optional() {
1985 assert_pattern!("{a,}{b,}", "ab");
1986 assert_pattern!("{a,}{b,}", "a");
1987 assert_pattern!("{a,}{b,}", "b");
1988 assert_pattern!("{a,}{b,}", "");
1989 assert_pattern!("{a,b,}{c,}", "ac");
1990 assert_pattern!("{a,b,}{c,}", "bc");
1991 assert_pattern!("{a,b,}{c,}", "a");
1992 assert_pattern!("{a,b,}{c,}", "b");
1993 assert_pattern!("{a,b,}{c,}", "c");
1994 assert_pattern!("{a,b,}{c,}", "");
1995 assert_pattern!("{a,b,}{c,}", NOT "ab");
1996 assert_pattern!("{a,b,}{c,}", NOT "abc");
1997 }
1998
1999 #[test]
2000 fn test_alternate_strategy() {
2001 assert_strategy!("{}foo{}", Literal);
2003 assert_strategy!("foo{}bar", Literal);
2004 assert_strategy!("foo{}{}{}bar", Literal);
2005 assert_strategy!("foo{,,,}bar", Literal);
2006 }
2007
2008 #[test]
2009 fn test_optional_wildcard_strategy() {
2010 assert_strategy!("*{foo,}", Static);
2012 assert_strategy!("*{foo,bar,}", Static);
2013 assert_strategy!("foo*{bar,}", Prefix);
2014 assert_strategy!("foo*{bar,baz,}", Prefix);
2015 assert_strategy!("*{foo,}bar", Suffix);
2016 assert_strategy!("*{foo,baz,}bar", Suffix);
2017 assert_strategy!("*{bar,}foo*", Contains);
2018 assert_strategy!("*{bar,baz,}foo*", Contains);
2019
2020 assert_strategy!("{foo,}*", Static);
2022 assert_strategy!("{foo,bar,}*", Static);
2023 assert_strategy!("foo{bar,}*", Prefix);
2024 assert_strategy!("foo{bar,baz,}*", Prefix);
2025 assert_strategy!("{foo,}*bar", Suffix);
2026 assert_strategy!("{foo,baz,}*bar", Suffix);
2027 assert_strategy!("*foo{bar,}*", Contains);
2028 assert_strategy!("*foo{bar,baz,}*", Contains);
2029
2030 assert_strategy!("*{bar,}{baz,qux,}foo", Suffix);
2032 assert_strategy!("{*,bar}{baz,qux,}foo", Suffix);
2033 assert_strategy!("foo{bar,}{baz,qux,}*", Prefix);
2034 assert_strategy!("foo{bar,}{baz,qux,}{bar,*}", Prefix);
2035 }
2036
2037 #[test]
2038 fn test_alternates_case_insensitive() {
2039 assert_pattern!("{foo}", "foo", i);
2040 assert_pattern!("{foo}", "fOo", i);
2041 assert_pattern!("{foo}", NOT "bar", i);
2042 assert_pattern!("{foo,bar}", "foo", i);
2043 assert_pattern!("{foo,bar}", "bar", i);
2044 assert_pattern!("{foo,bar}", "Foo", i);
2045 assert_pattern!("{foo,bar}", "fOo", i);
2046 assert_pattern!("{foo,bar}", "BAR", i);
2047 assert_pattern!("{foo,bar}", NOT "bao", i);
2048 assert_pattern!("{f[o0-9]o,b[a]r}", "foo", i);
2049 assert_pattern!("{f[o0-9]o,b[a]r}", "fOo", i);
2050 assert_pattern!("{f[o0-9]o,b[a]r}", "f1o", i);
2051 assert_pattern!("{f[o0-9]o,b[a]r}", "foO", i);
2052 assert_pattern!("{f[o0-9]o,b[a]r}", "FOO", i);
2053 assert_pattern!("{f[o0-9]o,b[a]r}", "bar", i);
2054 assert_pattern!("{f[o0-9]o,b[a]r}", "bAr", i);
2055 assert_pattern!("{f[o0-9]o,b[a]r}", "baR", i);
2056 assert_pattern!("{f[o0-9]o,b[a]r}", "BAR", i);
2057 assert_pattern!("{f[o0-9]o,b[!a]r}", "foo", i);
2058 assert_pattern!("{f[o0-9]o,b[!a]r}", "bXr", i);
2059 assert_pattern!("{f[o0-9]o,b[!a]r}", NOT "bar", i);
2060 assert_pattern!("{f[o0-9]o,b[!a]r}", NOT "bAr", i);
2061 }
2062
2063 #[test]
2064 fn test_complex() {
2065 assert_pattern!("*?", "\n");
2066 assert_pattern!("?*", "\n");
2067 assert_pattern!("*?*", "\n");
2068 assert_pattern!("1.18.[!0-4].*", "1.18.5.");
2069 assert_pattern!("1.18.[!0-4].*", "1.18.5.aBc");
2070 assert_pattern!("1.18.[!0-4].*", NOT "1.18.3.abc");
2071 assert_pattern!("!*!*.md", "!foo!.md"); assert_pattern!("foo*foofoo*foobar", "foofoofooxfoofoobar");
2073 assert_pattern!("foo*fooFOO*fOobar", "fooFoofooXfoofooBAR", i);
2074 assert_pattern!("[0-9]*a", "0aaaaaaaaa", i);
2075 assert_pattern!("[0-9]*Bar[x]", "0foobarx", i);
2076
2077 assert_pattern!(
2078 r"/api/0/organizations/\{organization_slug\}/event*",
2079 "/api/0/organizations/{organization_slug}/event/foobar"
2080 );
2081 assert_pattern!(
2082 r"/api/0/organizations/\{organization_slug\}/event*",
2083 NOT r"/api/0/organizations/\{organization_slug\}/event/foobar"
2084 );
2085
2086 assert_pattern!(
2087 "*b??{foo,bar,baz,with}*cr{x,y,z,?}zyl[a-z]ng{suffix,pr?*ix}*it?**?uallymatches",
2088 "foobarwithacrazylongprefixandanditactuallymatches"
2089 );
2090 assert_pattern!(
2091 "*b??{foo,bar,baz,with}*cr{x,y,z,?}zyl[a-z]ng{suffix,pr?*ix}*it?**?uallymatches",
2092 "FOOBARWITHACRAZYLONGPREFIXANDANDITACTUALLYMATCHES",
2093 i
2094 );
2095 }
2096
2097 #[test]
2101 fn test_kirk_j_krauss() {
2102 assert_pattern!("Hi*", "Hi");
2104
2105 assert_pattern!("ab*d", NOT "abc");
2107
2108 assert_pattern!("*ccd", "abcccd");
2110 assert_pattern!("*issip*ss*", "mississipissippi");
2111 assert_pattern!("xxxx*zzy*fffff", NOT "xxxx*zzzzzzzzy*f");
2112 assert_pattern!("xxx*zzy*f", "xxxx*zzzzzzzzy*f");
2113 assert_pattern!("xxxx*zzy*fffff", NOT "xxxxzzzzzzzzyf");
2114 assert_pattern!("xxxx*zzy*f", "xxxxzzzzzzzzyf");
2115 assert_pattern!("xy*z*xyz", "xyxyxyzyxyz");
2116 assert_pattern!("*sip*", "mississippi");
2117 assert_pattern!("xy*xyz", "xyxyxyxyz");
2118 assert_pattern!("mi*sip*", "mississippi");
2119 assert_pattern!("*abac*", "ababac");
2120 assert_pattern!("*abac*", "ababac");
2121 assert_pattern!("a*zz*", "aaazz");
2122 assert_pattern!("*12*23", NOT "a12b12");
2123 assert_pattern!("a12b", NOT "a12b12");
2124 assert_pattern!("*12*12*", "a12b12");
2125
2126 assert_pattern!("*a?b", "caaab");
2128
2129 assert_pattern!("*", "*");
2131 assert_pattern!("a*b", "a*abab");
2132 assert_pattern!("a*", "a*r");
2133 assert_pattern!("a*aar", NOT "a*ar");
2134
2135 assert_pattern!("XY*Z*XYz", "XYXYXYZYXYz");
2137 assert_pattern!("*SIP*", "missisSIPpi");
2138 assert_pattern!("*issip*PI", "mississipPI");
2139 assert_pattern!("xy*xyz", "xyxyxyxyz");
2140 assert_pattern!("mi*sip*", "miSsissippi");
2141 assert_pattern!("mi*Sip*", NOT "miSsissippi");
2142 assert_pattern!("*Abac*", "abAbac");
2143 assert_pattern!("*Abac*", "abAbac");
2144 assert_pattern!("a*zz*", "aAazz");
2145 assert_pattern!("*12*23", NOT "A12b12");
2146 assert_pattern!("*12*12*", "a12B12");
2147 assert_pattern!("*oWn*", "oWn");
2148
2149 assert_pattern!("bLah", "bLah");
2151 assert_pattern!("bLaH", NOT "bLah");
2152
2153 assert_pattern!("*?", "a");
2155 assert_pattern!("*?", "ab");
2156 assert_pattern!("*?", "abc");
2157
2158 assert_pattern!("??", NOT "a");
2160 assert_pattern!("?*?", "ab");
2161 assert_pattern!("*?*?*", "ab");
2162 assert_pattern!("?**?*?", "abc");
2163 assert_pattern!("?**?*&?", NOT "abc");
2164 assert_pattern!("?b*??", "abcd");
2165 assert_pattern!("?a*??", NOT "abcd");
2166 assert_pattern!("?**?c?", "abcd");
2167 assert_pattern!("?**?d?", NOT "abcd");
2168 assert_pattern!("?*b*?*d*?", "abcde");
2169
2170 assert_pattern!("bL?h", "bLah");
2172 assert_pattern!("bLa?", NOT "bLaaa");
2173 assert_pattern!("bLa?", "bLah");
2174 assert_pattern!("?Lah", NOT "bLaH");
2175 assert_pattern!("?LaH", "bLaH");
2176
2177 assert_pattern!(
2179 "a*a*a*a*a*a*aa*aaa*a*a*b",
2180 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
2181 );
2182 assert_pattern!(
2183 "*a*b*ba*ca*a*aa*aaa*fa*ga*b*",
2184 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2185 );
2186 assert_pattern!(
2187 "*a*b*ba*ca*a*x*aaa*fa*ga*b*",
2188 NOT "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2189 );
2190 assert_pattern!(
2191 "*a*b*ba*ca*aaaa*fa*ga*gggg*b*",
2192 NOT "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2193 );
2194 assert_pattern!(
2195 "*a*b*ba*ca*aaaa*fa*ga*ggg*b*",
2196 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2197 );
2198 assert_pattern!("*aabbaa*a*", "aaabbaabbaab");
2199 assert_pattern!(
2200 "a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*",
2201 "a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*"
2202 );
2203 assert_pattern!("*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaaaaaaaaa");
2204 assert_pattern!(
2205 "*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*",
2206 NOT "aaaaaaaaaaaaaaaa"
2207 );
2208 assert_pattern!(
2209 "abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*",
2210 NOT "abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn"
2211 );
2212 assert_pattern!(
2213 "abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*",
2214 "abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn"
2215 );
2216 assert_pattern!("abc*abc*abc*abc*abc", NOT "abc*abcd*abcd*abc*abcd");
2217 assert_pattern!(
2218 "abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abcd",
2219 "abc*abcd*abcd*abc*abcd*abcd*abc*abcd*abc*abc*abcd"
2220 );
2221 assert_pattern!("********a********b********c********", "abc");
2222 assert_pattern!("abc", NOT "********a********b********c********");
2223 assert_pattern!("********a********b********b********", NOT "abc");
2224 assert_pattern!("***a*b*c***", "*abc*");
2225
2226 assert_pattern!("*issip*PI", "mississippi", i);
2228
2229 assert_pattern!("?", NOT "");
2231 assert_pattern!("*?", NOT "");
2232 assert_pattern!("", NOT "a");
2234
2235 assert_pattern!("abd", NOT "abc");
2237
2238 assert_pattern!("abcccd", "abcccd");
2240 assert_pattern!("mississipissippi", "mississipissippi");
2241 assert_pattern!("xxxxzzzzzzzzyfffff", NOT "xxxxzzzzzzzzyf");
2242 assert_pattern!("xxxxzzzzzzzzyf", "xxxxzzzzzzzzyf");
2243 assert_pattern!("xxxxzzy.fffff", NOT "xxxxzzzzzzzzyf");
2244 assert_pattern!("xxxxzzzzzzzzyf", "xxxxzzzzzzzzyf");
2245 assert_pattern!("xyxyxyzyxyz", "xyxyxyzyxyz");
2246 assert_pattern!("mississippi", "mississippi");
2247 assert_pattern!("xyxyxyxyz", "xyxyxyxyz");
2248 assert_pattern!("m ississippi", "m ississippi");
2249 assert_pattern!("ababac?", NOT "ababac");
2250 assert_pattern!("ababac", NOT "dababac");
2251 assert_pattern!("aaazz", "aaazz");
2252 assert_pattern!("1212", NOT "a12b12");
2253 assert_pattern!("a12b", NOT "a12b12");
2254 assert_pattern!("a12b12", "a12b12");
2255
2256 assert_pattern!("n", "n");
2258 assert_pattern!("aabab", "aabab");
2259 assert_pattern!("ar", "ar");
2260 assert_pattern!("aaar", NOT "aar");
2261 assert_pattern!("XYXYXYZYXYz", "XYXYXYZYXYz");
2262 assert_pattern!("missisSIPpi", "missisSIPpi");
2263 assert_pattern!("mississipPI", "mississipPI");
2264 assert_pattern!("xyxyxyxyz", "xyxyxyxyz");
2265 assert_pattern!("miSsissippi", "miSsissippi");
2266 assert_pattern!("miSsisSippi", NOT "miSsissippi");
2267 assert_pattern!("abAbac", "abAbac");
2268 assert_pattern!("abAbac", "abAbac");
2269 assert_pattern!("aAazz", "aAazz");
2270 assert_pattern!("A12b123", NOT "A12b12");
2271 assert_pattern!("a12B12", "a12B12");
2272 assert_pattern!("oWn", "oWn");
2273 assert_pattern!("bLah", "bLah");
2274 assert_pattern!("bLaH", NOT "bLah");
2275
2276 assert_pattern!("a", "a");
2278 assert_pattern!("a?", "ab");
2279 assert_pattern!("ab?", "abc");
2280
2281 assert_pattern!("??", NOT "a");
2283 assert_pattern!("??", "ab");
2284 assert_pattern!("???", "abc");
2285 assert_pattern!("????", "abcd");
2286 assert_pattern!("????", NOT "abc");
2287 assert_pattern!("?b??", "abcd");
2288 assert_pattern!("?a??", NOT "abcd");
2289 assert_pattern!("??c?", "abcd");
2290 assert_pattern!("??d?", NOT "abcd");
2291 assert_pattern!("?b?d*?", "abcde");
2292
2293 assert_pattern!(
2295 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
2296 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
2297 );
2298 assert_pattern!(
2299 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",
2300 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2301 );
2302 assert_pattern!(
2303 "abababababababababababababababababababaacacacacacacacadaeafagahaiajaxalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",
2304 NOT "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2305 );
2306 assert_pattern!(
2307 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaggggagaaaaaaaab",
2308 NOT "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2309 );
2310 assert_pattern!(
2311 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",
2312 "abababababababababababababababababababaacacacacacacacadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab"
2313 );
2314 assert_pattern!("aaabbaabbaab", "aaabbaabbaab");
2315 assert_pattern!(
2316 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
2317 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
2318 );
2319 assert_pattern!("aaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaa");
2320 assert_pattern!("aaaaaaaaaaaaaaaaa", NOT "aaaaaaaaaaaaaaaa");
2321 assert_pattern!(
2322 "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc",
2323 NOT "abcabcdabcdeabcdefabcdefgabcdefghabcdefghiabcdefghijabcdefghijkabcdefghijklabcdefghijklmabcdefghijklmn"
2324 );
2325 assert_pattern!(
2326 "abcabcdabcdeabcdefabcdefgabcdefghabcdefghiabcdefghijabcdefghijkabcdefghijklabcdefghijklmabcdefghijklmn",
2327 "abcabcdabcdeabcdefabcdefgabcdefghabcdefghiabcdefghijabcdefghijkabcdefghijklabcdefghijklmabcdefghijklmn"
2328 );
2329 assert_pattern!("abcabc?abcabcabc", NOT "abcabcdabcdabcabcd");
2330 assert_pattern!(
2331 "abcabc?abc?abcabc?abc?abc?bc?abc?bc?bcd",
2332 "abcabcdabcdabcabcdabcdabcabcdabcabcabcd"
2333 );
2334 assert_pattern!("?abc?", "?abc?");
2335 }
2336
2337 #[test]
2338 fn test_builder_complexity() {
2339 assert!(
2340 Pattern::builder("{foo,bar}")
2341 .max_complexity(1)
2342 .build()
2343 .is_err()
2344 );
2345 assert!(
2346 Pattern::builder("{foo,bar}")
2347 .max_complexity(2)
2348 .build()
2349 .is_ok()
2350 );
2351 assert!(
2352 Pattern::builder("{foo,bar}/{*.html,*.js,*.css}")
2353 .max_complexity(5)
2354 .build()
2355 .is_err()
2356 );
2357 assert!(
2358 Pattern::builder("{foo,bar}/{*.html,*.js,*.css}")
2359 .max_complexity(6)
2360 .build()
2361 .is_ok()
2362 );
2363 }
2364
2365 #[test]
2366 fn test_patterns() {
2367 let patterns = patterns!("foobaR", "a*", "*a", "[0-9]*baz");
2368
2369 assert_eq!(patterns.is_match("foobaR", Gas::MAX), Ok(true));
2370 assert_eq!(patterns.is_match("abc", Gas::MAX), Ok(true));
2371 assert_eq!(patterns.is_match("cba", Gas::MAX), Ok(true));
2372 assert_eq!(patterns.is_match("3baz", Gas::MAX), Ok(true));
2373 assert_eq!(patterns.is_match("123456789baz", Gas::MAX), Ok(true));
2374 assert_eq!(patterns.is_match("foobar", Gas::MAX), Ok(false));
2375 assert_eq!(patterns.is_match("FOOBAR", Gas::MAX), Ok(false));
2376 }
2377
2378 #[test]
2379 fn test_patterns_case_insensitive() {
2380 let patterns = patterns!("fOObar", "a*", "*a", "[0-9]*baz", @ i);
2381
2382 assert_eq!(patterns.is_match("FooBar", Gas::MAX), Ok(true));
2383 assert_eq!(patterns.is_match("abC", Gas::MAX), Ok(true));
2384 assert_eq!(patterns.is_match("cbA", Gas::MAX), Ok(true));
2385 assert_eq!(patterns.is_match("3BAZ", Gas::MAX), Ok(true));
2386 assert_eq!(patterns.is_match("123456789baz", Gas::MAX), Ok(true));
2387 assert_eq!(patterns.is_match("b", Gas::MAX), Ok(false));
2388 }
2389
2390 #[test]
2391 fn test_patterns_take_clears_builder() {
2392 let mut builder = Patterns::builder().add("foo").unwrap();
2393
2394 let patterns = builder.take();
2395 assert_eq!(patterns, patterns!("foo"));
2396 assert_eq!(patterns.is_match("foo", Gas::MAX), Ok(true));
2397 assert_eq!(patterns.is_match("bar", Gas::MAX), Ok(false));
2398
2399 builder.add("bar").unwrap();
2400 let patterns = builder.build();
2401 assert_eq!(patterns, patterns!("bar"));
2402 assert_eq!(patterns.is_match("foo", Gas::MAX), Ok(false));
2403 assert_eq!(patterns.is_match("bar", Gas::MAX), Ok(true));
2404 }
2405
2406 #[test]
2407 fn test_pattern_eq() {
2408 let pattern1 = pattern!("Foo**", i);
2409 let pattern2 = pattern!("Foo**", i);
2410 let pattern3 = pattern!("foo*", i);
2411 assert_eq!(&pattern1, &pattern1);
2412 assert_eq!(&pattern1, &pattern2);
2413 assert_eq!(&pattern1, &pattern3);
2414 assert_eq!(&pattern2, &pattern3);
2415
2416 let pattern = Pattern::builder("foo*").max_complexity(1).build().unwrap();
2417 assert_eq!(pattern, Pattern::new("foo*").unwrap());
2418 }
2419
2420 #[test]
2421 fn test_pattern_neq() {
2422 assert_ne!(pattern!("Foo**"), pattern!("foo*"));
2423 assert_ne!(pattern!("foo*"), pattern!("foo*", i));
2424 assert_ne!(pattern!("foo*"), pattern!("bar*"));
2425 }
2426
2427 #[test]
2428 fn test_patterns_eq() {
2429 let patterns1 = patterns!("Foo**", "*[rt]X", @ i);
2430 let patterns2 = patterns1.clone();
2431 let patterns3 = patterns!("foo*", "*[rt]x", @ i);
2432 assert_eq!(&patterns1, &patterns1);
2433 assert_eq!(&patterns1, &patterns2);
2434 assert_eq!(&patterns1, &patterns3);
2435 assert_eq!(&patterns2, &patterns3);
2436 assert_eq!(Patterns::empty(), patterns!());
2437 }
2438
2439 #[test]
2440 fn test_patterns_neq() {
2441 let patterns = patterns!("foo*", "bar");
2442 let case_insensitive = patterns!("foo*", "bar", @ i);
2443 let reordered = patterns!("bar", "foo*");
2444 assert_ne!(patterns, case_insensitive);
2445 assert_ne!(patterns, reordered);
2446 assert_ne!(patterns, patterns!("foo*"));
2447 assert_ne!(patterns, patterns!());
2448 assert_ne!(patterns!(), patterns!(@ i));
2449 }
2450
2451 #[test]
2452 #[cfg(feature = "serde")]
2453 fn test_pattern_deserialize() {
2454 let pattern: Pattern = serde_json::from_str(r#""**[rt]x""#).unwrap();
2455 assert_eq!(pattern, Pattern::new("*[rt]x").unwrap());
2456 assert_eq!(pattern.is_match("foobar_rx", Gas::MAX), Ok(true));
2457 assert_eq!(pattern.is_match("foobar_tx", Gas::MAX), Ok(true));
2458 assert_eq!(pattern.is_match("foobar_RX", Gas::MAX), Ok(false));
2459 assert_eq!(pattern.is_match("foobar", Gas::MAX), Ok(false));
2460 }
2461
2462 #[test]
2463 #[cfg(feature = "serde")]
2464 fn test_pattern_deserialize_err() {
2465 for json in [r#""[invalid""#, "null", "true", "42", "[]", "{}"] {
2466 assert!(serde_json::from_str::<Pattern>(json).is_err(), "{json}",);
2467 }
2468 }
2469
2470 #[test]
2471 #[cfg(feature = "serde")]
2472 fn test_pattern_serialize() {
2473 for (source, expected) in [
2474 ("", r#""""#),
2475 ("**", r#""*""#),
2476 ("Foobar", r#""Foobar""#),
2477 ("Foo**", r#""Foo*""#),
2478 ("**Bar", r#""*Bar""#),
2479 ("**Foo**", r#""*Foo*""#),
2480 ("*[rt]x", r#""*[rt]x""#),
2481 (r"f\*o", r#""f\\*o""#),
2482 (r#"f"o"#, r#""f\"o""#),
2483 ] {
2484 let pattern = Pattern::new(source).unwrap();
2485 assert_eq!(serde_json::to_string(&pattern).unwrap(), expected);
2486 }
2487
2488 let pattern = pattern!("Foo**", i);
2489 assert_eq!(serde_json::to_string(&pattern).unwrap(), r#""foo*""#);
2490 }
2491
2492 #[test]
2493 #[cfg(feature = "serde")]
2494 fn test_pattern_serde_roundtrip() {
2495 for source in [
2496 "",
2497 "*",
2498 "Foobar",
2499 "Foo**",
2500 "*Bar",
2501 "*Foo*",
2502 "*[rt]x",
2503 "{foo,bar}",
2504 r"f\*o",
2505 r#"f"o"#,
2506 "Grüße",
2507 ] {
2508 let pattern = Pattern::new(source).unwrap();
2509 let json = serde_json::to_string(&pattern).unwrap();
2510 let deserialized: Pattern = serde_json::from_str(&json).unwrap();
2511 assert_eq!(pattern, deserialized);
2512 }
2513 }
2514
2515 #[test]
2516 #[cfg(feature = "serde")]
2517 fn test_patterns_deserialize() {
2518 let patterns: Patterns = serde_json::from_str(r#"["**[rt]x","Foobar"]"#).unwrap();
2519 let expected = patterns!("*[rt]x", "Foobar");
2520 assert_eq!(patterns, expected);
2521 assert_eq!(patterns.is_match("foobar_rx", Gas::MAX), Ok(true));
2522 assert_eq!(patterns.is_match("Foobar", Gas::MAX), Ok(true));
2523 assert_eq!(patterns.is_match("foobar_RX", Gas::MAX), Ok(false));
2524 assert_eq!(patterns.is_match("FOOBAR", Gas::MAX), Ok(false));
2525 }
2526
2527 #[test]
2528 #[cfg(feature = "serde")]
2529 fn test_patterns_deserialize_err() {
2530 for json in [
2531 r#"["[invalid","foobar"]"#,
2532 r#"["foobar","[invalid"]"#,
2533 r#"["foobar",42]"#,
2534 r#"["foobar",null]"#,
2535 r#"["foobar",[]]"#,
2536 r#""foobar""#,
2537 "null",
2538 "true",
2539 "42",
2540 "{}",
2541 ] {
2542 assert!(serde_json::from_str::<Patterns>(json).is_err());
2543 }
2544 }
2545
2546 #[test]
2547 #[cfg(feature = "serde")]
2548 fn test_patterns_serialize() {
2549 let p = patterns!(
2550 "", "**", "Foobar", "Foo**", "**Bar", "**Foo**", "*[rt]x", r"f\*o",
2551 );
2552 assert_eq!(
2553 serde_json::to_string(&p).unwrap(),
2554 r#"["","*","Foobar","Foo*","*Bar","*Foo*","*[rt]x","f\\*o"]"#,
2555 );
2556
2557 let p = patterns!(
2558 "", "**", "Foobar", "Foo**", "**Bar", "**Foo**", "*[rt]x", r"f\*o", @ i
2559 );
2560 assert_eq!(
2561 serde_json::to_string(&p).unwrap(),
2562 r#"["","*","foobar","foo*","*bar","*foo*","*[rt]x","f\\*o"]"#,
2563 );
2564 }
2565
2566 #[test]
2567 #[cfg(feature = "serde")]
2568 fn test_patterns_serde_empty() {
2569 let patterns: Patterns = serde_json::from_str("[]").unwrap();
2570 assert_eq!(patterns, patterns!());
2571 assert!(patterns.is_empty());
2572 assert_eq!(patterns.is_match("", Gas::MAX), Ok(false));
2573 assert_eq!(patterns.is_match("foobar", Gas::MAX), Ok(false));
2574 assert_eq!(serde_json::to_string(&patterns).unwrap(), "[]");
2575 }
2576}