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.
// This behavior mirrors Go's handling of name lookup in
// 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.
// 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)
}
// 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.
//
// 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 {
panic(errTypeField)
}
@ -769,7 +769,7 @@ func (t *rawType) rawFieldByName(n string) (rawStructField, []int, bool) {
name := readStringZ(data)
data = unsafe.Add(data, len(name))
if name == n {
if match(name) {
found = append(found, result{
rawStructFieldFromPointer(descriptor, field.fieldType, data, flagsByte, name, offset),
append(ll.index, int(i)),
@ -1099,7 +1099,28 @@ func (t *rawType) FieldByName(name string) (StructField, bool) {
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 {
return StructField{}, false
}

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

@ -1846,6 +1846,17 @@ func (v Value) FieldByName(name string) 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
func hashmapMake(keySize, valueSize uintptr, sizeHint uintptr, alg uint8) unsafe.Pointer

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

@ -4,6 +4,7 @@ import (
"encoding/base64"
. "reflect"
"sort"
"strings"
"testing"
)
@ -452,10 +453,20 @@ func TestTinyStruct(t *testing.T) {
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")
if 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) {