68 lines
1.8 KiB
Go
68 lines
1.8 KiB
Go
|
package q
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"go/token"
|
||
|
"reflect"
|
||
|
)
|
||
|
|
||
|
// ErrUnknownField is returned when an unknown field is passed.
|
||
|
var ErrUnknownField = errors.New("unknown field")
|
||
|
|
||
|
type fieldMatcherDelegate struct {
|
||
|
FieldMatcher
|
||
|
Field string
|
||
|
}
|
||
|
|
||
|
// NewFieldMatcher creates a Matcher for a given field.
|
||
|
func NewFieldMatcher(field string, fm FieldMatcher) Matcher {
|
||
|
return fieldMatcherDelegate{Field: field, FieldMatcher: fm}
|
||
|
}
|
||
|
|
||
|
// FieldMatcher can be used in NewFieldMatcher as a simple way to create the
|
||
|
// most common Matcher: A Matcher that evaluates one field's value.
|
||
|
// For more complex scenarios, implement the Matcher interface directly.
|
||
|
type FieldMatcher interface {
|
||
|
MatchField(v interface{}) (bool, error)
|
||
|
}
|
||
|
|
||
|
func (r fieldMatcherDelegate) Match(i interface{}) (bool, error) {
|
||
|
v := reflect.Indirect(reflect.ValueOf(i))
|
||
|
return r.MatchValue(&v)
|
||
|
}
|
||
|
|
||
|
func (r fieldMatcherDelegate) MatchValue(v *reflect.Value) (bool, error) {
|
||
|
field := v.FieldByName(r.Field)
|
||
|
if !field.IsValid() {
|
||
|
return false, ErrUnknownField
|
||
|
}
|
||
|
return r.MatchField(field.Interface())
|
||
|
}
|
||
|
|
||
|
// NewField2FieldMatcher creates a Matcher for a given field1 and field2.
|
||
|
func NewField2FieldMatcher(field1, field2 string, tok token.Token) Matcher {
|
||
|
return field2fieldMatcherDelegate{Field1: field1, Field2: field2, Tok: tok}
|
||
|
}
|
||
|
|
||
|
type field2fieldMatcherDelegate struct {
|
||
|
Field1, Field2 string
|
||
|
Tok token.Token
|
||
|
}
|
||
|
|
||
|
func (r field2fieldMatcherDelegate) Match(i interface{}) (bool, error) {
|
||
|
v := reflect.Indirect(reflect.ValueOf(i))
|
||
|
return r.MatchValue(&v)
|
||
|
}
|
||
|
|
||
|
func (r field2fieldMatcherDelegate) MatchValue(v *reflect.Value) (bool, error) {
|
||
|
field1 := v.FieldByName(r.Field1)
|
||
|
if !field1.IsValid() {
|
||
|
return false, ErrUnknownField
|
||
|
}
|
||
|
field2 := v.FieldByName(r.Field2)
|
||
|
if !field2.IsValid() {
|
||
|
return false, ErrUnknownField
|
||
|
}
|
||
|
return compare(field1.Interface(), field2.Interface(), r.Tok), nil
|
||
|
}
|