reflect: Add FieldByNameFunc
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>
Этот коммит содержится в:
родитель
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) {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче