Skip to content

Commit 0c5383d

Browse files
committed
workaround for go generics
1 parent 6a85b40 commit 0c5383d

4 files changed

Lines changed: 30 additions & 18 deletions

File tree

util.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,5 +125,5 @@ func ForEach(m Multiaddr, cb func(c Component) bool) {
125125

126126
func (m Multiaddr) Match(p ...meg.Pattern) (bool, error) {
127127
matcher := meg.PatternToMatcher(p...)
128-
return meg.Match(matcher, m)
128+
return meg.Match(matcher, m, func(c *Component) meg.Matchable { return c })
129129
}

x/meg/bench_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,12 @@ func preallocateCapture() *preallocatedCapture {
2929

3030
var webrtcMatchPrealloc *preallocatedCapture
3131

32+
func componentPtrToMatchable(c *multiaddr.Component) *multiaddr.Component {
33+
return c
34+
}
35+
3236
func (p *preallocatedCapture) IsWebRTCDirectMultiaddr(addr multiaddr.Multiaddr) (bool, int) {
33-
found, _ := meg.Match(p.matcher, addr)
37+
found, _ := meg.Match(p.matcher, addr, componentPtrToMatchable)
3438
return found, len(p.certHashes)
3539
}
3640

@@ -107,7 +111,7 @@ func isWebTransportMultiaddrPrealloc() *preallocatedCapture {
107111

108112
func IsWebTransportMultiaddrPrealloc(m multiaddr.Multiaddr) (bool, int) {
109113
p := isWebTransportMultiaddrPrealloc()
110-
found, _ := meg.Match(p.matcher, m)
114+
found, _ := meg.Match(p.matcher, m, componentPtrToMatchable)
111115
return found, len(p.certHashes)
112116
}
113117

@@ -365,7 +369,7 @@ func BenchmarkIsWebTransportMultiaddrNoCapturePrealloc(b *testing.B) {
365369

366370
b.ResetTimer()
367371
for i := 0; i < b.N; i++ {
368-
isWT, _ := meg.Match(wtPreallocNoCapture, addr)
372+
isWT, _ := meg.Match(wtPreallocNoCapture, addr, componentPtrToMatchable)
369373
if !isWT {
370374
b.Fatal("unexpected result")
371375
}

x/meg/meg.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ type Matchable interface {
6969
// Match returns whether the given Components match the Pattern defined in MatchState.
7070
// Errors are used to communicate capture errors.
7171
// If the error is non-nil the returned bool will be false.
72-
func Match[S ~[]T, T Matchable](matcher Matcher, components S) (bool, error) {
72+
// The ptrToMatchable function is used to convert type *T to a Matchable..
73+
// This is due to a limitation of Go generics, where we cannot say *T implements Matchable.
74+
// When meg moves out of the x/ directory, we can reference the `*Component` type directly and avoid this limitation.
75+
func Match[S ~[]T, T any, G Matchable](matcher Matcher, components S, ptrToMatchable func(*T) G) (bool, error) {
7376
states := matcher.states
7477
startStateIdx := matcher.startIdx
7578

@@ -92,19 +95,20 @@ func Match[S ~[]T, T Matchable](matcher Matcher, components S) (bool, error) {
9295

9396
currentStates = appendState(currentStates, states, startStateIdx, nil, visitedBitSet)
9497

95-
for _, c := range components {
98+
for ic := range components {
9699
clear(visitedBitSet)
97100
if len(currentStates.states) == 0 {
98101
return false, nil
99102
}
100103
for i, stateIndex := range currentStates.states {
101104
s := states[stateIndex]
102-
if s.codeOrKind == matchAny || (s.codeOrKind >= 0 && s.codeOrKind == c.Code()) {
105+
cPtr := ptrToMatchable(&components[ic])
106+
if s.codeOrKind == matchAny || (s.codeOrKind >= 0 && s.codeOrKind == cPtr.Code()) {
103107
cm := currentStates.captures[i]
104108
if s.capture != nil {
105109
next := &capture{
106110
f: s.capture,
107-
v: c,
111+
v: cPtr,
108112
}
109113
if cm == nil {
110114
cm = next

x/meg/meg_test.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,30 @@ type codeAndValue struct {
1313
}
1414

1515
// Code implements Matchable.
16-
func (c codeAndValue) Code() int {
16+
func (c *codeAndValue) Code() int {
1717
return c.code
1818
}
1919

2020
// Value implements Matchable.
21-
func (c codeAndValue) Value() string {
21+
func (c *codeAndValue) Value() string {
2222
return c.val
2323
}
2424

2525
// Bytes implements Matchable.
26-
func (c codeAndValue) Bytes() []byte {
26+
func (c *codeAndValue) Bytes() []byte {
2727
return []byte(c.val)
2828
}
2929

3030
// RawValue implements Matchable.
31-
func (c codeAndValue) RawValue() []byte {
31+
func (c *codeAndValue) RawValue() []byte {
3232
return []byte(c.val)
3333
}
3434

35-
var _ Matchable = codeAndValue{}
35+
var _ Matchable = &codeAndValue{}
36+
37+
func codeAndValuePtrToMatchable(c *codeAndValue) *codeAndValue {
38+
return c
39+
}
3640

3741
func TestSimple(t *testing.T) {
3842
type testCase struct {
@@ -106,12 +110,12 @@ func TestSimple(t *testing.T) {
106110

107111
for i, tc := range testCases {
108112
for _, m := range tc.shouldMatch {
109-
if matches, err := Match(tc.pattern, codesToCodeAndValue(m)); !matches {
113+
if matches, err := Match(tc.pattern, codesToCodeAndValue(m), codeAndValuePtrToMatchable); !matches {
110114
t.Fatalf("failed to match %v with %v. idx=%d. err=%v", m, tc.pattern, i, err)
111115
}
112116
}
113117
for _, m := range tc.shouldNotMatch {
114-
if matches, _ := Match(tc.pattern, codesToCodeAndValue(m)); matches {
118+
if matches, _ := Match(tc.pattern, codesToCodeAndValue(m), codeAndValuePtrToMatchable); matches {
115119
t.Fatalf("failed to not match %v with %v. idx=%d", m, tc.pattern, i)
116120
}
117121
}
@@ -125,7 +129,7 @@ func TestSimple(t *testing.T) {
125129
return true
126130
}
127131
}
128-
matches, _ := Match(tc.pattern, codesToCodeAndValue(notMatch))
132+
matches, _ := Match(tc.pattern, codesToCodeAndValue(notMatch), codeAndValuePtrToMatchable)
129133
return !matches
130134
}, &quick.Config{}); err != nil {
131135
t.Fatal(err)
@@ -172,7 +176,7 @@ func TestCapture(t *testing.T) {
172176
_ = testCases
173177
for _, tc := range testCases {
174178
state, assert := tc.setup()
175-
if matches, _ := Match(state, tc.parts); !matches {
179+
if matches, _ := Match(state, tc.parts, codeAndValuePtrToMatchable); !matches {
176180
t.Fatalf("failed to match %v with %v", tc.parts, state)
177181
}
178182
assert()
@@ -255,7 +259,7 @@ func FuzzMatchesRegexpBehavior(f *testing.F) {
255259
return
256260
}
257261
p := PatternToMatcher(pattern...)
258-
otherMatched, _ := Match(p, bytesToCodeAndValue(corpus))
262+
otherMatched, _ := Match(p, bytesToCodeAndValue(corpus), codeAndValuePtrToMatchable)
259263
if otherMatched != matched {
260264
t.Log("regexp", string(regexpPattern))
261265
t.Log("corpus", string(corpus))

0 commit comments

Comments
 (0)