Add isStruct and isStructPtr helpers
Test: proptools tests Change-Id: I7814b2138cd19b538a3a33036a15119e118d7644
This commit is contained in:
parent
0c4d1db0a0
commit
6898d26054
6 changed files with 32 additions and 42 deletions
|
@ -67,13 +67,9 @@ func CopyProperties(dstValue, srcValue reflect.Value) {
|
||||||
|
|
||||||
srcFieldValue = srcFieldValue.Elem()
|
srcFieldValue = srcFieldValue.Elem()
|
||||||
|
|
||||||
if srcFieldValue.Kind() != reflect.Ptr {
|
if !isStructPtr(srcFieldValue.Type()) {
|
||||||
panic(fmt.Errorf("can't clone field %q: interface refers to a non-pointer",
|
panic(fmt.Errorf("can't clone field %q: expected interface to contain *struct, found %s",
|
||||||
field.Name))
|
field.Name, srcFieldValue.Type()))
|
||||||
}
|
|
||||||
if srcFieldValue.Type().Elem().Kind() != reflect.Struct {
|
|
||||||
panic(fmt.Errorf("can't clone field %q: interface points to a non-struct",
|
|
||||||
field.Name))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if dstFieldValue.IsNil() || dstFieldValue.Elem().Type() != srcFieldValue.Type() {
|
if dstFieldValue.IsNil() || dstFieldValue.Elem().Type() != srcFieldValue.Type() {
|
||||||
|
@ -146,13 +142,9 @@ func ZeroProperties(structValue reflect.Value) {
|
||||||
// We leave the pointer intact and zero out the struct that's
|
// We leave the pointer intact and zero out the struct that's
|
||||||
// pointed to.
|
// pointed to.
|
||||||
fieldValue = fieldValue.Elem()
|
fieldValue = fieldValue.Elem()
|
||||||
if fieldValue.Kind() != reflect.Ptr {
|
if !isStructPtr(fieldValue.Type()) {
|
||||||
panic(fmt.Errorf("can't zero field %q: interface refers to a non-pointer",
|
panic(fmt.Errorf("can't zero field %q: expected interface to contain *struct, found %s",
|
||||||
field.Name))
|
field.Name, fieldValue.Type()))
|
||||||
}
|
|
||||||
if fieldValue.Type().Elem().Kind() != reflect.Struct {
|
|
||||||
panic(fmt.Errorf("can't zero field %q: interface points to a non-struct",
|
|
||||||
field.Name))
|
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
|
@ -206,13 +198,9 @@ func cloneEmptyProperties(dstValue, srcValue reflect.Value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
srcFieldValue = srcFieldValue.Elem()
|
srcFieldValue = srcFieldValue.Elem()
|
||||||
if srcFieldValue.Kind() != reflect.Ptr {
|
if !isStructPtr(srcFieldValue.Type()) {
|
||||||
panic(fmt.Errorf("can't clone empty field %q: interface refers to a non-pointer",
|
panic(fmt.Errorf("can't clone empty field %q: expected interface to contain *struct, found %s",
|
||||||
field.Name))
|
field.Name, srcFieldValue.Type()))
|
||||||
}
|
|
||||||
if srcFieldValue.Type().Elem().Kind() != reflect.Struct {
|
|
||||||
panic(fmt.Errorf("can't clone empty field %q: interface points to a non-struct",
|
|
||||||
field.Name))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newValue := reflect.New(srcFieldValue.Type()).Elem()
|
newValue := reflect.New(srcFieldValue.Type()).Elem()
|
||||||
|
|
|
@ -274,7 +274,7 @@ func extendPropertiesRecursive(dstValues []reflect.Value, srcValue reflect.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step into source pointers to structs
|
// Step into source pointers to structs
|
||||||
if srcFieldValue.Kind() == reflect.Ptr && srcFieldValue.Type().Elem().Kind() == reflect.Struct {
|
if isStructPtr(srcFieldValue.Type()) {
|
||||||
if srcFieldValue.IsNil() {
|
if srcFieldValue.IsNil() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -323,7 +323,7 @@ func extendPropertiesRecursive(dstValues []reflect.Value, srcValue reflect.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step into destination pointers to structs
|
// Step into destination pointers to structs
|
||||||
if dstFieldValue.Kind() == reflect.Ptr && dstFieldValue.Type().Elem().Kind() == reflect.Struct {
|
if isStructPtr(dstFieldValue.Type()) {
|
||||||
if dstFieldValue.IsNil() {
|
if dstFieldValue.IsNil() {
|
||||||
dstFieldValue = reflect.New(dstFieldValue.Type().Elem())
|
dstFieldValue = reflect.New(dstFieldValue.Type().Elem())
|
||||||
origDstFieldValue.Set(dstFieldValue)
|
origDstFieldValue.Set(dstFieldValue)
|
||||||
|
@ -501,11 +501,8 @@ func getOrCreateStruct(in interface{}) (reflect.Value, error) {
|
||||||
|
|
||||||
func getStruct(in interface{}) (reflect.Value, error) {
|
func getStruct(in interface{}) (reflect.Value, error) {
|
||||||
value := reflect.ValueOf(in)
|
value := reflect.ValueOf(in)
|
||||||
if value.Kind() != reflect.Ptr {
|
if !isStructPtr(value.Type()) {
|
||||||
return reflect.Value{}, fmt.Errorf("expected pointer to struct, got %T", in)
|
return reflect.Value{}, fmt.Errorf("expected pointer to struct, got %s", value.Type())
|
||||||
}
|
|
||||||
if value.Type().Elem().Kind() != reflect.Struct {
|
|
||||||
return reflect.Value{}, fmt.Errorf("expected pointer to struct, got %T", in)
|
|
||||||
}
|
}
|
||||||
if value.IsNil() {
|
if value.IsNil() {
|
||||||
return reflect.Value{}, getStructEmptyError{}
|
return reflect.Value{}, getStructEmptyError{}
|
||||||
|
|
|
@ -50,8 +50,7 @@ func filterPropertyStructFields(fields []reflect.StructField, prefix string, max
|
||||||
|
|
||||||
if maxTypeNameSize > 0 && structNameSize+fieldTypeNameSize > maxTypeNameSize {
|
if maxTypeNameSize > 0 && structNameSize+fieldTypeNameSize > maxTypeNameSize {
|
||||||
if len(filteredFields) == 0 {
|
if len(filteredFields) == 0 {
|
||||||
if field.Type.Kind() == reflect.Struct ||
|
if isStruct(field.Type) || isStructPtr(field.Type) {
|
||||||
field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
|
|
||||||
// An error fitting the nested struct should have been caught when recursing
|
// An error fitting the nested struct should have been caught when recursing
|
||||||
// into the nested struct.
|
// into the nested struct.
|
||||||
panic(fmt.Errorf("Shouldn't happen: can't fit nested struct %q (%d) into %d",
|
panic(fmt.Errorf("Shouldn't happen: can't fit nested struct %q (%d) into %d",
|
||||||
|
@ -82,12 +81,12 @@ func filterPropertyStructFields(fields []reflect.StructField, prefix string, max
|
||||||
}
|
}
|
||||||
|
|
||||||
ptrToStruct := false
|
ptrToStruct := false
|
||||||
if field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
|
if isStructPtr(field.Type) {
|
||||||
ptrToStruct = true
|
ptrToStruct = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recurse into structs
|
// Recurse into structs
|
||||||
if ptrToStruct || field.Type.Kind() == reflect.Struct {
|
if ptrToStruct || isStruct(field.Type) {
|
||||||
subMaxTypeNameSize := maxTypeNameSize
|
subMaxTypeNameSize := maxTypeNameSize
|
||||||
if maxTypeNameSize > 0 {
|
if maxTypeNameSize > 0 {
|
||||||
// In the worst case where only this nested struct will fit in the outer struct, the
|
// In the worst case where only this nested struct will fit in the outer struct, the
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
package proptools
|
package proptools
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
@ -97,3 +98,11 @@ func IntDefault(i *int64, def int) int {
|
||||||
func Int(i *int64) int {
|
func Int(i *int64) int {
|
||||||
return IntDefault(i, 0)
|
return IntDefault(i, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isStruct(t reflect.Type) bool {
|
||||||
|
return t.Kind() == reflect.Struct
|
||||||
|
}
|
||||||
|
|
||||||
|
func isStructPtr(t reflect.Type) bool {
|
||||||
|
return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
|
||||||
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ func HasTag(field reflect.StructField, name, value string) bool {
|
||||||
// are tagged with the given key and value, including ones found in embedded structs or pointers to structs.
|
// are tagged with the given key and value, including ones found in embedded structs or pointers to structs.
|
||||||
func PropertyIndexesWithTag(ps interface{}, key, value string) [][]int {
|
func PropertyIndexesWithTag(ps interface{}, key, value string) [][]int {
|
||||||
t := reflect.TypeOf(ps)
|
t := reflect.TypeOf(ps)
|
||||||
if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
|
if !isStructPtr(t) {
|
||||||
panic(fmt.Errorf("type %s is not a pointer to a struct", t))
|
panic(fmt.Errorf("type %s is not a pointer to a struct", t))
|
||||||
}
|
}
|
||||||
t = t.Elem()
|
t = t.Elem()
|
||||||
|
@ -49,7 +49,7 @@ func propertyIndexesWithTag(t reflect.Type, key, value string) [][]int {
|
||||||
for i := 0; i < t.NumField(); i++ {
|
for i := 0; i < t.NumField(); i++ {
|
||||||
field := t.Field(i)
|
field := t.Field(i)
|
||||||
ft := field.Type
|
ft := field.Type
|
||||||
if ft.Kind() == reflect.Struct || (ft.Kind() == reflect.Ptr && ft.Elem().Kind() == reflect.Struct) {
|
if isStruct(ft) || isStructPtr(ft) {
|
||||||
if ft.Kind() == reflect.Ptr {
|
if ft.Kind() == reflect.Ptr {
|
||||||
ft = ft.Elem()
|
ft = ft.Elem()
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,14 +49,11 @@ func UnpackProperties(propertyDefs []*parser.Property,
|
||||||
|
|
||||||
for _, properties := range propertiesStructs {
|
for _, properties := range propertiesStructs {
|
||||||
propertiesValue := reflect.ValueOf(properties)
|
propertiesValue := reflect.ValueOf(properties)
|
||||||
if propertiesValue.Kind() != reflect.Ptr {
|
if !isStructPtr(propertiesValue.Type()) {
|
||||||
panic("properties must be a pointer to a struct")
|
panic(fmt.Errorf("properties must be *struct, got %s",
|
||||||
|
propertiesValue.Type()))
|
||||||
}
|
}
|
||||||
|
|
||||||
propertiesValue = propertiesValue.Elem()
|
propertiesValue = propertiesValue.Elem()
|
||||||
if propertiesValue.Kind() != reflect.Struct {
|
|
||||||
panic("properties must be a pointer to a struct")
|
|
||||||
}
|
|
||||||
|
|
||||||
newErrs := unpackStructValue("", propertiesValue, propertyMap)
|
newErrs := unpackStructValue("", propertiesValue, propertyMap)
|
||||||
errs = append(errs, newErrs...)
|
errs = append(errs, newErrs...)
|
||||||
|
@ -212,7 +209,7 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
|
||||||
panic(fmt.Errorf("unsupported kind for field %s: %s", propertyName, kind))
|
panic(fmt.Errorf("unsupported kind for field %s: %s", propertyName, kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
if field.Anonymous && fieldValue.Kind() == reflect.Struct {
|
if field.Anonymous && isStruct(fieldValue.Type()) {
|
||||||
newErrs := unpackStructValue(namePrefix, fieldValue, propertyMap)
|
newErrs := unpackStructValue(namePrefix, fieldValue, propertyMap)
|
||||||
errs = append(errs, newErrs...)
|
errs = append(errs, newErrs...)
|
||||||
continue
|
continue
|
||||||
|
@ -239,7 +236,7 @@ func unpackStructValue(namePrefix string, structValue reflect.Value,
|
||||||
|
|
||||||
var newErrs []error
|
var newErrs []error
|
||||||
|
|
||||||
if fieldValue.Kind() == reflect.Struct {
|
if isStruct(fieldValue.Type()) {
|
||||||
newErrs = unpackStruct(propertyName+".", fieldValue,
|
newErrs = unpackStruct(propertyName+".", fieldValue,
|
||||||
packedProperty.property, propertyMap)
|
packedProperty.property, propertyMap)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue