diff --git a/util.go b/util.go index 7711428..a01d4b1 100644 --- a/util.go +++ b/util.go @@ -11,6 +11,7 @@ import ( // underlying value and it's kind. func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) { +BEGIN: switch current.Kind() { case reflect.Ptr: @@ -20,7 +21,8 @@ func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (re return current, reflect.Ptr, nullable } - return v.extractTypeInternal(current.Elem(), nullable) + current = current.Elem() + goto BEGIN case reflect.Interface: @@ -30,7 +32,8 @@ func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (re return current, reflect.Interface, nullable } - return v.extractTypeInternal(current.Elem(), nullable) + current = current.Elem() + goto BEGIN case reflect.Invalid: return current, reflect.Invalid, nullable @@ -40,7 +43,8 @@ func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (re if v.v.hasCustomFuncs { if fn, ok := v.v.customFuncs[current.Type()]; ok { - return v.extractTypeInternal(reflect.ValueOf(fn(current)), nullable) + current = reflect.ValueOf(fn(current)) + goto BEGIN } } @@ -53,23 +57,24 @@ func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (re // // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field // could not be retrieved because it didn't exist. -func (v *validate) getStructFieldOKInternal(current reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) { +func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, found bool) { - current, kind, _ := v.ExtractType(current) +BEGIN: + current, kind, _ = v.ExtractType(val) if kind == reflect.Invalid { - return current, kind, false + return } if namespace == "" { - return current, kind, true + found = true + return } switch kind { case reflect.Ptr, reflect.Interface: - - return current, kind, false + return case reflect.Struct: @@ -95,9 +100,9 @@ func (v *validate) getStructFieldOKInternal(current reflect.Value, namespace str ns = namespace[bracketIdx:] } - current = current.FieldByName(fld) - - return v.getStructFieldOKInternal(current, ns) + val = current.FieldByName(fld) + namespace = ns + goto BEGIN } case reflect.Array, reflect.Slice: @@ -118,7 +123,9 @@ func (v *validate) getStructFieldOKInternal(current reflect.Value, namespace str } } - return v.getStructFieldOKInternal(current.Index(arrIdx), namespace[startIdx:]) + val = current.Index(arrIdx) + namespace = namespace[startIdx:] + goto BEGIN case reflect.Map: idx := strings.Index(namespace, leftBracket) + 1 @@ -137,48 +144,76 @@ func (v *validate) getStructFieldOKInternal(current reflect.Value, namespace str switch current.Type().Key().Kind() { case reflect.Int: i, _ := strconv.Atoi(key) - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(i)) + namespace = namespace[endIdx+1:] + case reflect.Int8: i, _ := strconv.ParseInt(key, 10, 8) - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(int8(i))), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(int8(i))) + namespace = namespace[endIdx+1:] + case reflect.Int16: i, _ := strconv.ParseInt(key, 10, 16) - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(int16(i))), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(int16(i))) + namespace = namespace[endIdx+1:] + case reflect.Int32: i, _ := strconv.ParseInt(key, 10, 32) - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(int32(i))), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(int32(i))) + namespace = namespace[endIdx+1:] + case reflect.Int64: i, _ := strconv.ParseInt(key, 10, 64) - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(i)) + namespace = namespace[endIdx+1:] + case reflect.Uint: i, _ := strconv.ParseUint(key, 10, 0) - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(uint(i))), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(uint(i))) + namespace = namespace[endIdx+1:] + case reflect.Uint8: i, _ := strconv.ParseUint(key, 10, 8) - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(uint8(i))), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(uint8(i))) + namespace = namespace[endIdx+1:] + case reflect.Uint16: i, _ := strconv.ParseUint(key, 10, 16) - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(uint16(i))), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(uint16(i))) + namespace = namespace[endIdx+1:] + case reflect.Uint32: i, _ := strconv.ParseUint(key, 10, 32) - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(uint32(i))), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(uint32(i))) + namespace = namespace[endIdx+1:] + case reflect.Uint64: i, _ := strconv.ParseUint(key, 10, 64) - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(i)) + namespace = namespace[endIdx+1:] + case reflect.Float32: f, _ := strconv.ParseFloat(key, 32) - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(float32(f))), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(float32(f))) + namespace = namespace[endIdx+1:] + case reflect.Float64: f, _ := strconv.ParseFloat(key, 64) - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(f)), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(f)) + namespace = namespace[endIdx+1:] + case reflect.Bool: b, _ := strconv.ParseBool(key) - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(b)), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(b)) + namespace = namespace[endIdx+1:] // reflect.Type = string default: - return v.getStructFieldOKInternal(current.MapIndex(reflect.ValueOf(key)), namespace[endIdx+1:]) + val = current.MapIndex(reflect.ValueOf(key)) + namespace = namespace[endIdx+1:] } + + goto BEGIN } // if got here there was more namespace, cannot go any deeper