OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / magiconair / properties / decode.go
1 // Copyright 2017 Frank Schroeder. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package properties
6
7 import (
8         "fmt"
9         "reflect"
10         "strconv"
11         "strings"
12         "time"
13 )
14
15 // Decode assigns property values to exported fields of a struct.
16 //
17 // Decode traverses v recursively and returns an error if a value cannot be
18 // converted to the field type or a required value is missing for a field.
19 //
20 // The following type dependent decodings are used:
21 //
22 // String, boolean, numeric fields have the value of the property key assigned.
23 // The property key name is the name of the field. A different key and a default
24 // value can be set in the field's tag. Fields without default value are
25 // required. If the value cannot be converted to the field type an error is
26 // returned.
27 //
28 // time.Duration fields have the result of time.ParseDuration() assigned.
29 //
30 // time.Time fields have the vaule of time.Parse() assigned. The default layout
31 // is time.RFC3339 but can be set in the field's tag.
32 //
33 // Arrays and slices of string, boolean, numeric, time.Duration and time.Time
34 // fields have the value interpreted as a comma separated list of values. The
35 // individual values are trimmed of whitespace and empty values are ignored. A
36 // default value can be provided as a semicolon separated list in the field's
37 // tag.
38 //
39 // Struct fields are decoded recursively using the field name plus "." as
40 // prefix. The prefix (without dot) can be overridden in the field's tag.
41 // Default values are not supported in the field's tag. Specify them on the
42 // fields of the inner struct instead.
43 //
44 // Map fields must have a key of type string and are decoded recursively by
45 // using the field's name plus ".' as prefix and the next element of the key
46 // name as map key. The prefix (without dot) can be overridden in the field's
47 // tag. Default values are not supported.
48 //
49 // Examples:
50 //
51 //     // Field is ignored.
52 //     Field int `properties:"-"`
53 //
54 //     // Field is assigned value of 'Field'.
55 //     Field int
56 //
57 //     // Field is assigned value of 'myName'.
58 //     Field int `properties:"myName"`
59 //
60 //     // Field is assigned value of key 'myName' and has a default
61 //     // value 15 if the key does not exist.
62 //     Field int `properties:"myName,default=15"`
63 //
64 //     // Field is assigned value of key 'Field' and has a default
65 //     // value 15 if the key does not exist.
66 //     Field int `properties:",default=15"`
67 //
68 //     // Field is assigned value of key 'date' and the date
69 //     // is in format 2006-01-02
70 //     Field time.Time `properties:"date,layout=2006-01-02"`
71 //
72 //     // Field is assigned the non-empty and whitespace trimmed
73 //     // values of key 'Field' split by commas.
74 //     Field []string
75 //
76 //     // Field is assigned the non-empty and whitespace trimmed
77 //     // values of key 'Field' split by commas and has a default
78 //     // value ["a", "b", "c"] if the key does not exist.
79 //     Field []string `properties:",default=a;b;c"`
80 //
81 //     // Field is decoded recursively with "Field." as key prefix.
82 //     Field SomeStruct
83 //
84 //     // Field is decoded recursively with "myName." as key prefix.
85 //     Field SomeStruct `properties:"myName"`
86 //
87 //     // Field is decoded recursively with "Field." as key prefix
88 //     // and the next dotted element of the key as map key.
89 //     Field map[string]string
90 //
91 //     // Field is decoded recursively with "myName." as key prefix
92 //     // and the next dotted element of the key as map key.
93 //     Field map[string]string `properties:"myName"`
94 func (p *Properties) Decode(x interface{}) error {
95         t, v := reflect.TypeOf(x), reflect.ValueOf(x)
96         if t.Kind() != reflect.Ptr || v.Elem().Type().Kind() != reflect.Struct {
97                 return fmt.Errorf("not a pointer to struct: %s", t)
98         }
99         if err := dec(p, "", nil, nil, v); err != nil {
100                 return err
101         }
102         return nil
103 }
104
105 func dec(p *Properties, key string, def *string, opts map[string]string, v reflect.Value) error {
106         t := v.Type()
107
108         // value returns the property value for key or the default if provided.
109         value := func() (string, error) {
110                 if val, ok := p.Get(key); ok {
111                         return val, nil
112                 }
113                 if def != nil {
114                         return *def, nil
115                 }
116                 return "", fmt.Errorf("missing required key %s", key)
117         }
118
119         // conv converts a string to a value of the given type.
120         conv := func(s string, t reflect.Type) (val reflect.Value, err error) {
121                 var v interface{}
122
123                 switch {
124                 case isDuration(t):
125                         v, err = time.ParseDuration(s)
126
127                 case isTime(t):
128                         layout := opts["layout"]
129                         if layout == "" {
130                                 layout = time.RFC3339
131                         }
132                         v, err = time.Parse(layout, s)
133
134                 case isBool(t):
135                         v, err = boolVal(s), nil
136
137                 case isString(t):
138                         v, err = s, nil
139
140                 case isFloat(t):
141                         v, err = strconv.ParseFloat(s, 64)
142
143                 case isInt(t):
144                         v, err = strconv.ParseInt(s, 10, 64)
145
146                 case isUint(t):
147                         v, err = strconv.ParseUint(s, 10, 64)
148
149                 default:
150                         return reflect.Zero(t), fmt.Errorf("unsupported type %s", t)
151                 }
152                 if err != nil {
153                         return reflect.Zero(t), err
154                 }
155                 return reflect.ValueOf(v).Convert(t), nil
156         }
157
158         // keydef returns the property key and the default value based on the
159         // name of the struct field and the options in the tag.
160         keydef := func(f reflect.StructField) (string, *string, map[string]string) {
161                 _key, _opts := parseTag(f.Tag.Get("properties"))
162
163                 var _def *string
164                 if d, ok := _opts["default"]; ok {
165                         _def = &d
166                 }
167                 if _key != "" {
168                         return _key, _def, _opts
169                 }
170                 return f.Name, _def, _opts
171         }
172
173         switch {
174         case isDuration(t) || isTime(t) || isBool(t) || isString(t) || isFloat(t) || isInt(t) || isUint(t):
175                 s, err := value()
176                 if err != nil {
177                         return err
178                 }
179                 val, err := conv(s, t)
180                 if err != nil {
181                         return err
182                 }
183                 v.Set(val)
184
185         case isPtr(t):
186                 return dec(p, key, def, opts, v.Elem())
187
188         case isStruct(t):
189                 for i := 0; i < v.NumField(); i++ {
190                         fv := v.Field(i)
191                         fk, def, opts := keydef(t.Field(i))
192                         if !fv.CanSet() {
193                                 return fmt.Errorf("cannot set %s", t.Field(i).Name)
194                         }
195                         if fk == "-" {
196                                 continue
197                         }
198                         if key != "" {
199                                 fk = key + "." + fk
200                         }
201                         if err := dec(p, fk, def, opts, fv); err != nil {
202                                 return err
203                         }
204                 }
205                 return nil
206
207         case isArray(t):
208                 val, err := value()
209                 if err != nil {
210                         return err
211                 }
212                 vals := split(val, ";")
213                 a := reflect.MakeSlice(t, 0, len(vals))
214                 for _, s := range vals {
215                         val, err := conv(s, t.Elem())
216                         if err != nil {
217                                 return err
218                         }
219                         a = reflect.Append(a, val)
220                 }
221                 v.Set(a)
222
223         case isMap(t):
224                 valT := t.Elem()
225                 m := reflect.MakeMap(t)
226                 for postfix := range p.FilterStripPrefix(key + ".").m {
227                         pp := strings.SplitN(postfix, ".", 2)
228                         mk, mv := pp[0], reflect.New(valT)
229                         if err := dec(p, key+"."+mk, nil, nil, mv); err != nil {
230                                 return err
231                         }
232                         m.SetMapIndex(reflect.ValueOf(mk), mv.Elem())
233                 }
234                 v.Set(m)
235
236         default:
237                 return fmt.Errorf("unsupported type %s", t)
238         }
239         return nil
240 }
241
242 // split splits a string on sep, trims whitespace of elements
243 // and omits empty elements
244 func split(s string, sep string) []string {
245         var a []string
246         for _, v := range strings.Split(s, sep) {
247                 if v = strings.TrimSpace(v); v != "" {
248                         a = append(a, v)
249                 }
250         }
251         return a
252 }
253
254 // parseTag parses a "key,k=v,k=v,..."
255 func parseTag(tag string) (key string, opts map[string]string) {
256         opts = map[string]string{}
257         for i, s := range strings.Split(tag, ",") {
258                 if i == 0 {
259                         key = s
260                         continue
261                 }
262
263                 pp := strings.SplitN(s, "=", 2)
264                 if len(pp) == 1 {
265                         opts[pp[0]] = ""
266                 } else {
267                         opts[pp[0]] = pp[1]
268                 }
269         }
270         return key, opts
271 }
272
273 func isArray(t reflect.Type) bool    { return t.Kind() == reflect.Array || t.Kind() == reflect.Slice }
274 func isBool(t reflect.Type) bool     { return t.Kind() == reflect.Bool }
275 func isDuration(t reflect.Type) bool { return t == reflect.TypeOf(time.Second) }
276 func isMap(t reflect.Type) bool      { return t.Kind() == reflect.Map }
277 func isPtr(t reflect.Type) bool      { return t.Kind() == reflect.Ptr }
278 func isString(t reflect.Type) bool   { return t.Kind() == reflect.String }
279 func isStruct(t reflect.Type) bool   { return t.Kind() == reflect.Struct }
280 func isTime(t reflect.Type) bool     { return t == reflect.TypeOf(time.Time{}) }
281 func isFloat(t reflect.Type) bool {
282         return t.Kind() == reflect.Float32 || t.Kind() == reflect.Float64
283 }
284 func isInt(t reflect.Type) bool {
285         return t.Kind() == reflect.Int || t.Kind() == reflect.Int8 || t.Kind() == reflect.Int16 || t.Kind() == reflect.Int32 || t.Kind() == reflect.Int64
286 }
287 func isUint(t reflect.Type) bool {
288         return t.Kind() == reflect.Uint || t.Kind() == reflect.Uint8 || t.Kind() == reflect.Uint16 || t.Kind() == reflect.Uint32 || t.Kind() == reflect.Uint64
289 }