-
Notifications
You must be signed in to change notification settings - Fork 0
/
reflect.go
84 lines (73 loc) · 1.89 KB
/
reflect.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
package request
import "reflect"
// convertTo converts struct to any data format(result).
func convertTo(tagName string, param interface{}, result interface{}, fn func(result interface{}, key string, value interface{})) {
t := toType(param)
values := toValue(param)
resultSeed := typeCopy(result)
for i, max := 0, t.NumField(); i < max; i++ {
f := t.Field(i)
if f.PkgPath != "" && !f.Anonymous {
continue // skip private field
}
tag, opts := parseTag(f, tagName)
if tag == "-" {
continue // skip `-` tag
}
v := values.Field(i)
if opts.has("omitempty") && isZero(v) {
continue // skip zero-value when omitempty option exists in tag
}
if opts.has("squash") {
convertTo(tagName, v.Interface(), result, fn)
continue
}
name := getNameFromTag(f, tagName)
if opts.has("recursive") {
copy := typeCopy(resultSeed)
convertTo(tagName, v.Interface(), copy, fn)
fn(result, name, copy)
continue
}
fn(result, name, v.Interface())
}
}
// toValue converts any value to reflect.Value.
func toValue(p interface{}) reflect.Value {
v := reflect.ValueOf(p)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
return v
}
// toType converts any value to reflect.Type.
func toType(p interface{}) reflect.Type {
t := reflect.ValueOf(p).Type()
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
return t
}
// isZero checks the value is zero-value or not.
func isZero(v reflect.Value) bool {
zero := reflect.Zero(v.Type()).Interface()
value := v.Interface()
return reflect.DeepEqual(value, zero)
}
// typeCopy returns the copy of zero value from given type.
func typeCopy(v interface{}) interface{} {
rt := reflect.ValueOf(v).Type()
if rt.Kind() == reflect.Ptr {
rt = rt.Elem()
}
var rv reflect.Value
switch rt.Kind() {
case reflect.Map:
rv = reflect.MakeMap(rt)
case reflect.Slice:
rv = reflect.MakeSlice(rt, 0, 0)
default:
rv = reflect.New(rt)
}
return rv.Interface()
}