util.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. package validator
  2. import (
  3. "reflect"
  4. "strconv"
  5. "strings"
  6. )
  7. // extractTypeInternal gets the actual underlying type of field value.
  8. // It will dive into pointers, customTypes and return you the
  9. // underlying value and it's kind.
  10. func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) {
  11. BEGIN:
  12. switch current.Kind() {
  13. case reflect.Ptr:
  14. nullable = true
  15. if current.IsNil() {
  16. return current, reflect.Ptr, nullable
  17. }
  18. current = current.Elem()
  19. goto BEGIN
  20. case reflect.Interface:
  21. nullable = true
  22. if current.IsNil() {
  23. return current, reflect.Interface, nullable
  24. }
  25. current = current.Elem()
  26. goto BEGIN
  27. case reflect.Invalid:
  28. return current, reflect.Invalid, nullable
  29. default:
  30. if v.v.hasCustomFuncs {
  31. if fn, ok := v.v.customFuncs[current.Type()]; ok {
  32. current = reflect.ValueOf(fn(current))
  33. goto BEGIN
  34. }
  35. }
  36. return current, current.Kind(), nullable
  37. }
  38. }
  39. // getStructFieldOKInternal traverses a struct to retrieve a specific field denoted by the provided namespace and
  40. // returns the field, field kind and whether is was successful in retrieving the field at all.
  41. //
  42. // NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
  43. // could not be retrieved because it didn't exist.
  44. func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, found bool) {
  45. BEGIN:
  46. current, kind, _ = v.ExtractType(val)
  47. if kind == reflect.Invalid {
  48. return
  49. }
  50. if namespace == "" {
  51. found = true
  52. return
  53. }
  54. switch kind {
  55. case reflect.Ptr, reflect.Interface:
  56. return
  57. case reflect.Struct:
  58. typ := current.Type()
  59. fld := namespace
  60. ns := namespace
  61. if typ != timeType {
  62. idx := strings.Index(namespace, namespaceSeparator)
  63. if idx != -1 {
  64. fld = namespace[:idx]
  65. ns = namespace[idx+1:]
  66. } else {
  67. ns = ""
  68. }
  69. bracketIdx := strings.Index(fld, leftBracket)
  70. if bracketIdx != -1 {
  71. fld = fld[:bracketIdx]
  72. ns = namespace[bracketIdx:]
  73. }
  74. val = current.FieldByName(fld)
  75. namespace = ns
  76. goto BEGIN
  77. }
  78. case reflect.Array, reflect.Slice:
  79. idx := strings.Index(namespace, leftBracket)
  80. idx2 := strings.Index(namespace, rightBracket)
  81. arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2])
  82. if arrIdx >= current.Len() {
  83. return current, kind, false
  84. }
  85. startIdx := idx2 + 1
  86. if startIdx < len(namespace) {
  87. if namespace[startIdx:startIdx+1] == namespaceSeparator {
  88. startIdx++
  89. }
  90. }
  91. val = current.Index(arrIdx)
  92. namespace = namespace[startIdx:]
  93. goto BEGIN
  94. case reflect.Map:
  95. idx := strings.Index(namespace, leftBracket) + 1
  96. idx2 := strings.Index(namespace, rightBracket)
  97. endIdx := idx2
  98. if endIdx+1 < len(namespace) {
  99. if namespace[endIdx+1:endIdx+2] == namespaceSeparator {
  100. endIdx++
  101. }
  102. }
  103. key := namespace[idx:idx2]
  104. switch current.Type().Key().Kind() {
  105. case reflect.Int:
  106. i, _ := strconv.Atoi(key)
  107. val = current.MapIndex(reflect.ValueOf(i))
  108. namespace = namespace[endIdx+1:]
  109. case reflect.Int8:
  110. i, _ := strconv.ParseInt(key, 10, 8)
  111. val = current.MapIndex(reflect.ValueOf(int8(i)))
  112. namespace = namespace[endIdx+1:]
  113. case reflect.Int16:
  114. i, _ := strconv.ParseInt(key, 10, 16)
  115. val = current.MapIndex(reflect.ValueOf(int16(i)))
  116. namespace = namespace[endIdx+1:]
  117. case reflect.Int32:
  118. i, _ := strconv.ParseInt(key, 10, 32)
  119. val = current.MapIndex(reflect.ValueOf(int32(i)))
  120. namespace = namespace[endIdx+1:]
  121. case reflect.Int64:
  122. i, _ := strconv.ParseInt(key, 10, 64)
  123. val = current.MapIndex(reflect.ValueOf(i))
  124. namespace = namespace[endIdx+1:]
  125. case reflect.Uint:
  126. i, _ := strconv.ParseUint(key, 10, 0)
  127. val = current.MapIndex(reflect.ValueOf(uint(i)))
  128. namespace = namespace[endIdx+1:]
  129. case reflect.Uint8:
  130. i, _ := strconv.ParseUint(key, 10, 8)
  131. val = current.MapIndex(reflect.ValueOf(uint8(i)))
  132. namespace = namespace[endIdx+1:]
  133. case reflect.Uint16:
  134. i, _ := strconv.ParseUint(key, 10, 16)
  135. val = current.MapIndex(reflect.ValueOf(uint16(i)))
  136. namespace = namespace[endIdx+1:]
  137. case reflect.Uint32:
  138. i, _ := strconv.ParseUint(key, 10, 32)
  139. val = current.MapIndex(reflect.ValueOf(uint32(i)))
  140. namespace = namespace[endIdx+1:]
  141. case reflect.Uint64:
  142. i, _ := strconv.ParseUint(key, 10, 64)
  143. val = current.MapIndex(reflect.ValueOf(i))
  144. namespace = namespace[endIdx+1:]
  145. case reflect.Float32:
  146. f, _ := strconv.ParseFloat(key, 32)
  147. val = current.MapIndex(reflect.ValueOf(float32(f)))
  148. namespace = namespace[endIdx+1:]
  149. case reflect.Float64:
  150. f, _ := strconv.ParseFloat(key, 64)
  151. val = current.MapIndex(reflect.ValueOf(f))
  152. namespace = namespace[endIdx+1:]
  153. case reflect.Bool:
  154. b, _ := strconv.ParseBool(key)
  155. val = current.MapIndex(reflect.ValueOf(b))
  156. namespace = namespace[endIdx+1:]
  157. // reflect.Type = string
  158. default:
  159. val = current.MapIndex(reflect.ValueOf(key))
  160. namespace = namespace[endIdx+1:]
  161. }
  162. goto BEGIN
  163. }
  164. // if got here there was more namespace, cannot go any deeper
  165. panic("Invalid field namespace")
  166. }
  167. // asInt returns the parameter as a int64
  168. // or panics if it can't convert
  169. func asInt(param string) int64 {
  170. i, err := strconv.ParseInt(param, 0, 64)
  171. panicIf(err)
  172. return i
  173. }
  174. // asUint returns the parameter as a uint64
  175. // or panics if it can't convert
  176. func asUint(param string) uint64 {
  177. i, err := strconv.ParseUint(param, 0, 64)
  178. panicIf(err)
  179. return i
  180. }
  181. // asFloat returns the parameter as a float64
  182. // or panics if it can't convert
  183. func asFloat(param string) float64 {
  184. i, err := strconv.ParseFloat(param, 64)
  185. panicIf(err)
  186. return i
  187. }
  188. func panicIf(err error) {
  189. if err != nil {
  190. panic(err.Error())
  191. }
  192. }