Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / go-ini / ini / struct.go
1 // Copyright 2014 Unknwon
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"): you may
4 // not use this file except in compliance with the License. You may obtain
5 // a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations
13 // under the License.
14
15 package ini
16
17 import (
18         "bytes"
19         "errors"
20         "fmt"
21         "reflect"
22         "time"
23         "unicode"
24 )
25
26 // NameMapper represents a ini tag name mapper.
27 type NameMapper func(string) string
28
29 // Built-in name getters.
30 var (
31         // AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE.
32         AllCapsUnderscore NameMapper = func(raw string) string {
33                 newstr := make([]rune, 0, len(raw))
34                 for i, chr := range raw {
35                         if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
36                                 if i > 0 {
37                                         newstr = append(newstr, '_')
38                                 }
39                         }
40                         newstr = append(newstr, unicode.ToUpper(chr))
41                 }
42                 return string(newstr)
43         }
44         // TitleUnderscore converts to format title_underscore.
45         TitleUnderscore NameMapper = func(raw string) string {
46                 newstr := make([]rune, 0, len(raw))
47                 for i, chr := range raw {
48                         if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
49                                 if i > 0 {
50                                         newstr = append(newstr, '_')
51                                 }
52                                 chr -= ('A' - 'a')
53                         }
54                         newstr = append(newstr, chr)
55                 }
56                 return string(newstr)
57         }
58 )
59
60 func (s *Section) parseFieldName(raw, actual string) string {
61         if len(actual) > 0 {
62                 return actual
63         }
64         if s.f.NameMapper != nil {
65                 return s.f.NameMapper(raw)
66         }
67         return raw
68 }
69
70 func parseDelim(actual string) string {
71         if len(actual) > 0 {
72                 return actual
73         }
74         return ","
75 }
76
77 var reflectTime = reflect.TypeOf(time.Now()).Kind()
78
79 // setWithProperType sets proper value to field based on its type,
80 // but it does not return error for failing parsing,
81 // because we want to use default value that is already assigned to strcut.
82 func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error {
83         switch t.Kind() {
84         case reflect.String:
85                 if len(key.String()) == 0 {
86                         return nil
87                 }
88                 field.SetString(key.String())
89         case reflect.Bool:
90                 boolVal, err := key.Bool()
91                 if err != nil {
92                         return nil
93                 }
94                 field.SetBool(boolVal)
95         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
96                 durationVal, err := key.Duration()
97                 if err == nil {
98                         field.Set(reflect.ValueOf(durationVal))
99                         return nil
100                 }
101
102                 intVal, err := key.Int64()
103                 if err != nil {
104                         return nil
105                 }
106                 field.SetInt(intVal)
107         //      byte is an alias for uint8, so supporting uint8 breaks support for byte
108         case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
109                 durationVal, err := key.Duration()
110                 if err == nil {
111                         field.Set(reflect.ValueOf(durationVal))
112                         return nil
113                 }
114
115                 uintVal, err := key.Uint64()
116                 if err != nil {
117                         return nil
118                 }
119                 field.SetUint(uintVal)
120
121         case reflect.Float64:
122                 floatVal, err := key.Float64()
123                 if err != nil {
124                         return nil
125                 }
126                 field.SetFloat(floatVal)
127         case reflectTime:
128                 timeVal, err := key.Time()
129                 if err != nil {
130                         return nil
131                 }
132                 field.Set(reflect.ValueOf(timeVal))
133         case reflect.Slice:
134                 vals := key.Strings(delim)
135                 numVals := len(vals)
136                 if numVals == 0 {
137                         return nil
138                 }
139
140                 sliceOf := field.Type().Elem().Kind()
141
142                 var times []time.Time
143                 if sliceOf == reflectTime {
144                         times = key.Times(delim)
145                 }
146
147                 slice := reflect.MakeSlice(field.Type(), numVals, numVals)
148                 for i := 0; i < numVals; i++ {
149                         switch sliceOf {
150                         case reflectTime:
151                                 slice.Index(i).Set(reflect.ValueOf(times[i]))
152                         default:
153                                 slice.Index(i).Set(reflect.ValueOf(vals[i]))
154                         }
155                 }
156                 field.Set(slice)
157         default:
158                 return fmt.Errorf("unsupported type '%s'", t)
159         }
160         return nil
161 }
162
163 func (s *Section) mapTo(val reflect.Value) error {
164         if val.Kind() == reflect.Ptr {
165                 val = val.Elem()
166         }
167         typ := val.Type()
168
169         for i := 0; i < typ.NumField(); i++ {
170                 field := val.Field(i)
171                 tpField := typ.Field(i)
172
173                 tag := tpField.Tag.Get("ini")
174                 if tag == "-" {
175                         continue
176                 }
177
178                 fieldName := s.parseFieldName(tpField.Name, tag)
179                 if len(fieldName) == 0 || !field.CanSet() {
180                         continue
181                 }
182
183                 isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous
184                 isStruct := tpField.Type.Kind() == reflect.Struct
185                 if isAnonymous {
186                         field.Set(reflect.New(tpField.Type.Elem()))
187                 }
188
189                 if isAnonymous || isStruct {
190                         if sec, err := s.f.GetSection(fieldName); err == nil {
191                                 if err = sec.mapTo(field); err != nil {
192                                         return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
193                                 }
194                                 continue
195                         }
196                 }
197
198                 if key, err := s.GetKey(fieldName); err == nil {
199                         if err = setWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil {
200                                 return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
201                         }
202                 }
203         }
204         return nil
205 }
206
207 // MapTo maps section to given struct.
208 func (s *Section) MapTo(v interface{}) error {
209         typ := reflect.TypeOf(v)
210         val := reflect.ValueOf(v)
211         if typ.Kind() == reflect.Ptr {
212                 typ = typ.Elem()
213                 val = val.Elem()
214         } else {
215                 return errors.New("cannot map to non-pointer struct")
216         }
217
218         return s.mapTo(val)
219 }
220
221 // MapTo maps file to given struct.
222 func (f *File) MapTo(v interface{}) error {
223         return f.Section("").MapTo(v)
224 }
225
226 // MapTo maps data sources to given struct with name mapper.
227 func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
228         cfg, err := Load(source, others...)
229         if err != nil {
230                 return err
231         }
232         cfg.NameMapper = mapper
233         return cfg.MapTo(v)
234 }
235
236 // MapTo maps data sources to given struct.
237 func MapTo(v, source interface{}, others ...interface{}) error {
238         return MapToWithMapper(v, nil, source, others...)
239 }
240
241 // reflectWithProperType does the opposite thing with setWithProperType.
242 func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error {
243         switch t.Kind() {
244         case reflect.String:
245                 key.SetValue(field.String())
246         case reflect.Bool,
247                 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
248                 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
249                 reflect.Float64,
250                 reflectTime:
251                 key.SetValue(fmt.Sprint(field))
252         case reflect.Slice:
253                 vals := field.Slice(0, field.Len())
254                 if field.Len() == 0 {
255                         return nil
256                 }
257
258                 var buf bytes.Buffer
259                 isTime := fmt.Sprint(field.Type()) == "[]time.Time"
260                 for i := 0; i < field.Len(); i++ {
261                         if isTime {
262                                 buf.WriteString(vals.Index(i).Interface().(time.Time).Format(time.RFC3339))
263                         } else {
264                                 buf.WriteString(fmt.Sprint(vals.Index(i)))
265                         }
266                         buf.WriteString(delim)
267                 }
268                 key.SetValue(buf.String()[:buf.Len()-1])
269         default:
270                 return fmt.Errorf("unsupported type '%s'", t)
271         }
272         return nil
273 }
274
275 func (s *Section) reflectFrom(val reflect.Value) error {
276         if val.Kind() == reflect.Ptr {
277                 val = val.Elem()
278         }
279         typ := val.Type()
280
281         for i := 0; i < typ.NumField(); i++ {
282                 field := val.Field(i)
283                 tpField := typ.Field(i)
284
285                 tag := tpField.Tag.Get("ini")
286                 if tag == "-" {
287                         continue
288                 }
289
290                 fieldName := s.parseFieldName(tpField.Name, tag)
291                 if len(fieldName) == 0 || !field.CanSet() {
292                         continue
293                 }
294
295                 if (tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous) ||
296                         (tpField.Type.Kind() == reflect.Struct) {
297                         // Note: The only error here is section doesn't exist.
298                         sec, err := s.f.GetSection(fieldName)
299                         if err != nil {
300                                 // Note: fieldName can never be empty here, ignore error.
301                                 sec, _ = s.f.NewSection(fieldName)
302                         }
303                         if err = sec.reflectFrom(field); err != nil {
304                                 return fmt.Errorf("error reflecting field(%s): %v", fieldName, err)
305                         }
306                         continue
307                 }
308
309                 // Note: Same reason as secion.
310                 key, err := s.GetKey(fieldName)
311                 if err != nil {
312                         key, _ = s.NewKey(fieldName, "")
313                 }
314                 if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil {
315                         return fmt.Errorf("error reflecting field(%s): %v", fieldName, err)
316                 }
317
318         }
319         return nil
320 }
321
322 // ReflectFrom reflects secion from given struct.
323 func (s *Section) ReflectFrom(v interface{}) error {
324         typ := reflect.TypeOf(v)
325         val := reflect.ValueOf(v)
326         if typ.Kind() == reflect.Ptr {
327                 typ = typ.Elem()
328                 val = val.Elem()
329         } else {
330                 return errors.New("cannot reflect from non-pointer struct")
331         }
332
333         return s.reflectFrom(val)
334 }
335
336 // ReflectFrom reflects file from given struct.
337 func (f *File) ReflectFrom(v interface{}) error {
338         return f.Section("").ReflectFrom(v)
339 }
340
341 // ReflectFrom reflects data sources from given struct with name mapper.
342 func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error {
343         cfg.NameMapper = mapper
344         return cfg.ReflectFrom(v)
345 }
346
347 // ReflectFrom reflects data sources from given struct.
348 func ReflectFrom(cfg *File, v interface{}) error {
349         return ReflectFromWithMapper(cfg, v, nil)
350 }