summaryrefslogtreecommitdiff
path: root/vendor/github.com/go-playground/form/v4/encoder.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-playground/form/v4/encoder.go')
-rw-r--r--vendor/github.com/go-playground/form/v4/encoder.go261
1 files changed, 261 insertions, 0 deletions
diff --git a/vendor/github.com/go-playground/form/v4/encoder.go b/vendor/github.com/go-playground/form/v4/encoder.go
new file mode 100644
index 000000000..eea0bd9f3
--- /dev/null
+++ b/vendor/github.com/go-playground/form/v4/encoder.go
@@ -0,0 +1,261 @@
+package form
+
+import (
+ "fmt"
+ "net/url"
+ "reflect"
+ "strconv"
+ "time"
+)
+
+type encoder struct {
+ e *Encoder
+ errs EncodeErrors
+ values url.Values
+ namespace []byte
+}
+
+func (e *encoder) setError(namespace []byte, err error) {
+ if e.errs == nil {
+ e.errs = make(EncodeErrors)
+ }
+
+ e.errs[string(namespace)] = err
+}
+
+func (e *encoder) setVal(namespace []byte, idx int, vals ...string) {
+
+ arr, ok := e.values[string(namespace)]
+ if ok {
+ arr = append(arr, vals...)
+ } else {
+ arr = vals
+ }
+
+ e.values[string(namespace)] = arr
+}
+
+func (e *encoder) traverseStruct(v reflect.Value, namespace []byte, idx int) {
+
+ typ := v.Type()
+ l := len(namespace)
+ first := l == 0
+
+ // anonymous structs will still work for caching as the whole definition is stored
+ // including tags
+ s, ok := e.e.structCache.Get(typ)
+ if !ok {
+ s = e.e.structCache.parseStruct(e.e.mode, v, typ, e.e.tagName)
+ }
+
+ for _, f := range s.fields {
+ namespace = namespace[:l]
+
+ if f.isAnonymous && e.e.embedAnonymous {
+ e.setFieldByType(v.Field(f.idx), namespace, idx, f.isOmitEmpty)
+ continue
+ }
+
+ if first {
+ namespace = append(namespace, f.name...)
+ } else {
+ namespace = append(namespace, e.e.namespacePrefix...)
+ namespace = append(namespace, f.name...)
+ namespace = append(namespace, e.e.namespaceSuffix...)
+ }
+
+ e.setFieldByType(v.Field(f.idx), namespace, idx, f.isOmitEmpty)
+ }
+}
+
+func (e *encoder) setFieldByType(current reflect.Value, namespace []byte, idx int, isOmitEmpty bool) {
+
+ if idx > -1 && current.Kind() == reflect.Ptr {
+ namespace = append(namespace, '[')
+ namespace = strconv.AppendInt(namespace, int64(idx), 10)
+ namespace = append(namespace, ']')
+ idx = -2
+ }
+
+ if isOmitEmpty && !hasValue(current) {
+ return
+ }
+ v, kind := ExtractType(current)
+
+ if e.e.customTypeFuncs != nil {
+
+ if cf, ok := e.e.customTypeFuncs[v.Type()]; ok {
+
+ arr, err := cf(v.Interface())
+ if err != nil {
+ e.setError(namespace, err)
+ return
+ }
+
+ if idx > -1 {
+ namespace = append(namespace, '[')
+ namespace = strconv.AppendInt(namespace, int64(idx), 10)
+ namespace = append(namespace, ']')
+ }
+
+ e.setVal(namespace, idx, arr...)
+ return
+ }
+ }
+
+ switch kind {
+ case reflect.Ptr, reflect.Interface, reflect.Invalid:
+ return
+
+ case reflect.String:
+
+ e.setVal(namespace, idx, v.String())
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+
+ e.setVal(namespace, idx, strconv.FormatUint(v.Uint(), 10))
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+
+ e.setVal(namespace, idx, strconv.FormatInt(v.Int(), 10))
+
+ case reflect.Float32:
+
+ e.setVal(namespace, idx, strconv.FormatFloat(v.Float(), 'f', -1, 32))
+
+ case reflect.Float64:
+
+ e.setVal(namespace, idx, strconv.FormatFloat(v.Float(), 'f', -1, 64))
+
+ case reflect.Bool:
+
+ e.setVal(namespace, idx, strconv.FormatBool(v.Bool()))
+
+ case reflect.Slice, reflect.Array:
+
+ if idx == -1 {
+
+ for i := 0; i < v.Len(); i++ {
+ e.setFieldByType(v.Index(i), namespace, i, false)
+ }
+
+ return
+ }
+
+ if idx > -1 {
+ namespace = append(namespace, '[')
+ namespace = strconv.AppendInt(namespace, int64(idx), 10)
+ namespace = append(namespace, ']')
+ }
+
+ namespace = append(namespace, '[')
+ l := len(namespace)
+
+ for i := 0; i < v.Len(); i++ {
+ namespace = namespace[:l]
+ namespace = strconv.AppendInt(namespace, int64(i), 10)
+ namespace = append(namespace, ']')
+ e.setFieldByType(v.Index(i), namespace, -2, false)
+ }
+
+ case reflect.Map:
+
+ if idx > -1 {
+ namespace = append(namespace, '[')
+ namespace = strconv.AppendInt(namespace, int64(idx), 10)
+ namespace = append(namespace, ']')
+ }
+
+ var valid bool
+ var s string
+ l := len(namespace)
+
+ for _, key := range v.MapKeys() {
+
+ namespace = namespace[:l]
+
+ if s, valid = e.getMapKey(key, namespace); !valid {
+ continue
+ }
+
+ namespace = append(namespace, '[')
+ namespace = append(namespace, s...)
+ namespace = append(namespace, ']')
+
+ e.setFieldByType(v.MapIndex(key), namespace, -2, false)
+ }
+
+ case reflect.Struct:
+
+ // if we get here then no custom time function declared so use RFC3339 by default
+ if v.Type() == timeType {
+
+ if idx > -1 {
+ namespace = append(namespace, '[')
+ namespace = strconv.AppendInt(namespace, int64(idx), 10)
+ namespace = append(namespace, ']')
+ }
+
+ e.setVal(namespace, idx, v.Interface().(time.Time).Format(time.RFC3339))
+ return
+ }
+
+ if idx == -1 {
+ e.traverseStruct(v, namespace, idx)
+ return
+ }
+
+ if idx > -1 {
+ namespace = append(namespace, '[')
+ namespace = strconv.AppendInt(namespace, int64(idx), 10)
+ namespace = append(namespace, ']')
+ }
+
+ e.traverseStruct(v, namespace, -2)
+ }
+}
+
+func (e *encoder) getMapKey(key reflect.Value, namespace []byte) (string, bool) {
+
+ v, kind := ExtractType(key)
+
+ if e.e.customTypeFuncs != nil {
+
+ if cf, ok := e.e.customTypeFuncs[v.Type()]; ok {
+ arr, err := cf(v.Interface())
+ if err != nil {
+ e.setError(namespace, err)
+ return "", false
+ }
+
+ return arr[0], true
+ }
+ }
+
+ switch kind {
+ case reflect.Interface, reflect.Ptr:
+ return "", false
+
+ case reflect.String:
+ return v.String(), true
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ return strconv.FormatUint(v.Uint(), 10), true
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return strconv.FormatInt(v.Int(), 10), true
+
+ case reflect.Float32:
+ return strconv.FormatFloat(v.Float(), 'f', -1, 32), true
+
+ case reflect.Float64:
+ return strconv.FormatFloat(v.Float(), 'f', -1, 64), true
+
+ case reflect.Bool:
+ return strconv.FormatBool(v.Bool()), true
+
+ default:
+ e.setError(namespace, fmt.Errorf("Unsupported Map Key '%v' Namespace '%s'", v.String(), namespace))
+ return "", false
+ }
+}