gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

util.go (6525B)


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