123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- package validator
- import (
- "reflect"
- "strconv"
- "strings"
- )
- // extractTypeInternal gets the actual underlying type of field value.
- // It will dive into pointers, customTypes and return you the
- // 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:
- nullable = true
- if current.IsNil() {
- return current, reflect.Ptr, nullable
- }
- current = current.Elem()
- goto BEGIN
- case reflect.Interface:
- nullable = true
- if current.IsNil() {
- return current, reflect.Interface, nullable
- }
- current = current.Elem()
- goto BEGIN
- case reflect.Invalid:
- return current, reflect.Invalid, nullable
- default:
- if v.v.hasCustomFuncs {
- if fn, ok := v.v.customFuncs[current.Type()]; ok {
- current = reflect.ValueOf(fn(current))
- goto BEGIN
- }
- }
- return current, current.Kind(), nullable
- }
- }
- // getStructFieldOKInternal traverses a struct to retrieve a specific field denoted by the provided namespace and
- // returns the field, field kind and whether is was successful in retrieving the field at all.
- //
- // 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(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, found bool) {
- BEGIN:
- current, kind, _ = v.ExtractType(val)
- if kind == reflect.Invalid {
- return
- }
- if namespace == "" {
- found = true
- return
- }
- switch kind {
- case reflect.Ptr, reflect.Interface:
- return
- case reflect.Struct:
- typ := current.Type()
- fld := namespace
- ns := namespace
- if typ != timeType {
- idx := strings.Index(namespace, namespaceSeparator)
- if idx != -1 {
- fld = namespace[:idx]
- ns = namespace[idx+1:]
- } else {
- ns = ""
- }
- bracketIdx := strings.Index(fld, leftBracket)
- if bracketIdx != -1 {
- fld = fld[:bracketIdx]
- ns = namespace[bracketIdx:]
- }
- val = current.FieldByName(fld)
- namespace = ns
- goto BEGIN
- }
- case reflect.Array, reflect.Slice:
- idx := strings.Index(namespace, leftBracket)
- idx2 := strings.Index(namespace, rightBracket)
- arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2])
- if arrIdx >= current.Len() {
- return current, kind, false
- }
- startIdx := idx2 + 1
- if startIdx < len(namespace) {
- if namespace[startIdx:startIdx+1] == namespaceSeparator {
- startIdx++
- }
- }
- val = current.Index(arrIdx)
- namespace = namespace[startIdx:]
- goto BEGIN
- case reflect.Map:
- idx := strings.Index(namespace, leftBracket) + 1
- idx2 := strings.Index(namespace, rightBracket)
- endIdx := idx2
- if endIdx+1 < len(namespace) {
- if namespace[endIdx+1:endIdx+2] == namespaceSeparator {
- endIdx++
- }
- }
- key := namespace[idx:idx2]
- switch current.Type().Key().Kind() {
- case reflect.Int:
- i, _ := strconv.Atoi(key)
- val = current.MapIndex(reflect.ValueOf(i))
- namespace = namespace[endIdx+1:]
- case reflect.Int8:
- i, _ := strconv.ParseInt(key, 10, 8)
- val = current.MapIndex(reflect.ValueOf(int8(i)))
- namespace = namespace[endIdx+1:]
- case reflect.Int16:
- i, _ := strconv.ParseInt(key, 10, 16)
- val = current.MapIndex(reflect.ValueOf(int16(i)))
- namespace = namespace[endIdx+1:]
- case reflect.Int32:
- i, _ := strconv.ParseInt(key, 10, 32)
- val = current.MapIndex(reflect.ValueOf(int32(i)))
- namespace = namespace[endIdx+1:]
- case reflect.Int64:
- i, _ := strconv.ParseInt(key, 10, 64)
- val = current.MapIndex(reflect.ValueOf(i))
- namespace = namespace[endIdx+1:]
- case reflect.Uint:
- i, _ := strconv.ParseUint(key, 10, 0)
- val = current.MapIndex(reflect.ValueOf(uint(i)))
- namespace = namespace[endIdx+1:]
- case reflect.Uint8:
- i, _ := strconv.ParseUint(key, 10, 8)
- val = current.MapIndex(reflect.ValueOf(uint8(i)))
- namespace = namespace[endIdx+1:]
- case reflect.Uint16:
- i, _ := strconv.ParseUint(key, 10, 16)
- val = current.MapIndex(reflect.ValueOf(uint16(i)))
- namespace = namespace[endIdx+1:]
- case reflect.Uint32:
- i, _ := strconv.ParseUint(key, 10, 32)
- val = current.MapIndex(reflect.ValueOf(uint32(i)))
- namespace = namespace[endIdx+1:]
- case reflect.Uint64:
- i, _ := strconv.ParseUint(key, 10, 64)
- val = current.MapIndex(reflect.ValueOf(i))
- namespace = namespace[endIdx+1:]
- case reflect.Float32:
- f, _ := strconv.ParseFloat(key, 32)
- val = current.MapIndex(reflect.ValueOf(float32(f)))
- namespace = namespace[endIdx+1:]
- case reflect.Float64:
- f, _ := strconv.ParseFloat(key, 64)
- val = current.MapIndex(reflect.ValueOf(f))
- namespace = namespace[endIdx+1:]
- case reflect.Bool:
- b, _ := strconv.ParseBool(key)
- val = current.MapIndex(reflect.ValueOf(b))
- namespace = namespace[endIdx+1:]
- // reflect.Type = string
- default:
- val = current.MapIndex(reflect.ValueOf(key))
- namespace = namespace[endIdx+1:]
- }
- goto BEGIN
- }
- // if got here there was more namespace, cannot go any deeper
- panic("Invalid field namespace")
- }
- // asInt returns the parameter as a int64
- // or panics if it can't convert
- func asInt(param string) int64 {
- i, err := strconv.ParseInt(param, 0, 64)
- panicIf(err)
- return i
- }
- // asUint returns the parameter as a uint64
- // or panics if it can't convert
- func asUint(param string) uint64 {
- i, err := strconv.ParseUint(param, 0, 64)
- panicIf(err)
- return i
- }
- // asFloat returns the parameter as a float64
- // or panics if it can't convert
- func asFloat(param string) float64 {
- i, err := strconv.ParseFloat(param, 64)
- panicIf(err)
- return i
- }
- func panicIf(err error) {
- if err != nil {
- panic(err.Error())
- }
- }
|