256 field.Set(reflect.ValueOf(timeVal)) |
256 field.Set(reflect.ValueOf(timeVal)) |
257 } |
257 } |
258 case reflect.Slice: |
258 case reflect.Slice: |
259 return setSliceWithProperType(key, field, delim, allowShadow, isStrict) |
259 return setSliceWithProperType(key, field, delim, allowShadow, isStrict) |
260 default: |
260 default: |
261 return fmt.Errorf("unsupported type '%s'", t) |
261 return fmt.Errorf("unsupported type %q", t) |
262 } |
262 } |
263 return nil |
263 return nil |
264 } |
264 } |
265 |
265 |
266 func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool) { |
266 func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool, allowNonUnique bool, extends bool) { |
267 opts := strings.SplitN(tag, ",", 3) |
267 opts := strings.SplitN(tag, ",", 5) |
268 rawName = opts[0] |
268 rawName = opts[0] |
269 if len(opts) > 1 { |
269 for _, opt := range opts[1:] { |
270 omitEmpty = opts[1] == "omitempty" |
270 omitEmpty = omitEmpty || (opt == "omitempty") |
271 } |
271 allowShadow = allowShadow || (opt == "allowshadow") |
272 if len(opts) > 2 { |
272 allowNonUnique = allowNonUnique || (opt == "nonunique") |
273 allowShadow = opts[2] == "allowshadow" |
273 extends = extends || (opt == "extends") |
274 } |
274 } |
275 return rawName, omitEmpty, allowShadow |
275 return rawName, omitEmpty, allowShadow, allowNonUnique, extends |
276 } |
276 } |
277 |
277 |
278 func (s *Section) mapTo(val reflect.Value, isStrict bool) error { |
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. |
|
280 func (s *Section) mapToField(val reflect.Value, isStrict bool, sectionIndex int, sectionName string) error { |
279 if val.Kind() == reflect.Ptr { |
281 if val.Kind() == reflect.Ptr { |
280 val = val.Elem() |
282 val = val.Elem() |
281 } |
283 } |
282 typ := val.Type() |
284 typ := val.Type() |
283 |
285 |
288 tag := tpField.Tag.Get("ini") |
290 tag := tpField.Tag.Get("ini") |
289 if tag == "-" { |
291 if tag == "-" { |
290 continue |
292 continue |
291 } |
293 } |
292 |
294 |
293 rawName, _, allowShadow := parseTagOptions(tag) |
295 rawName, _, allowShadow, allowNonUnique, extends := parseTagOptions(tag) |
294 fieldName := s.parseFieldName(tpField.Name, rawName) |
296 fieldName := s.parseFieldName(tpField.Name, rawName) |
295 if len(fieldName) == 0 || !field.CanSet() { |
297 if len(fieldName) == 0 || !field.CanSet() { |
296 continue |
298 continue |
297 } |
299 } |
298 |
300 |
299 isStruct := tpField.Type.Kind() == reflect.Struct |
301 isStruct := tpField.Type.Kind() == reflect.Struct |
300 isStructPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct |
302 isStructPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct |
301 isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous |
303 isAnonymousPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous |
302 if isAnonymous { |
304 if isAnonymousPtr { |
303 field.Set(reflect.New(tpField.Type.Elem())) |
305 field.Set(reflect.New(tpField.Type.Elem())) |
304 } |
306 } |
305 |
307 |
306 if isAnonymous || isStruct || isStructPtr { |
308 if extends && (isAnonymousPtr || (isStruct && tpField.Anonymous)) { |
307 if sec, err := s.f.GetSection(fieldName); err == nil { |
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 } |
308 // Only set the field to non-nil struct value if we have a section for it. |
327 // Only set the field to non-nil struct value if we have a section for it. |
309 // Otherwise, we end up with a non-nil struct ptr even though there is no data. |
328 // Otherwise, we end up with a non-nil struct ptr even though there is no data. |
310 if isStructPtr && field.IsNil() { |
329 if isStructPtr && field.IsNil() { |
311 field.Set(reflect.New(tpField.Type.Elem())) |
330 field.Set(reflect.New(tpField.Type.Elem())) |
312 } |
331 } |
313 if err = sec.mapTo(field, isStrict); err != nil { |
332 if err = secs[sectionIndex].mapToField(field, isStrict, sectionIndex, fieldName); err != nil { |
314 return fmt.Errorf("error mapping field %q: %v", fieldName, err) |
333 return fmt.Errorf("map to field %q: %v", fieldName, err) |
315 } |
334 } |
316 continue |
335 continue |
317 } |
336 } |
318 } |
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 |
319 if key, err := s.GetKey(fieldName); err == nil { |
350 if key, err := s.GetKey(fieldName); err == nil { |
320 delim := parseDelim(tpField.Tag.Get("delim")) |
351 delim := parseDelim(tpField.Tag.Get("delim")) |
321 if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil { |
352 if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil { |
322 return fmt.Errorf("error mapping field %q: %v", fieldName, err) |
353 return fmt.Errorf("set field %q: %v", fieldName, err) |
323 } |
354 } |
324 } |
355 } |
325 } |
356 } |
326 return nil |
357 return nil |
327 } |
358 } |
328 |
359 |
329 // MapTo maps section to given struct. |
360 // mapToSlice maps all sections with the same name and returns the new value. |
330 func (s *Section) MapTo(v interface{}) error { |
361 // The type of the Value must be a slice. |
|
362 func (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. |
|
381 func (s *Section) mapTo(v interface{}, isStrict bool) error { |
331 typ := reflect.TypeOf(v) |
382 typ := reflect.TypeOf(v) |
332 val := reflect.ValueOf(v) |
383 val := reflect.ValueOf(v) |
333 if typ.Kind() == reflect.Ptr { |
384 if typ.Kind() == reflect.Ptr { |
334 typ = typ.Elem() |
385 typ = typ.Elem() |
335 val = val.Elem() |
386 val = val.Elem() |
336 } else { |
387 } else { |
337 return errors.New("cannot map to non-pointer struct") |
388 return errors.New("not a pointer to a struct") |
338 } |
389 } |
339 |
390 |
340 return s.mapTo(val, false) |
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. |
|
405 func (s *Section) MapTo(v interface{}) error { |
|
406 return s.mapTo(v, false) |
341 } |
407 } |
342 |
408 |
343 // StrictMapTo maps section to given struct in strict mode, |
409 // StrictMapTo maps section to given struct in strict mode, |
344 // which returns all possible error including value parsing error. |
410 // which returns all possible error including value parsing error. |
345 func (s *Section) StrictMapTo(v interface{}) error { |
411 func (s *Section) StrictMapTo(v interface{}) error { |
346 typ := reflect.TypeOf(v) |
412 return s.mapTo(v, true) |
347 val := reflect.ValueOf(v) |
|
348 if typ.Kind() == reflect.Ptr { |
|
349 typ = typ.Elem() |
|
350 val = val.Elem() |
|
351 } else { |
|
352 return errors.New("cannot map to non-pointer struct") |
|
353 } |
|
354 |
|
355 return s.mapTo(val, true) |
|
356 } |
413 } |
357 |
414 |
358 // MapTo maps file to given struct. |
415 // MapTo maps file to given struct. |
359 func (f *File) MapTo(v interface{}) error { |
416 func (f *File) MapTo(v interface{}) error { |
360 return f.Section("").MapTo(v) |
417 return f.Section("").MapTo(v) |
558 if len(sec.Comment) == 0 { |
626 if len(sec.Comment) == 0 { |
559 sec.Comment = tpField.Tag.Get("comment") |
627 sec.Comment = tpField.Tag.Get("comment") |
560 } |
628 } |
561 |
629 |
562 if err = sec.reflectFrom(field); err != nil { |
630 if err = sec.reflectFrom(field); err != nil { |
563 return fmt.Errorf("error reflecting field %q: %v", fieldName, err) |
631 return fmt.Errorf("reflect from field %q: %v", fieldName, err) |
564 } |
632 } |
565 continue |
633 continue |
566 } |
634 } |
567 |
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. |
568 key, err := s.GetKey(fieldName) |
666 key, err := s.GetKey(fieldName) |
569 if err != nil { |
667 if err != nil { |
570 key, _ = s.NewKey(fieldName, "") |
668 key, _ = s.NewKey(fieldName, "") |
571 } |
669 } |
572 |
670 |
575 key.Comment = tpField.Tag.Get("comment") |
673 key.Comment = tpField.Tag.Get("comment") |
576 } |
674 } |
577 |
675 |
578 delim := parseDelim(tpField.Tag.Get("delim")) |
676 delim := parseDelim(tpField.Tag.Get("delim")) |
579 if err = reflectWithProperType(tpField.Type, key, field, delim, allowShadow); err != nil { |
677 if err = reflectWithProperType(tpField.Type, key, field, delim, allowShadow); err != nil { |
580 return fmt.Errorf("error reflecting field %q: %v", fieldName, err) |
678 return fmt.Errorf("reflect field %q: %v", fieldName, err) |
581 } |
679 } |
582 |
680 |
583 } |
681 } |
584 return nil |
682 return nil |
585 } |
683 } |
586 |
684 |
587 // ReflectFrom reflects secion from given struct. |
685 // ReflectFrom reflects section from given struct. It overwrites existing ones. |
588 func (s *Section) ReflectFrom(v interface{}) error { |
686 func (s *Section) ReflectFrom(v interface{}) error { |
589 typ := reflect.TypeOf(v) |
687 typ := reflect.TypeOf(v) |
590 val := reflect.ValueOf(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 |
591 if typ.Kind() == reflect.Ptr { |
724 if typ.Kind() == reflect.Ptr { |
592 typ = typ.Elem() |
|
593 val = val.Elem() |
725 val = val.Elem() |
594 } else { |
726 } else { |
595 return errors.New("cannot reflect from non-pointer struct") |
727 return errors.New("not a pointer to a struct") |
596 } |
728 } |
597 |
729 |
598 return s.reflectFrom(val) |
730 return s.reflectFrom(val) |
599 } |
731 } |
600 |
732 |