This repository has been archived by the owner on Feb 22, 2019. It is now read-only.
/
encoder.go
130 lines (108 loc) · 2.6 KB
/
encoder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package urlvalues
import (
"reflect"
"strconv"
"strings"
)
// Encoder encodes values from a struct into url.Values.
type Encoder struct {
TagID string
}
// NewEncoder returns a new Encoder with defaults.
func NewEncoder() *Encoder {
return &Encoder{TagID: "url"}
}
// SetAliasTag changes the tag used to locate urlvalues annotations. The default
// value is "url"
func (e *Encoder) SetAliasTag(tag string) *Encoder {
e.TagID = tag
return e
}
// Encode encodes a struct into map[string][]string.
//
// Intended for use with url.Values.
func (e *Encoder) Encode(src interface{}, dst map[string][]string) error {
v := reflect.ValueOf(src)
if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
v = v.Elem()
}
return e.encode(v, dst)
}
func (e *Encoder) encode(v reflect.Value, dst map[string][]string) error {
var opts string
var value string
t := v.Type()
for i := 0; i < v.NumField(); i++ {
tag := t.Field(i).Tag.Get(e.TagID)
name := tag
if idx := strings.Index(tag, ","); idx != -1 {
name = tag[:idx]
opts = tag[idx+1:]
}
if name == "-" {
continue
}
encFunc, recurse := encoder(v.Field(i).Type())
if recurse {
e.encode(v.Field(i), dst)
continue
}
value = encFunc(v.Field(i))
if value == "" && strings.Contains(opts, "omitempty") {
continue
}
dst[name] = []string{value}
}
return nil
}
func encoder(t reflect.Type) (func(v reflect.Value) string, bool) {
switch t.Kind() {
case reflect.Bool:
return boolEncoder, false
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return intEncoder, false
case reflect.Float32:
return float32Encoder, false
case reflect.Float64:
return float64Encoder, false
case reflect.Ptr:
f, recurse := ptrEncoder(t)
return f, recurse
case reflect.String:
return stringEncoder, false
case reflect.Struct:
return unsupportedEncoder, true
default:
return unsupportedEncoder, false
}
}
func boolEncoder(v reflect.Value) string {
if v.Bool() {
return "1"
}
return "0"
}
func intEncoder(v reflect.Value) string {
return strconv.Itoa(int(v.Int()))
}
func float32Encoder(v reflect.Value) string {
return strconv.FormatFloat(v.Float(), 'f', 6, 32)
}
func float64Encoder(v reflect.Value) string {
return strconv.FormatFloat(v.Float(), 'f', 6, 64)
}
func ptrEncoder(t reflect.Type) (func(v reflect.Value) string, bool) {
f, recurse := encoder(t.Elem())
return func(v reflect.Value) string {
if v.IsNil() {
return "null"
}
return f(v.Elem())
}, recurse
}
func stringEncoder(v reflect.Value) string {
return v.String()
}
func unsupportedEncoder(v reflect.Value) string {
return ""
}