gtsocial-umbx

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

encoder.go (5772B)


      1 package form
      2 
      3 import (
      4 	"fmt"
      5 	"net/url"
      6 	"reflect"
      7 	"strconv"
      8 	"time"
      9 )
     10 
     11 type encoder struct {
     12 	e         *Encoder
     13 	errs      EncodeErrors
     14 	values    url.Values
     15 	namespace []byte
     16 }
     17 
     18 func (e *encoder) setError(namespace []byte, err error) {
     19 	if e.errs == nil {
     20 		e.errs = make(EncodeErrors)
     21 	}
     22 
     23 	e.errs[string(namespace)] = err
     24 }
     25 
     26 func (e *encoder) setVal(namespace []byte, idx int, vals ...string) {
     27 
     28 	arr, ok := e.values[string(namespace)]
     29 	if ok {
     30 		arr = append(arr, vals...)
     31 	} else {
     32 		arr = vals
     33 	}
     34 
     35 	e.values[string(namespace)] = arr
     36 }
     37 
     38 func (e *encoder) traverseStruct(v reflect.Value, namespace []byte, idx int) {
     39 
     40 	typ := v.Type()
     41 	l := len(namespace)
     42 	first := l == 0
     43 
     44 	// anonymous structs will still work for caching as the whole definition is stored
     45 	// including tags
     46 	s, ok := e.e.structCache.Get(typ)
     47 	if !ok {
     48 		s = e.e.structCache.parseStruct(e.e.mode, v, typ, e.e.tagName)
     49 	}
     50 
     51 	for _, f := range s.fields {
     52 		namespace = namespace[:l]
     53 
     54 		if f.isAnonymous && e.e.embedAnonymous {
     55 			e.setFieldByType(v.Field(f.idx), namespace, idx, f.isOmitEmpty)
     56 			continue
     57 		}
     58 
     59 		if first {
     60 			namespace = append(namespace, f.name...)
     61 		} else {
     62 			namespace = append(namespace, e.e.namespacePrefix...)
     63 			namespace = append(namespace, f.name...)
     64 			namespace = append(namespace, e.e.namespaceSuffix...)
     65 		}
     66 
     67 		e.setFieldByType(v.Field(f.idx), namespace, idx, f.isOmitEmpty)
     68 	}
     69 }
     70 
     71 func (e *encoder) setFieldByType(current reflect.Value, namespace []byte, idx int, isOmitEmpty bool) {
     72 
     73 	if idx > -1 && current.Kind() == reflect.Ptr {
     74 		namespace = append(namespace, '[')
     75 		namespace = strconv.AppendInt(namespace, int64(idx), 10)
     76 		namespace = append(namespace, ']')
     77 		idx = -2
     78 	}
     79 
     80 	if isOmitEmpty && !hasValue(current) {
     81 		return
     82 	}
     83 	v, kind := ExtractType(current)
     84 
     85 	if e.e.customTypeFuncs != nil {
     86 
     87 		if cf, ok := e.e.customTypeFuncs[v.Type()]; ok {
     88 
     89 			arr, err := cf(v.Interface())
     90 			if err != nil {
     91 				e.setError(namespace, err)
     92 				return
     93 			}
     94 
     95 			if idx > -1 {
     96 				namespace = append(namespace, '[')
     97 				namespace = strconv.AppendInt(namespace, int64(idx), 10)
     98 				namespace = append(namespace, ']')
     99 			}
    100 
    101 			e.setVal(namespace, idx, arr...)
    102 			return
    103 		}
    104 	}
    105 
    106 	switch kind {
    107 	case reflect.Ptr, reflect.Interface, reflect.Invalid:
    108 		return
    109 
    110 	case reflect.String:
    111 
    112 		e.setVal(namespace, idx, v.String())
    113 
    114 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
    115 
    116 		e.setVal(namespace, idx, strconv.FormatUint(v.Uint(), 10))
    117 
    118 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    119 
    120 		e.setVal(namespace, idx, strconv.FormatInt(v.Int(), 10))
    121 
    122 	case reflect.Float32:
    123 
    124 		e.setVal(namespace, idx, strconv.FormatFloat(v.Float(), 'f', -1, 32))
    125 
    126 	case reflect.Float64:
    127 
    128 		e.setVal(namespace, idx, strconv.FormatFloat(v.Float(), 'f', -1, 64))
    129 
    130 	case reflect.Bool:
    131 
    132 		e.setVal(namespace, idx, strconv.FormatBool(v.Bool()))
    133 
    134 	case reflect.Slice, reflect.Array:
    135 
    136 		if idx == -1 {
    137 
    138 			for i := 0; i < v.Len(); i++ {
    139 				e.setFieldByType(v.Index(i), namespace, i, false)
    140 			}
    141 
    142 			return
    143 		}
    144 
    145 		if idx > -1 {
    146 			namespace = append(namespace, '[')
    147 			namespace = strconv.AppendInt(namespace, int64(idx), 10)
    148 			namespace = append(namespace, ']')
    149 		}
    150 
    151 		namespace = append(namespace, '[')
    152 		l := len(namespace)
    153 
    154 		for i := 0; i < v.Len(); i++ {
    155 			namespace = namespace[:l]
    156 			namespace = strconv.AppendInt(namespace, int64(i), 10)
    157 			namespace = append(namespace, ']')
    158 			e.setFieldByType(v.Index(i), namespace, -2, false)
    159 		}
    160 
    161 	case reflect.Map:
    162 
    163 		if idx > -1 {
    164 			namespace = append(namespace, '[')
    165 			namespace = strconv.AppendInt(namespace, int64(idx), 10)
    166 			namespace = append(namespace, ']')
    167 		}
    168 
    169 		var valid bool
    170 		var s string
    171 		l := len(namespace)
    172 
    173 		for _, key := range v.MapKeys() {
    174 
    175 			namespace = namespace[:l]
    176 
    177 			if s, valid = e.getMapKey(key, namespace); !valid {
    178 				continue
    179 			}
    180 
    181 			namespace = append(namespace, '[')
    182 			namespace = append(namespace, s...)
    183 			namespace = append(namespace, ']')
    184 
    185 			e.setFieldByType(v.MapIndex(key), namespace, -2, false)
    186 		}
    187 
    188 	case reflect.Struct:
    189 
    190 		// if we get here then no custom time function declared so use RFC3339 by default
    191 		if v.Type() == timeType {
    192 
    193 			if idx > -1 {
    194 				namespace = append(namespace, '[')
    195 				namespace = strconv.AppendInt(namespace, int64(idx), 10)
    196 				namespace = append(namespace, ']')
    197 			}
    198 
    199 			e.setVal(namespace, idx, v.Interface().(time.Time).Format(time.RFC3339))
    200 			return
    201 		}
    202 
    203 		if idx == -1 {
    204 			e.traverseStruct(v, namespace, idx)
    205 			return
    206 		}
    207 
    208 		if idx > -1 {
    209 			namespace = append(namespace, '[')
    210 			namespace = strconv.AppendInt(namespace, int64(idx), 10)
    211 			namespace = append(namespace, ']')
    212 		}
    213 
    214 		e.traverseStruct(v, namespace, -2)
    215 	}
    216 }
    217 
    218 func (e *encoder) getMapKey(key reflect.Value, namespace []byte) (string, bool) {
    219 
    220 	v, kind := ExtractType(key)
    221 
    222 	if e.e.customTypeFuncs != nil {
    223 
    224 		if cf, ok := e.e.customTypeFuncs[v.Type()]; ok {
    225 			arr, err := cf(v.Interface())
    226 			if err != nil {
    227 				e.setError(namespace, err)
    228 				return "", false
    229 			}
    230 
    231 			return arr[0], true
    232 		}
    233 	}
    234 
    235 	switch kind {
    236 	case reflect.Interface, reflect.Ptr:
    237 		return "", false
    238 
    239 	case reflect.String:
    240 		return v.String(), true
    241 
    242 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
    243 		return strconv.FormatUint(v.Uint(), 10), true
    244 
    245 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    246 		return strconv.FormatInt(v.Int(), 10), true
    247 
    248 	case reflect.Float32:
    249 		return strconv.FormatFloat(v.Float(), 'f', -1, 32), true
    250 
    251 	case reflect.Float64:
    252 		return strconv.FormatFloat(v.Float(), 'f', -1, 64), true
    253 
    254 	case reflect.Bool:
    255 		return strconv.FormatBool(v.Bool()), true
    256 
    257 	default:
    258 		e.setError(namespace, fmt.Errorf("Unsupported Map Key '%v' Namespace '%s'", v.String(), namespace))
    259 		return "", false
    260 	}
    261 }