/
reflect.go
155 lines (140 loc) Β· 3.98 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
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package env
import (
"encoding"
"fmt"
"reflect"
"strconv"
"time"
)
var (
durationType = reflect.TypeOf(new(time.Duration)).Elem()
unmarshalerIface = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
)
// typeOf reports whether v's type is one of the provided types.
func typeOf(v reflect.Value, types ...reflect.Type) bool {
for _, t := range types {
if t == v.Type() {
return true
}
}
return false
}
// kindOf reports whether v's kind is one of the provided kinds.
func kindOf(v reflect.Value, kinds ...reflect.Kind) bool {
for _, k := range kinds {
if k == v.Kind() {
return true
}
}
return false
}
// implements reports whether v's type implements one of the provided
// interfaces.
func implements(v reflect.Value, ifaces ...reflect.Type) bool {
for _, iface := range ifaces {
if t := v.Type(); t.Implements(iface) || reflect.PtrTo(v.Type()).Implements(iface) {
return true
}
}
return false
}
// structPtr reports whether v is a non-nil struct pointer.
func structPtr(v reflect.Value) bool {
return v.IsValid() && v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct && !v.IsNil()
}
// setValue parses s based on v's type/kind and sets v's underlying value to the
// result.
func setValue(v reflect.Value, s string) error {
switch {
case typeOf(v, durationType):
return setDuration(v, s)
case implements(v, unmarshalerIface):
return setUnmarshaler(v, s)
case kindOf(v, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64):
return setInt(v, s)
case kindOf(v, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64):
return setUint(v, s)
case kindOf(v, reflect.Float32, reflect.Float64):
return setFloat(v, s)
case kindOf(v, reflect.Bool):
return setBool(v, s)
case kindOf(v, reflect.String):
return setString(v, s)
default:
return fmt.Errorf("%w %q", ErrUnsupportedType, v.Type())
}
}
// setInt parses an int value from s and sets v's underlying value to it.
func setInt(v reflect.Value, s string) error {
bits := v.Type().Bits()
i, err := strconv.ParseInt(s, 10, bits)
if err != nil {
return fmt.Errorf("parsing int: %w", err)
}
v.SetInt(i)
return nil
}
// setUint parses an uint value from s and sets v's underlying value to it.
func setUint(v reflect.Value, s string) error {
bits := v.Type().Bits()
u, err := strconv.ParseUint(s, 10, bits)
if err != nil {
return fmt.Errorf("parsing uint: %w", err)
}
v.SetUint(u)
return nil
}
// setFloat parses a float value from s and sets v's underlying value to it.
func setFloat(v reflect.Value, s string) error {
bits := v.Type().Bits()
f, err := strconv.ParseFloat(s, bits)
if err != nil {
return fmt.Errorf("parsing float: %w", err)
}
v.SetFloat(f)
return nil
}
// setBool parses a bool value from s and sets v's underlying value to it.
func setBool(v reflect.Value, s string) error {
b, err := strconv.ParseBool(s)
if err != nil {
return fmt.Errorf("parsing bool: %w", err)
}
v.SetBool(b)
return nil
}
// setString sets v's underlying value to s.
func setString(v reflect.Value, s string) error {
v.SetString(s)
return nil
}
// setDuration parses a duration value from s and sets v's underlying value to
// it.
func setDuration(v reflect.Value, s string) error {
d, err := time.ParseDuration(s)
if err != nil {
return fmt.Errorf("parsing duration: %w", err)
}
v.Set(reflect.ValueOf(d))
return nil
}
// setUnmarshaler calls v's UnmarshalText method with s as the text argument.
func setUnmarshaler(v reflect.Value, s string) error {
u := v.Addr().Interface().(encoding.TextUnmarshaler)
if err := u.UnmarshalText([]byte(s)); err != nil {
return fmt.Errorf("unmarshaling text: %w", err)
}
return nil
}
// setSlice creates a new slice of the values parsed from s and sets v's
// underlying value to it.
func setSlice(v reflect.Value, s []string) error {
slice := reflect.MakeSlice(v.Type(), len(s), cap(s))
for i := 0; i < slice.Len(); i++ {
if err := setValue(slice.Index(i), s[i]); err != nil {
return err
}
}
v.Set(slice)
return nil
}