podman

Форк
0
311 строк · 7.1 Кб
1
package validator
2

3
import (
4
	"fmt"
5
	"reflect"
6
	"regexp"
7
	"strconv"
8
	"strings"
9
	"time"
10
)
11

12
// extractTypeInternal gets the actual underlying type of field value.
13
// It will dive into pointers, customTypes and return you the
14
// underlying value and it's kind.
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
// getStructFieldOKInternal traverses a struct to retrieve a specific field denoted by the provided namespace and
59
// returns the field, field kind and whether is was successful in retrieving the field at all.
60
//
61
// NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
62
// could not be retrieved because it didn't exist.
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
		// reflect.Type = string
213
		default:
214
			val = current.MapIndex(reflect.ValueOf(key))
215
			namespace = namespace[endIdx+1:]
216
		}
217

218
		goto BEGIN
219
	}
220

221
	// if got here there was more namespace, cannot go any deeper
222
	panic("Invalid field namespace")
223
}
224

225
// asInt returns the parameter as a int64
226
// or panics if it can't convert
227
func asInt(param string) int64 {
228
	i, err := strconv.ParseInt(param, 0, 64)
229
	panicIf(err)
230

231
	return i
232
}
233

234
// asIntFromTimeDuration parses param as time.Duration and returns it as int64
235
// or panics on error.
236
func asIntFromTimeDuration(param string) int64 {
237
	d, err := time.ParseDuration(param)
238
	if err != nil {
239
		// attempt parsing as an integer assuming nanosecond precision
240
		return asInt(param)
241
	}
242
	return int64(d)
243
}
244

245
// asIntFromType calls the proper function to parse param as int64,
246
// given a field's Type t.
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
// asUint returns the parameter as a uint64
257
// or panics if it can't convert
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
// asFloat64 returns the parameter as a float64
267
// or panics if it can't convert
268
func asFloat64(param string) float64 {
269
	i, err := strconv.ParseFloat(param, 64)
270
	panicIf(err)
271
	return i
272
}
273

274
// asFloat64 returns the parameter as a float64
275
// or panics if it can't convert
276
func asFloat32(param string) float64 {
277
	i, err := strconv.ParseFloat(param, 32)
278
	panicIf(err)
279
	return i
280
}
281

282
// asBool returns the parameter as a bool
283
// or panics if it can't convert
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
// Checks if field value matches regex. If fl.Field can be cast to Stringer, it uses the Stringer interfaces
299
// String() return value. Otherwise, it uses fl.Field's String() value.
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

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.