util.go 6.4 KB

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