This adds FieldByNameFunc, which some libraries like reflect2 need.

For my usecase I could also just stub FieldByNameFunc to panic, but
figured that it would work OK to just make it work. I'm not sure if
the overhead to FieldByName using a closure is acceptable.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
Этот коммит содержится в:
Tyler Rockwood 2023-06-22 15:23:19 -05:00 коммит произвёл Ron Evans
родитель dd4e9e86e7
коммит fdc4bbbfad
3 изменённых файлов: 48 добавлений и 5 удалений

Просмотреть файл

@ -360,7 +360,7 @@ type Type interface {
// and FieldByNameFunc returns no match. // and FieldByNameFunc returns no match.
// This behavior mirrors Go's handling of name lookup in // This behavior mirrors Go's handling of name lookup in
// structs containing embedded fields. // structs containing embedded fields.
//FieldByNameFunc(match func(string) bool) (StructField, bool) FieldByNameFunc(match func(string) bool) (StructField, bool)
// In returns the type of a function type's i'th input parameter. // In returns the type of a function type's i'th input parameter.
// It panics if the type's Kind is not Func. // It panics if the type's Kind is not Func.
@ -722,11 +722,11 @@ func (t *rawType) rawField(n int) rawStructField {
return rawStructFieldFromPointer(descriptor, field.fieldType, data, flagsByte, name, offset) return rawStructFieldFromPointer(descriptor, field.fieldType, data, flagsByte, name, offset)
} }
// rawFieldByName returns nearly the same value as FieldByName but without converting the // rawFieldByNameFunc returns nearly the same value as FieldByNameFunc but without converting the
// Type member to an interface. // Type member to an interface.
// //
// For internal use only. // For internal use only.
func (t *rawType) rawFieldByName(n string) (rawStructField, []int, bool) { func (t *rawType) rawFieldByNameFunc(match func(string) bool) (rawStructField, []int, bool) {
if t.Kind() != Struct { if t.Kind() != Struct {
panic(errTypeField) panic(errTypeField)
} }
@ -769,7 +769,7 @@ func (t *rawType) rawFieldByName(n string) (rawStructField, []int, bool) {
name := readStringZ(data) name := readStringZ(data)
data = unsafe.Add(data, len(name)) data = unsafe.Add(data, len(name))
if name == n { if match(name) {
found = append(found, result{ found = append(found, result{
rawStructFieldFromPointer(descriptor, field.fieldType, data, flagsByte, name, offset), rawStructFieldFromPointer(descriptor, field.fieldType, data, flagsByte, name, offset),
append(ll.index, int(i)), append(ll.index, int(i)),
@ -1099,7 +1099,28 @@ func (t *rawType) FieldByName(name string) (StructField, bool) {
panic(errTypeFieldByName) panic(errTypeFieldByName)
} }
field, index, ok := t.rawFieldByName(name) field, index, ok := t.rawFieldByNameFunc(func(n string) bool { return n == name })
if !ok {
return StructField{}, false
}
return StructField{
Name: field.Name,
PkgPath: field.PkgPath,
Type: field.Type, // note: converts rawType to Type
Tag: field.Tag,
Anonymous: field.Anonymous,
Offset: field.Offset,
Index: index,
}, true
}
func (t *rawType) FieldByNameFunc(match func(string) bool) (StructField, bool) {
if t.Kind() != Struct {
panic(TypeError{"FieldByNameFunc"})
}
field, index, ok := t.rawFieldByNameFunc(match)
if !ok { if !ok {
return StructField{}, false return StructField{}, false
} }

Просмотреть файл

@ -1846,6 +1846,17 @@ func (v Value) FieldByName(name string) Value {
return Value{} return Value{}
} }
func (v Value) FieldByNameFunc(match func(string) bool) Value {
if v.Kind() != Struct {
panic(&ValueError{"FieldByName", v.Kind()})
}
if field, ok := v.typecode.FieldByNameFunc(match); ok {
return v.FieldByIndex(field.Index)
}
return Value{}
}
//go:linkname hashmapMake runtime.hashmapMakeUnsafePointer //go:linkname hashmapMake runtime.hashmapMakeUnsafePointer
func hashmapMake(keySize, valueSize uintptr, sizeHint uintptr, alg uint8) unsafe.Pointer func hashmapMake(keySize, valueSize uintptr, sizeHint uintptr, alg uint8) unsafe.Pointer

Просмотреть файл

@ -4,6 +4,7 @@ import (
"encoding/base64" "encoding/base64"
. "reflect" . "reflect"
"sort" "sort"
"strings"
"testing" "testing"
) )
@ -452,10 +453,20 @@ func TestTinyStruct(t *testing.T) {
t.Errorf("StrucTag for Foo=%v, want %v", got, want) t.Errorf("StrucTag for Foo=%v, want %v", got, want)
} }
q, ok = reffb.FieldByNameFunc(func(s string) bool { return strings.ToLower(s) == "bar" })
if q.Name != "Bar" || !ok {
t.Errorf("FieldByNameFunc(bar)=%v,%v, want Bar, true", q.Name, ok)
}
q, ok = reffb.FieldByName("Snorble") q, ok = reffb.FieldByName("Snorble")
if q.Name != "" || ok { if q.Name != "" || ok {
t.Errorf("FieldByName(Snorble)=%v,%v, want ``, false", q.Name, ok) t.Errorf("FieldByName(Snorble)=%v,%v, want ``, false", q.Name, ok)
} }
q, ok = reffb.FieldByNameFunc(func(s string) bool { return strings.ToLower(s) == "snorble" })
if q.Name != "" || ok {
t.Errorf("FieldByName(snorble)=%v,%v, want ``, false", q.Name, ok)
}
} }
func TestTinyZero(t *testing.T) { func TestTinyZero(t *testing.T) {