struct.go (21199B)
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 "strings" 23 "time" 24 "unicode" 25 ) 26 27 // NameMapper represents a ini tag name mapper. 28 type NameMapper func(string) string 29 30 // Built-in name getters. 31 var ( 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 61 func (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 71 func parseDelim(actual string) string { 72 if len(actual) > 0 { 73 return actual 74 } 75 return "," 76 } 77 78 var reflectTime = reflect.TypeOf(time.Now()).Kind() 79 80 // setSliceWithProperType sets proper values to slice based on its type. 81 func 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 147 func 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. 157 func 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 266 func 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. 280 func (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. 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 { 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. 405 func (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. 411 func (s *Section) StrictMapTo(v interface{}) error { 412 return s.mapTo(v, true) 413 } 414 415 // MapTo maps file to given struct. 416 func (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. 422 func (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. 427 func 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. 438 func 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. 448 func 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. 454 func StrictMapTo(v, source interface{}, others ...interface{}) error { 455 return StrictMapToWithMapper(v, nil, source, others...) 456 } 457 458 // reflectSliceWithProperType does the opposite thing as setSliceWithProperType. 459 func 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. 522 func 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. 550 func 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. 572 type StructReflector interface { 573 ReflectINIStruct(*File) error 574 } 575 576 func (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. 686 func (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. 734 func (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. 739 func 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. 745 func ReflectFrom(cfg *File, v interface{}) error { 746 return ReflectFromWithMapper(cfg, v, nil) 747 }