1 package validator
2
3 import (
4 "fmt"
5 "reflect"
6 "regexp"
7 "strconv"
8 "strings"
9 "time"
10 )
11
12
13
14
15 func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) {
16
17 BEGIN:
18 switch current.Kind() {
19 case reflect.Ptr:
20
21 nullable = true
22
23 if current.IsNil() {
24 return current, reflect.Ptr, nullable
25 }
26
27 current = current.Elem()
28 goto BEGIN
29
30 case reflect.Interface:
31
32 nullable = true
33
34 if current.IsNil() {
35 return current, reflect.Interface, nullable
36 }
37
38 current = current.Elem()
39 goto BEGIN
40
41 case reflect.Invalid:
42 return current, reflect.Invalid, nullable
43
44 default:
45
46 if v.v.hasCustomFuncs {
47
48 if fn, ok := v.v.customFuncs[current.Type()]; ok {
49 current = reflect.ValueOf(fn(current))
50 goto BEGIN
51 }
52 }
53
54 return current, current.Kind(), nullable
55 }
56 }
57
58
59
60
61
62
63 func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, nullable bool, found bool) {
64
65 BEGIN:
66 current, kind, nullable = v.ExtractType(val)
67 if kind == reflect.Invalid {
68 return
69 }
70
71 if namespace == "" {
72 found = true
73 return
74 }
75
76 switch kind {
77
78 case reflect.Ptr, reflect.Interface:
79 return
80
81 case reflect.Struct:
82
83 typ := current.Type()
84 fld := namespace
85 var ns string
86
87 if !typ.ConvertibleTo(timeType) {
88
89 idx := strings.Index(namespace, namespaceSeparator)
90
91 if idx != -1 {
92 fld = namespace[:idx]
93 ns = namespace[idx+1:]
94 } else {
95 ns = ""
96 }
97
98 bracketIdx := strings.Index(fld, leftBracket)
99 if bracketIdx != -1 {
100 fld = fld[:bracketIdx]
101
102 ns = namespace[bracketIdx:]
103 }
104
105 val = current.FieldByName(fld)
106 namespace = ns
107 goto BEGIN
108 }
109
110 case reflect.Array, reflect.Slice:
111 idx := strings.Index(namespace, leftBracket)
112 idx2 := strings.Index(namespace, rightBracket)
113
114 arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2])
115
116 if arrIdx >= current.Len() {
117 return
118 }
119
120 startIdx := idx2 + 1
121
122 if startIdx < len(namespace) {
123 if namespace[startIdx:startIdx+1] == namespaceSeparator {
124 startIdx++
125 }
126 }
127
128 val = current.Index(arrIdx)
129 namespace = namespace[startIdx:]
130 goto BEGIN
131
132 case reflect.Map:
133 idx := strings.Index(namespace, leftBracket) + 1
134 idx2 := strings.Index(namespace, rightBracket)
135
136 endIdx := idx2
137
138 if endIdx+1 < len(namespace) {
139 if namespace[endIdx+1:endIdx+2] == namespaceSeparator {
140 endIdx++
141 }
142 }
143
144 key := namespace[idx:idx2]
145
146 switch current.Type().Key().Kind() {
147 case reflect.Int:
148 i, _ := strconv.Atoi(key)
149 val = current.MapIndex(reflect.ValueOf(i))
150 namespace = namespace[endIdx+1:]
151
152 case reflect.Int8:
153 i, _ := strconv.ParseInt(key, 10, 8)
154 val = current.MapIndex(reflect.ValueOf(int8(i)))
155 namespace = namespace[endIdx+1:]
156
157 case reflect.Int16:
158 i, _ := strconv.ParseInt(key, 10, 16)
159 val = current.MapIndex(reflect.ValueOf(int16(i)))
160 namespace = namespace[endIdx+1:]
161
162 case reflect.Int32:
163 i, _ := strconv.ParseInt(key, 10, 32)
164 val = current.MapIndex(reflect.ValueOf(int32(i)))
165 namespace = namespace[endIdx+1:]
166
167 case reflect.Int64:
168 i, _ := strconv.ParseInt(key, 10, 64)
169 val = current.MapIndex(reflect.ValueOf(i))
170 namespace = namespace[endIdx+1:]
171
172 case reflect.Uint:
173 i, _ := strconv.ParseUint(key, 10, 0)
174 val = current.MapIndex(reflect.ValueOf(uint(i)))
175 namespace = namespace[endIdx+1:]
176
177 case reflect.Uint8:
178 i, _ := strconv.ParseUint(key, 10, 8)
179 val = current.MapIndex(reflect.ValueOf(uint8(i)))
180 namespace = namespace[endIdx+1:]
181
182 case reflect.Uint16:
183 i, _ := strconv.ParseUint(key, 10, 16)
184 val = current.MapIndex(reflect.ValueOf(uint16(i)))
185 namespace = namespace[endIdx+1:]
186
187 case reflect.Uint32:
188 i, _ := strconv.ParseUint(key, 10, 32)
189 val = current.MapIndex(reflect.ValueOf(uint32(i)))
190 namespace = namespace[endIdx+1:]
191
192 case reflect.Uint64:
193 i, _ := strconv.ParseUint(key, 10, 64)
194 val = current.MapIndex(reflect.ValueOf(i))
195 namespace = namespace[endIdx+1:]
196
197 case reflect.Float32:
198 f, _ := strconv.ParseFloat(key, 32)
199 val = current.MapIndex(reflect.ValueOf(float32(f)))
200 namespace = namespace[endIdx+1:]
201
202 case reflect.Float64:
203 f, _ := strconv.ParseFloat(key, 64)
204 val = current.MapIndex(reflect.ValueOf(f))
205 namespace = namespace[endIdx+1:]
206
207 case reflect.Bool:
208 b, _ := strconv.ParseBool(key)
209 val = current.MapIndex(reflect.ValueOf(b))
210 namespace = namespace[endIdx+1:]
211
212
213 default:
214 val = current.MapIndex(reflect.ValueOf(key))
215 namespace = namespace[endIdx+1:]
216 }
217
218 goto BEGIN
219 }
220
221
222 panic("Invalid field namespace")
223 }
224
225
226
227 func asInt(param string) int64 {
228 i, err := strconv.ParseInt(param, 0, 64)
229 panicIf(err)
230
231 return i
232 }
233
234
235
236 func asIntFromTimeDuration(param string) int64 {
237 d, err := time.ParseDuration(param)
238 if err != nil {
239
240 return asInt(param)
241 }
242 return int64(d)
243 }
244
245
246
247 func asIntFromType(t reflect.Type, param string) int64 {
248 switch t {
249 case timeDurationType:
250 return asIntFromTimeDuration(param)
251 default:
252 return asInt(param)
253 }
254 }
255
256
257
258 func asUint(param string) uint64 {
259
260 i, err := strconv.ParseUint(param, 0, 64)
261 panicIf(err)
262
263 return i
264 }
265
266
267
268 func asFloat64(param string) float64 {
269 i, err := strconv.ParseFloat(param, 64)
270 panicIf(err)
271 return i
272 }
273
274
275
276 func asFloat32(param string) float64 {
277 i, err := strconv.ParseFloat(param, 32)
278 panicIf(err)
279 return i
280 }
281
282
283
284 func asBool(param string) bool {
285
286 i, err := strconv.ParseBool(param)
287 panicIf(err)
288
289 return i
290 }
291
292 func panicIf(err error) {
293 if err != nil {
294 panic(err.Error())
295 }
296 }
297
298
299
300 func fieldMatchesRegexByStringerValOrString(regex *regexp.Regexp, fl FieldLevel) bool {
301 switch fl.Field().Kind() {
302 case reflect.String:
303 return regex.MatchString(fl.Field().String())
304 default:
305 if stringer, ok := fl.Field().Interface().(fmt.Stringer); ok {
306 return regex.MatchString(stringer.String())
307 } else {
308 return regex.MatchString(fl.Field().String())
309 }
310 }
311 }
312
View as plain text