diff --git a/bench/competitor_bench.go b/bench/competitor_bench.go index 99e2cfe..83658e0 100644 --- a/bench/competitor_bench.go +++ b/bench/competitor_bench.go @@ -1,4 +1,4 @@ -package test +package bench import ( "errors" diff --git a/core/normalization.go b/core/normalization.go index 896a965..bd5df11 100644 --- a/core/normalization.go +++ b/core/normalization.go @@ -52,14 +52,14 @@ func normalizeNumeric(value interface{}) (result interface{}, kind reflect.Kind, // TODO: Normalize slices to arrays? func normalizeInternal(value interface{}, isNil bool) (*NormalizedValue, error) { - valueType := reflect.ValueOf(value) - kind := valueType.Kind() + reflectedValue := reflect.ValueOf(value) + kind := reflectedValue.Kind() - switch valueType.Kind() { + switch reflectedValue.Kind() { // Dereference the pointer and normalize that value case reflect.Ptr: // If it's a nil pointer then flag the value as nil, obtain the inner element and create/return a zero value for the type - if valueType.IsNil() { + if reflectedValue.IsNil() { isNil = true innerElement := reflect.TypeOf(value).Elem() @@ -67,7 +67,7 @@ func normalizeInternal(value interface{}, isNil bool) (*NormalizedValue, error) value = reflect.Zero(innerElement).Interface() } else { - value = valueType.Elem().Interface() + value = reflectedValue.Elem().Interface() } return normalizeInternal(value, isNil) diff --git a/core/reflection.go b/core/reflection.go index 1becd5d..7d8ae7a 100644 --- a/core/reflection.go +++ b/core/reflection.go @@ -8,12 +8,16 @@ import ( ) type ReflectedField struct { + Index int Parent *ReflectedField Name string - Value interface{} TagGroups []TagGroup } +func (this *ReflectedField) GetValue(sourceStruct reflect.Value) interface{} { + return sourceStruct.Field(this.Index).Interface() +} + func (this *ReflectedField) FullName(postfix ...string) string { fullName := this.Name parent := this.Parent @@ -35,24 +39,31 @@ func (this *ReflectedField) FullName(postfix ...string) string { return fullName } -func reflectValue(value interface{}) (reflect.Type, reflect.Value) { - reflectValue := reflect.ValueOf(value) - valueType := reflectValue.Type() +func reflectValue(value interface{}) reflect.Type { + reflectedValueType := reflect.TypeOf(value) - if valueType.Kind() == reflect.Ptr { - valueType = valueType.Elem() + if reflectedValueType.Kind() == reflect.Ptr { + reflectedValueType = reflectedValueType.Elem() } - return valueType, reflect.Indirect(reflectValue) + return reflectedValueType } +var structFieldCache map[reflect.Type][]*ReflectedField = map[reflect.Type][]*ReflectedField{} + func GetStructFields(value interface{}, tagName string) ([]*ReflectedField, error) { var fields []*ReflectedField - valueType, reflectedValue := reflectValue(value) + //reflectedValue := reflect.Indirect(reflect.ValueOf(value)) + + reflectedType := reflectValue(value) - for i := 0; i < valueType.NumField(); i++ { - field := valueType.Field(i) + if cachedFields, ok := structFieldCache[reflectedType]; ok { + return cachedFields, nil + } + + for i := 0; i < reflectedType.NumField(); i++ { + field := reflectedType.Field(i) if unicode.IsUpper(rune(field.Name[0])) { // only grab exported fields tagValue := field.Tag.Get(tagName) @@ -63,8 +74,8 @@ func GetStructFields(value interface{}, tagName string) ([]*ReflectedField, erro } reflectedField := &ReflectedField{ + Index: i, Name: field.Name, - Value: reflectedValue.Field(i).Interface(), TagGroups: tagGroups, } @@ -72,6 +83,8 @@ func GetStructFields(value interface{}, tagName string) ([]*ReflectedField, erro } } + structFieldCache[reflectedType] = fields + return fields, nil } diff --git a/walk.go b/walk.go index b8cd416..cdb9951 100644 --- a/walk.go +++ b/walk.go @@ -43,8 +43,12 @@ func walkValidateStruct(context *context, normalized *core.NormalizedValue, pare return } + sourceStruct := reflect.Indirect(reflect.ValueOf(normalized.Value)) + for _, field := range fields { - normalizedFieldValue, err := core.Normalize(field.Value) + fieldValue := field.GetValue(sourceStruct) + + normalizedFieldValue, err := core.Normalize(fieldValue) if err != nil { context.errors.Add(core.NewValidatorError(field, nil, err))