aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/gopkg.in/ini.v1/struct.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gopkg.in/ini.v1/struct.go')
-rw-r--r--vendor/gopkg.in/ini.v1/struct.go747
1 files changed, 747 insertions, 0 deletions
diff --git a/vendor/gopkg.in/ini.v1/struct.go b/vendor/gopkg.in/ini.v1/struct.go
new file mode 100644
index 0000000..a486b2f
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/struct.go
@@ -0,0 +1,747 @@
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
15package ini
16
17import (
18 "bytes"
19 "errors"
20 "fmt"
21 "reflect"
22 "strings"
23 "time"
24 "unicode"
25)
26
27// NameMapper represents a ini tag name mapper.
28type NameMapper func(string) string
29
30// Built-in name getters.
31var (
32 // SnackCase converts to format SNACK_CASE.
33 SnackCase NameMapper = func(raw string) string {
34 newstr := make([]rune, 0, len(raw))
35 for i, chr := range raw {
36 if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
37 if i > 0 {
38 newstr = append(newstr, '_')
39 }
40 }
41 newstr = append(newstr, unicode.ToUpper(chr))
42 }
43 return string(newstr)
44 }
45 // TitleUnderscore converts to format title_underscore.
46 TitleUnderscore NameMapper = func(raw string) string {
47 newstr := make([]rune, 0, len(raw))
48 for i, chr := range raw {
49 if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
50 if i > 0 {
51 newstr = append(newstr, '_')
52 }
53 chr -= 'A' - 'a'
54 }
55 newstr = append(newstr, chr)
56 }
57 return string(newstr)
58 }
59)
60
61func (s *Section) parseFieldName(raw, actual string) string {
62 if len(actual) > 0 {
63 return actual
64 }
65 if s.f.NameMapper != nil {
66 return s.f.NameMapper(raw)
67 }
68 return raw
69}
70
71func parseDelim(actual string) string {
72 if len(actual) > 0 {
73 return actual
74 }
75 return ","
76}
77
78var reflectTime = reflect.TypeOf(time.Now()).Kind()
79
80// setSliceWithProperType sets proper values to slice based on its type.
81func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error {
82 var strs []string
83 if allowShadow {
84 strs = key.StringsWithShadows(delim)
85 } else {
86 strs = key.Strings(delim)
87 }
88
89 numVals := len(strs)
90 if numVals == 0 {
91 return nil
92 }
93
94 var vals interface{}
95 var err error
96
97 sliceOf := field.Type().Elem().Kind()
98 switch sliceOf {
99 case reflect.String:
100 vals = strs
101 case reflect.Int:
102 vals, err = key.parseInts(strs, true, false)
103 case reflect.Int64:
104 vals, err = key.parseInt64s(strs, true, false)
105 case reflect.Uint:
106 vals, err = key.parseUints(strs, true, false)
107 case reflect.Uint64:
108 vals, err = key.parseUint64s(strs, true, false)
109 case reflect.Float64:
110 vals, err = key.parseFloat64s(strs, true, false)
111 case reflect.Bool:
112 vals, err = key.parseBools(strs, true, false)
113 case reflectTime:
114 vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false)
115 default:
116 return fmt.Errorf("unsupported type '[]%s'", sliceOf)
117 }
118 if err != nil && isStrict {
119 return err
120 }
121
122 slice := reflect.MakeSlice(field.Type(), numVals, numVals)
123 for i := 0; i < numVals; i++ {
124 switch sliceOf {
125 case reflect.String:
126 slice.Index(i).Set(reflect.ValueOf(vals.([]string)[i]))
127 case reflect.Int:
128 slice.Index(i).Set(reflect.ValueOf(vals.([]int)[i]))
129 case reflect.Int64:
130 slice.Index(i).Set(reflect.ValueOf(vals.([]int64)[i]))
131 case reflect.Uint:
132 slice.Index(i).Set(reflect.ValueOf(vals.([]uint)[i]))
133 case reflect.Uint64:
134 slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i]))
135 case reflect.Float64:
136 slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i]))
137 case reflect.Bool:
138 slice.Index(i).Set(reflect.ValueOf(vals.([]bool)[i]))
139 case reflectTime:
140 slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i]))
141 }
142 }
143 field.Set(slice)
144 return nil
145}
146
147func wrapStrictError(err error, isStrict bool) error {
148 if isStrict {
149 return err
150 }
151 return nil
152}
153
154// setWithProperType sets proper value to field based on its type,
155// but it does not return error for failing parsing,
156// because we want to use default value that is already assigned to struct.
157func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error {
158 vt := t
159 isPtr := t.Kind() == reflect.Ptr
160 if isPtr {
161 vt = t.Elem()
162 }
163 switch vt.Kind() {
164 case reflect.String:
165 stringVal := key.String()
166 if isPtr {
167 field.Set(reflect.ValueOf(&stringVal))
168 } else if len(stringVal) > 0 {
169 field.SetString(key.String())
170 }
171 case reflect.Bool:
172 boolVal, err := key.Bool()
173 if err != nil {
174 return wrapStrictError(err, isStrict)
175 }
176 if isPtr {
177 field.Set(reflect.ValueOf(&boolVal))
178 } else {
179 field.SetBool(boolVal)
180 }
181 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
182 // ParseDuration will not return err for `0`, so check the type name
183 if vt.Name() == "Duration" {
184 durationVal, err := key.Duration()
185 if err != nil {
186 if intVal, err := key.Int64(); err == nil {
187 field.SetInt(intVal)
188 return nil
189 }
190 return wrapStrictError(err, isStrict)
191 }
192 if isPtr {
193 field.Set(reflect.ValueOf(&durationVal))
194 } else if int64(durationVal) > 0 {
195 field.Set(reflect.ValueOf(durationVal))
196 }
197 return nil
198 }
199
200 intVal, err := key.Int64()
201 if err != nil {
202 return wrapStrictError(err, isStrict)
203 }
204 if isPtr {
205 pv := reflect.New(t.Elem())
206 pv.Elem().SetInt(intVal)
207 field.Set(pv)
208 } else {
209 field.SetInt(intVal)
210 }
211 // byte is an alias for uint8, so supporting uint8 breaks support for byte
212 case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
213 durationVal, err := key.Duration()
214 // Skip zero value
215 if err == nil && uint64(durationVal) > 0 {
216 if isPtr {
217 field.Set(reflect.ValueOf(&durationVal))
218 } else {
219 field.Set(reflect.ValueOf(durationVal))
220 }
221 return nil
222 }
223
224 uintVal, err := key.Uint64()
225 if err != nil {
226 return wrapStrictError(err, isStrict)
227 }
228 if isPtr {
229 pv := reflect.New(t.Elem())
230 pv.Elem().SetUint(uintVal)
231 field.Set(pv)
232 } else {
233 field.SetUint(uintVal)
234 }
235
236 case reflect.Float32, reflect.Float64:
237 floatVal, err := key.Float64()
238 if err != nil {
239 return wrapStrictError(err, isStrict)
240 }
241 if isPtr {
242 pv := reflect.New(t.Elem())
243 pv.Elem().SetFloat(floatVal)
244 field.Set(pv)
245 } else {
246 field.SetFloat(floatVal)
247 }
248 case reflectTime:
249 timeVal, err := key.Time()
250 if err != nil {
251 return wrapStrictError(err, isStrict)
252 }
253 if isPtr {
254 field.Set(reflect.ValueOf(&timeVal))
255 } else {
256 field.Set(reflect.ValueOf(timeVal))
257 }
258 case reflect.Slice:
259 return setSliceWithProperType(key, field, delim, allowShadow, isStrict)
260 default:
261 return fmt.Errorf("unsupported type %q", t)
262 }
263 return nil
264}
265
266func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool, allowNonUnique bool, extends bool) {
267 opts := strings.SplitN(tag, ",", 5)
268 rawName = opts[0]
269 for _, opt := range opts[1:] {
270 omitEmpty = omitEmpty || (opt == "omitempty")
271 allowShadow = allowShadow || (opt == "allowshadow")
272 allowNonUnique = allowNonUnique || (opt == "nonunique")
273 extends = extends || (opt == "extends")
274 }
275 return rawName, omitEmpty, allowShadow, allowNonUnique, extends
276}
277
278// mapToField maps the given value to the matching field of the given section.
279// The sectionIndex is the index (if non unique sections are enabled) to which the value should be added.
280func (s *Section) mapToField(val reflect.Value, isStrict bool, sectionIndex int, sectionName string) error {
281 if val.Kind() == reflect.Ptr {
282 val = val.Elem()
283 }
284 typ := val.Type()
285
286 for i := 0; i < typ.NumField(); i++ {
287 field := val.Field(i)
288 tpField := typ.Field(i)
289
290 tag := tpField.Tag.Get("ini")
291 if tag == "-" {
292 continue
293 }
294
295 rawName, _, allowShadow, allowNonUnique, extends := parseTagOptions(tag)
296 fieldName := s.parseFieldName(tpField.Name, rawName)
297 if len(fieldName) == 0 || !field.CanSet() {
298 continue
299 }
300
301 isStruct := tpField.Type.Kind() == reflect.Struct
302 isStructPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct
303 isAnonymousPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous
304 if isAnonymousPtr {
305 field.Set(reflect.New(tpField.Type.Elem()))
306 }
307
308 if extends && (isAnonymousPtr || (isStruct && tpField.Anonymous)) {
309 if isStructPtr && field.IsNil() {
310 field.Set(reflect.New(tpField.Type.Elem()))
311 }
312 fieldSection := s
313 if rawName != "" {
314 sectionName = s.name + s.f.options.ChildSectionDelimiter + rawName
315 if secs, err := s.f.SectionsByName(sectionName); err == nil && sectionIndex < len(secs) {
316 fieldSection = secs[sectionIndex]
317 }
318 }
319 if err := fieldSection.mapToField(field, isStrict, sectionIndex, sectionName); err != nil {
320 return fmt.Errorf("map to field %q: %v", fieldName, err)
321 }
322 } else if isAnonymousPtr || isStruct || isStructPtr {
323 if secs, err := s.f.SectionsByName(fieldName); err == nil {
324 if len(secs) <= sectionIndex {
325 return fmt.Errorf("there are not enough sections (%d <= %d) for the field %q", len(secs), sectionIndex, fieldName)
326 }
327 // Only set the field to non-nil struct value if we have a section for it.
328 // Otherwise, we end up with a non-nil struct ptr even though there is no data.
329 if isStructPtr && field.IsNil() {
330 field.Set(reflect.New(tpField.Type.Elem()))
331 }
332 if err = secs[sectionIndex].mapToField(field, isStrict, sectionIndex, fieldName); err != nil {
333 return fmt.Errorf("map to field %q: %v", fieldName, err)
334 }
335 continue
336 }
337 }
338
339 // Map non-unique sections
340 if allowNonUnique && tpField.Type.Kind() == reflect.Slice {
341 newField, err := s.mapToSlice(fieldName, field, isStrict)
342 if err != nil {
343 return fmt.Errorf("map to slice %q: %v", fieldName, err)
344 }
345
346 field.Set(newField)
347 continue
348 }
349
350 if key, err := s.GetKey(fieldName); err == nil {
351 delim := parseDelim(tpField.Tag.Get("delim"))
352 if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil {
353 return fmt.Errorf("set field %q: %v", fieldName, err)
354 }
355 }
356 }
357 return nil
358}
359
360// mapToSlice maps all sections with the same name and returns the new value.
361// The type of the Value must be a slice.
362func (s *Section) mapToSlice(secName string, val reflect.Value, isStrict bool) (reflect.Value, error) {
363 secs, err := s.f.SectionsByName(secName)
364 if err != nil {
365 return reflect.Value{}, err
366 }
367
368 typ := val.Type().Elem()
369 for i, sec := range secs {
370 elem := reflect.New(typ)
371 if err = sec.mapToField(elem, isStrict, i, sec.name); err != nil {
372 return reflect.Value{}, fmt.Errorf("map to field from section %q: %v", secName, err)
373 }
374
375 val = reflect.Append(val, elem.Elem())
376 }
377 return val, nil
378}
379
380// mapTo maps a section to object v.
381func (s *Section) mapTo(v interface{}, isStrict bool) error {
382 typ := reflect.TypeOf(v)
383 val := reflect.ValueOf(v)
384 if typ.Kind() == reflect.Ptr {
385 typ = typ.Elem()
386 val = val.Elem()
387 } else {
388 return errors.New("not a pointer to a struct")
389 }
390
391 if typ.Kind() == reflect.Slice {
392 newField, err := s.mapToSlice(s.name, val, isStrict)
393 if err != nil {
394 return err
395 }
396
397 val.Set(newField)
398 return nil
399 }
400
401 return s.mapToField(val, isStrict, 0, s.name)
402}
403
404// MapTo maps section to given struct.
405func (s *Section) MapTo(v interface{}) error {
406 return s.mapTo(v, false)
407}
408
409// StrictMapTo maps section to given struct in strict mode,
410// which returns all possible error including value parsing error.
411func (s *Section) StrictMapTo(v interface{}) error {
412 return s.mapTo(v, true)
413}
414
415// MapTo maps file to given struct.
416func (f *File) MapTo(v interface{}) error {
417 return f.Section("").MapTo(v)
418}
419
420// StrictMapTo maps file to given struct in strict mode,
421// which returns all possible error including value parsing error.
422func (f *File) StrictMapTo(v interface{}) error {
423 return f.Section("").StrictMapTo(v)
424}
425
426// MapToWithMapper maps data sources to given struct with name mapper.
427func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
428 cfg, err := Load(source, others...)
429 if err != nil {
430 return err
431 }
432 cfg.NameMapper = mapper
433 return cfg.MapTo(v)
434}
435
436// StrictMapToWithMapper maps data sources to given struct with name mapper in strict mode,
437// which returns all possible error including value parsing error.
438func StrictMapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
439 cfg, err := Load(source, others...)
440 if err != nil {
441 return err
442 }
443 cfg.NameMapper = mapper
444 return cfg.StrictMapTo(v)
445}
446
447// MapTo maps data sources to given struct.
448func MapTo(v, source interface{}, others ...interface{}) error {
449 return MapToWithMapper(v, nil, source, others...)
450}
451
452// StrictMapTo maps data sources to given struct in strict mode,
453// which returns all possible error including value parsing error.
454func StrictMapTo(v, source interface{}, others ...interface{}) error {
455 return StrictMapToWithMapper(v, nil, source, others...)
456}
457
458// reflectSliceWithProperType does the opposite thing as setSliceWithProperType.
459func reflectSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow bool) error {
460 slice := field.Slice(0, field.Len())
461 if field.Len() == 0 {
462 return nil
463 }
464 sliceOf := field.Type().Elem().Kind()
465
466 if allowShadow {
467 var keyWithShadows *Key
468 for i := 0; i < field.Len(); i++ {
469 var val string
470 switch sliceOf {
471 case reflect.String:
472 val = slice.Index(i).String()
473 case reflect.Int, reflect.Int64:
474 val = fmt.Sprint(slice.Index(i).Int())
475 case reflect.Uint, reflect.Uint64:
476 val = fmt.Sprint(slice.Index(i).Uint())
477 case reflect.Float64:
478 val = fmt.Sprint(slice.Index(i).Float())
479 case reflect.Bool:
480 val = fmt.Sprint(slice.Index(i).Bool())
481 case reflectTime:
482 val = slice.Index(i).Interface().(time.Time).Format(time.RFC3339)
483 default:
484 return fmt.Errorf("unsupported type '[]%s'", sliceOf)
485 }
486
487 if i == 0 {
488 keyWithShadows = newKey(key.s, key.name, val)
489 } else {
490 _ = keyWithShadows.AddShadow(val)
491 }
492 }
493 *key = *keyWithShadows
494 return nil
495 }
496
497 var buf bytes.Buffer
498 for i := 0; i < field.Len(); i++ {
499 switch sliceOf {
500 case reflect.String:
501 buf.WriteString(slice.Index(i).String())
502 case reflect.Int, reflect.Int64:
503 buf.WriteString(fmt.Sprint(slice.Index(i).Int()))
504 case reflect.Uint, reflect.Uint64:
505 buf.WriteString(fmt.Sprint(slice.Index(i).Uint()))
506 case reflect.Float64:
507 buf.WriteString(fmt.Sprint(slice.Index(i).Float()))
508 case reflect.Bool:
509 buf.WriteString(fmt.Sprint(slice.Index(i).Bool()))
510 case reflectTime:
511 buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339))
512 default:
513 return fmt.Errorf("unsupported type '[]%s'", sliceOf)
514 }
515 buf.WriteString(delim)
516 }
517 key.SetValue(buf.String()[:buf.Len()-len(delim)])
518 return nil
519}
520
521// reflectWithProperType does the opposite thing as setWithProperType.
522func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow bool) error {
523 switch t.Kind() {
524 case reflect.String:
525 key.SetValue(field.String())
526 case reflect.Bool:
527 key.SetValue(fmt.Sprint(field.Bool()))
528 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
529 key.SetValue(fmt.Sprint(field.Int()))
530 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
531 key.SetValue(fmt.Sprint(field.Uint()))
532 case reflect.Float32, reflect.Float64:
533 key.SetValue(fmt.Sprint(field.Float()))
534 case reflectTime:
535 key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339)))
536 case reflect.Slice:
537 return reflectSliceWithProperType(key, field, delim, allowShadow)
538 case reflect.Ptr:
539 if !field.IsNil() {
540 return reflectWithProperType(t.Elem(), key, field.Elem(), delim, allowShadow)
541 }
542 default:
543 return fmt.Errorf("unsupported type %q", t)
544 }
545 return nil
546}
547
548// CR: copied from encoding/json/encode.go with modifications of time.Time support.
549// TODO: add more test coverage.
550func isEmptyValue(v reflect.Value) bool {
551 switch v.Kind() {
552 case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
553 return v.Len() == 0
554 case reflect.Bool:
555 return !v.Bool()
556 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
557 return v.Int() == 0
558 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
559 return v.Uint() == 0
560 case reflect.Float32, reflect.Float64:
561 return v.Float() == 0
562 case reflect.Interface, reflect.Ptr:
563 return v.IsNil()
564 case reflectTime:
565 t, ok := v.Interface().(time.Time)
566 return ok && t.IsZero()
567 }
568 return false
569}
570
571// StructReflector is the interface implemented by struct types that can extract themselves into INI objects.
572type StructReflector interface {
573 ReflectINIStruct(*File) error
574}
575
576func (s *Section) reflectFrom(val reflect.Value) error {
577 if val.Kind() == reflect.Ptr {
578 val = val.Elem()
579 }
580 typ := val.Type()
581
582 for i := 0; i < typ.NumField(); i++ {
583 if !val.Field(i).CanInterface() {
584 continue
585 }
586
587 field := val.Field(i)
588 tpField := typ.Field(i)
589
590 tag := tpField.Tag.Get("ini")
591 if tag == "-" {
592 continue
593 }
594
595 rawName, omitEmpty, allowShadow, allowNonUnique, extends := parseTagOptions(tag)
596 if omitEmpty && isEmptyValue(field) {
597 continue
598 }
599
600 if r, ok := field.Interface().(StructReflector); ok {
601 return r.ReflectINIStruct(s.f)
602 }
603
604 fieldName := s.parseFieldName(tpField.Name, rawName)
605 if len(fieldName) == 0 || !field.CanSet() {
606 continue
607 }
608
609 if extends && tpField.Anonymous && (tpField.Type.Kind() == reflect.Ptr || tpField.Type.Kind() == reflect.Struct) {
610 if err := s.reflectFrom(field); err != nil {
611 return fmt.Errorf("reflect from field %q: %v", fieldName, err)
612 }
613 continue
614 }
615
616 if (tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct) ||
617 (tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") {
618 // Note: The only error here is section doesn't exist.
619 sec, err := s.f.GetSection(fieldName)
620 if err != nil {
621 // Note: fieldName can never be empty here, ignore error.
622 sec, _ = s.f.NewSection(fieldName)
623 }
624
625 // Add comment from comment tag
626 if len(sec.Comment) == 0 {
627 sec.Comment = tpField.Tag.Get("comment")
628 }
629
630 if err = sec.reflectFrom(field); err != nil {
631 return fmt.Errorf("reflect from field %q: %v", fieldName, err)
632 }
633 continue
634 }
635
636 if allowNonUnique && tpField.Type.Kind() == reflect.Slice {
637 slice := field.Slice(0, field.Len())
638 if field.Len() == 0 {
639 return nil
640 }
641 sliceOf := field.Type().Elem().Kind()
642
643 for i := 0; i < field.Len(); i++ {
644 if sliceOf != reflect.Struct && sliceOf != reflect.Ptr {
645 return fmt.Errorf("field %q is not a slice of pointer or struct", fieldName)
646 }
647
648 sec, err := s.f.NewSection(fieldName)
649 if err != nil {
650 return err
651 }
652
653 // Add comment from comment tag
654 if len(sec.Comment) == 0 {
655 sec.Comment = tpField.Tag.Get("comment")
656 }
657
658 if err := sec.reflectFrom(slice.Index(i)); err != nil {
659 return fmt.Errorf("reflect from field %q: %v", fieldName, err)
660 }
661 }
662 continue
663 }
664
665 // Note: Same reason as section.
666 key, err := s.GetKey(fieldName)
667 if err != nil {
668 key, _ = s.NewKey(fieldName, "")
669 }
670
671 // Add comment from comment tag
672 if len(key.Comment) == 0 {
673 key.Comment = tpField.Tag.Get("comment")
674 }
675
676 delim := parseDelim(tpField.Tag.Get("delim"))
677 if err = reflectWithProperType(tpField.Type, key, field, delim, allowShadow); err != nil {
678 return fmt.Errorf("reflect field %q: %v", fieldName, err)
679 }
680
681 }
682 return nil
683}
684
685// ReflectFrom reflects section from given struct. It overwrites existing ones.
686func (s *Section) ReflectFrom(v interface{}) error {
687 typ := reflect.TypeOf(v)
688 val := reflect.ValueOf(v)
689
690 if s.name != DefaultSection && s.f.options.AllowNonUniqueSections &&
691 (typ.Kind() == reflect.Slice || typ.Kind() == reflect.Ptr) {
692 // Clear sections to make sure none exists before adding the new ones
693 s.f.DeleteSection(s.name)
694
695 if typ.Kind() == reflect.Ptr {
696 sec, err := s.f.NewSection(s.name)
697 if err != nil {
698 return err
699 }
700 return sec.reflectFrom(val.Elem())
701 }
702
703 slice := val.Slice(0, val.Len())
704 sliceOf := val.Type().Elem().Kind()
705 if sliceOf != reflect.Ptr {
706 return fmt.Errorf("not a slice of pointers")
707 }
708
709 for i := 0; i < slice.Len(); i++ {
710 sec, err := s.f.NewSection(s.name)
711 if err != nil {
712 return err
713 }
714
715 err = sec.reflectFrom(slice.Index(i))
716 if err != nil {
717 return fmt.Errorf("reflect from %dth field: %v", i, err)
718 }
719 }
720
721 return nil
722 }
723
724 if typ.Kind() == reflect.Ptr {
725 val = val.Elem()
726 } else {
727 return errors.New("not a pointer to a struct")
728 }
729
730 return s.reflectFrom(val)
731}
732
733// ReflectFrom reflects file from given struct.
734func (f *File) ReflectFrom(v interface{}) error {
735 return f.Section("").ReflectFrom(v)
736}
737
738// ReflectFromWithMapper reflects data sources from given struct with name mapper.
739func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error {
740 cfg.NameMapper = mapper
741 return cfg.ReflectFrom(v)
742}
743
744// ReflectFrom reflects data sources from given struct.
745func ReflectFrom(cfg *File, v interface{}) error {
746 return ReflectFromWithMapper(cfg, v, nil)
747}