-
Notifications
You must be signed in to change notification settings - Fork 0
/
matcher.go
108 lines (86 loc) · 2.71 KB
/
matcher.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package bus
import (
"errors"
"unicode"
)
// MatchSubject checks if the given subject matches the pattern.
// it has been optimized for performance and zero allocations.
func MatchSubject(subject, pattern string) bool {
i, j := 0, 0
subLen, patLen := len(subject), len(pattern)
for i < subLen && j < patLen {
subStart, patStart := i, j
// Advance index to next dot in subject
for i < subLen && subject[i] != '.' {
i++
}
// Advance index to next dot in pattern
for j < patLen && pattern[j] != '.' {
j++
}
subPart := subject[subStart:i]
patPart := pattern[patStart:j]
// Handle ">" (catch-all) in pattern
if patPart == ">" {
return true // matches anything that follows
}
// Handle "*" (single element wildcard)
if patPart != "*" && subPart != patPart {
return false
}
// Skip the dots
i++
j++
}
// If pattern contains ">", it's valid to have remaining parts in subject
if j < patLen && pattern[j:] == ">" {
return true
}
// Ensure both subject and pattern are fully processed
return i >= subLen && j >= patLen
}
func ValidateSubject(subject string) error {
// subject must be in a form of "a.b.c", "a.b.*", "a.b.>"
// - subject should not have > at the middle of the string
// - subject should not have spaces or any other characters other than alphanumerics, dots, *, and >
// - * should have a dot or nothing before and after it
// - > should have a dot or nothing before it and nothing after it
// - subject should not starts with .
// - subject should not ends with .
// - subject should not have .. in the middle of the string
if subject == "" {
return errors.New("subject is empty")
}
for i, c := range subject {
if i == 0 && c == '.' {
return errors.New("subject should not starts with .")
}
if i == len(subject)-1 && c == '.' {
return errors.New("subject should not ends with .")
}
if c == ' ' {
return errors.New("subject should not have spaces")
}
if i > 0 && c == '.' && subject[i-1] == '.' {
return errors.New("subject should not have series of dots one after another")
}
if c == '>' && i != len(subject)-1 {
return errors.New("subject should not have anything after >")
}
if c == '>' && i > 0 && subject[i-1] != '.' {
return errors.New("subject should have a dot before >")
}
if c == '*' {
if i > 0 && subject[i-1] != '.' {
return errors.New("subject should have a dot before *")
}
if i != len(subject)-1 && subject[i+1] != '.' {
return errors.New("subject should have a dot after *")
}
}
if c != '.' && c != '*' && c != '>' && !unicode.IsDigit(c) && !unicode.IsLetter(c) && c != '_' {
return errors.New("subject should have only consists of alphanumerics, dots, *, > and _")
}
}
return nil
}