vendor/gopkg.in/ini.v1/struct.go
changeset 251 1c52a0eeb952
child 256 6d9efbef00a9
equal deleted inserted replaced
250:c040f992052f 251:1c52a0eeb952
       
     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 '%s'", t)
       
   262 	}
       
   263 	return nil
       
   264 }
       
   265 
       
   266 func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool) {
       
   267 	opts := strings.SplitN(tag, ",", 3)
       
   268 	rawName = opts[0]
       
   269 	if len(opts) > 1 {
       
   270 		omitEmpty = opts[1] == "omitempty"
       
   271 	}
       
   272 	if len(opts) > 2 {
       
   273 		allowShadow = opts[2] == "allowshadow"
       
   274 	}
       
   275 	return rawName, omitEmpty, allowShadow
       
   276 }
       
   277 
       
   278 func (s *Section) mapTo(val reflect.Value, isStrict bool) error {
       
   279 	if val.Kind() == reflect.Ptr {
       
   280 		val = val.Elem()
       
   281 	}
       
   282 	typ := val.Type()
       
   283 
       
   284 	for i := 0; i < typ.NumField(); i++ {
       
   285 		field := val.Field(i)
       
   286 		tpField := typ.Field(i)
       
   287 
       
   288 		tag := tpField.Tag.Get("ini")
       
   289 		if tag == "-" {
       
   290 			continue
       
   291 		}
       
   292 
       
   293 		rawName, _, allowShadow := parseTagOptions(tag)
       
   294 		fieldName := s.parseFieldName(tpField.Name, rawName)
       
   295 		if len(fieldName) == 0 || !field.CanSet() {
       
   296 			continue
       
   297 		}
       
   298 
       
   299 		isStruct := tpField.Type.Kind() == reflect.Struct
       
   300 		isStructPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct
       
   301 		isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous
       
   302 		if isAnonymous {
       
   303 			field.Set(reflect.New(tpField.Type.Elem()))
       
   304 		}
       
   305 
       
   306 		if isAnonymous || isStruct || isStructPtr {
       
   307 			if sec, err := s.f.GetSection(fieldName); err == nil {
       
   308 				// 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.
       
   310 				if isStructPtr && field.IsNil() {
       
   311 					field.Set(reflect.New(tpField.Type.Elem()))
       
   312 				}
       
   313 				if err = sec.mapTo(field, isStrict); err != nil {
       
   314 					return fmt.Errorf("error mapping field %q: %v", fieldName, err)
       
   315 				}
       
   316 				continue
       
   317 			}
       
   318 		}
       
   319 		if key, err := s.GetKey(fieldName); err == nil {
       
   320 			delim := parseDelim(tpField.Tag.Get("delim"))
       
   321 			if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil {
       
   322 				return fmt.Errorf("error mapping field %q: %v", fieldName, err)
       
   323 			}
       
   324 		}
       
   325 	}
       
   326 	return nil
       
   327 }
       
   328 
       
   329 // MapTo maps section to given struct.
       
   330 func (s *Section) MapTo(v interface{}) error {
       
   331 	typ := reflect.TypeOf(v)
       
   332 	val := reflect.ValueOf(v)
       
   333 	if typ.Kind() == reflect.Ptr {
       
   334 		typ = typ.Elem()
       
   335 		val = val.Elem()
       
   336 	} else {
       
   337 		return errors.New("cannot map to non-pointer struct")
       
   338 	}
       
   339 
       
   340 	return s.mapTo(val, false)
       
   341 }
       
   342 
       
   343 // StrictMapTo maps section to given struct in strict mode,
       
   344 // which returns all possible error including value parsing error.
       
   345 func (s *Section) StrictMapTo(v interface{}) error {
       
   346 	typ := reflect.TypeOf(v)
       
   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 }
       
   357 
       
   358 // MapTo maps file to given struct.
       
   359 func (f *File) MapTo(v interface{}) error {
       
   360 	return f.Section("").MapTo(v)
       
   361 }
       
   362 
       
   363 // StrictMapTo maps file to given struct in strict mode,
       
   364 // which returns all possible error including value parsing error.
       
   365 func (f *File) StrictMapTo(v interface{}) error {
       
   366 	return f.Section("").StrictMapTo(v)
       
   367 }
       
   368 
       
   369 // MapToWithMapper maps data sources to given struct with name mapper.
       
   370 func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
       
   371 	cfg, err := Load(source, others...)
       
   372 	if err != nil {
       
   373 		return err
       
   374 	}
       
   375 	cfg.NameMapper = mapper
       
   376 	return cfg.MapTo(v)
       
   377 }
       
   378 
       
   379 // StrictMapToWithMapper maps data sources to given struct with name mapper in strict mode,
       
   380 // which returns all possible error including value parsing error.
       
   381 func StrictMapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
       
   382 	cfg, err := Load(source, others...)
       
   383 	if err != nil {
       
   384 		return err
       
   385 	}
       
   386 	cfg.NameMapper = mapper
       
   387 	return cfg.StrictMapTo(v)
       
   388 }
       
   389 
       
   390 // MapTo maps data sources to given struct.
       
   391 func MapTo(v, source interface{}, others ...interface{}) error {
       
   392 	return MapToWithMapper(v, nil, source, others...)
       
   393 }
       
   394 
       
   395 // StrictMapTo maps data sources to given struct in strict mode,
       
   396 // which returns all possible error including value parsing error.
       
   397 func StrictMapTo(v, source interface{}, others ...interface{}) error {
       
   398 	return StrictMapToWithMapper(v, nil, source, others...)
       
   399 }
       
   400 
       
   401 // reflectSliceWithProperType does the opposite thing as setSliceWithProperType.
       
   402 func reflectSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow bool) error {
       
   403 	slice := field.Slice(0, field.Len())
       
   404 	if field.Len() == 0 {
       
   405 		return nil
       
   406 	}
       
   407 	sliceOf := field.Type().Elem().Kind()
       
   408 
       
   409 	if allowShadow {
       
   410 		var keyWithShadows *Key
       
   411 		for i := 0; i < field.Len(); i++ {
       
   412 			var val string
       
   413 			switch sliceOf {
       
   414 			case reflect.String:
       
   415 				val = slice.Index(i).String()
       
   416 			case reflect.Int, reflect.Int64:
       
   417 				val = fmt.Sprint(slice.Index(i).Int())
       
   418 			case reflect.Uint, reflect.Uint64:
       
   419 				val = fmt.Sprint(slice.Index(i).Uint())
       
   420 			case reflect.Float64:
       
   421 				val = fmt.Sprint(slice.Index(i).Float())
       
   422 			case reflect.Bool:
       
   423 				val = fmt.Sprint(slice.Index(i).Bool())
       
   424 			case reflectTime:
       
   425 				val = slice.Index(i).Interface().(time.Time).Format(time.RFC3339)
       
   426 			default:
       
   427 				return fmt.Errorf("unsupported type '[]%s'", sliceOf)
       
   428 			}
       
   429 
       
   430 			if i == 0 {
       
   431 				keyWithShadows = newKey(key.s, key.name, val)
       
   432 			} else {
       
   433 				keyWithShadows.AddShadow(val)
       
   434 			}
       
   435 		}
       
   436 		key = keyWithShadows
       
   437 		return nil
       
   438 	}
       
   439 
       
   440 	var buf bytes.Buffer
       
   441 	for i := 0; i < field.Len(); i++ {
       
   442 		switch sliceOf {
       
   443 		case reflect.String:
       
   444 			buf.WriteString(slice.Index(i).String())
       
   445 		case reflect.Int, reflect.Int64:
       
   446 			buf.WriteString(fmt.Sprint(slice.Index(i).Int()))
       
   447 		case reflect.Uint, reflect.Uint64:
       
   448 			buf.WriteString(fmt.Sprint(slice.Index(i).Uint()))
       
   449 		case reflect.Float64:
       
   450 			buf.WriteString(fmt.Sprint(slice.Index(i).Float()))
       
   451 		case reflect.Bool:
       
   452 			buf.WriteString(fmt.Sprint(slice.Index(i).Bool()))
       
   453 		case reflectTime:
       
   454 			buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339))
       
   455 		default:
       
   456 			return fmt.Errorf("unsupported type '[]%s'", sliceOf)
       
   457 		}
       
   458 		buf.WriteString(delim)
       
   459 	}
       
   460 	key.SetValue(buf.String()[:buf.Len()-len(delim)])
       
   461 	return nil
       
   462 }
       
   463 
       
   464 // reflectWithProperType does the opposite thing as setWithProperType.
       
   465 func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow bool) error {
       
   466 	switch t.Kind() {
       
   467 	case reflect.String:
       
   468 		key.SetValue(field.String())
       
   469 	case reflect.Bool:
       
   470 		key.SetValue(fmt.Sprint(field.Bool()))
       
   471 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
       
   472 		key.SetValue(fmt.Sprint(field.Int()))
       
   473 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
       
   474 		key.SetValue(fmt.Sprint(field.Uint()))
       
   475 	case reflect.Float32, reflect.Float64:
       
   476 		key.SetValue(fmt.Sprint(field.Float()))
       
   477 	case reflectTime:
       
   478 		key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339)))
       
   479 	case reflect.Slice:
       
   480 		return reflectSliceWithProperType(key, field, delim, allowShadow)
       
   481 	case reflect.Ptr:
       
   482 		if !field.IsNil() {
       
   483 			return reflectWithProperType(t.Elem(), key, field.Elem(), delim, allowShadow)
       
   484 		}
       
   485 	default:
       
   486 		return fmt.Errorf("unsupported type '%s'", t)
       
   487 	}
       
   488 	return nil
       
   489 }
       
   490 
       
   491 // CR: copied from encoding/json/encode.go with modifications of time.Time support.
       
   492 // TODO: add more test coverage.
       
   493 func isEmptyValue(v reflect.Value) bool {
       
   494 	switch v.Kind() {
       
   495 	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
       
   496 		return v.Len() == 0
       
   497 	case reflect.Bool:
       
   498 		return !v.Bool()
       
   499 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
       
   500 		return v.Int() == 0
       
   501 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
       
   502 		return v.Uint() == 0
       
   503 	case reflect.Float32, reflect.Float64:
       
   504 		return v.Float() == 0
       
   505 	case reflect.Interface, reflect.Ptr:
       
   506 		return v.IsNil()
       
   507 	case reflectTime:
       
   508 		t, ok := v.Interface().(time.Time)
       
   509 		return ok && t.IsZero()
       
   510 	}
       
   511 	return false
       
   512 }
       
   513 
       
   514 // StructReflector is the interface implemented by struct types that can extract themselves into INI objects.
       
   515 type StructReflector interface {
       
   516 	ReflectINIStruct(*File) error
       
   517 }
       
   518 
       
   519 func (s *Section) reflectFrom(val reflect.Value) error {
       
   520 	if val.Kind() == reflect.Ptr {
       
   521 		val = val.Elem()
       
   522 	}
       
   523 	typ := val.Type()
       
   524 
       
   525 	for i := 0; i < typ.NumField(); i++ {
       
   526 		field := val.Field(i)
       
   527 		tpField := typ.Field(i)
       
   528 
       
   529 		tag := tpField.Tag.Get("ini")
       
   530 		if tag == "-" {
       
   531 			continue
       
   532 		}
       
   533 
       
   534 		rawName, omitEmpty, allowShadow := parseTagOptions(tag)
       
   535 		if omitEmpty && isEmptyValue(field) {
       
   536 			continue
       
   537 		}
       
   538 
       
   539 		if r, ok := field.Interface().(StructReflector); ok {
       
   540 			return r.ReflectINIStruct(s.f)
       
   541 		}
       
   542 
       
   543 		fieldName := s.parseFieldName(tpField.Name, rawName)
       
   544 		if len(fieldName) == 0 || !field.CanSet() {
       
   545 			continue
       
   546 		}
       
   547 
       
   548 		if (tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous) ||
       
   549 			(tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") {
       
   550 			// Note: The only error here is section doesn't exist.
       
   551 			sec, err := s.f.GetSection(fieldName)
       
   552 			if err != nil {
       
   553 				// Note: fieldName can never be empty here, ignore error.
       
   554 				sec, _ = s.f.NewSection(fieldName)
       
   555 			}
       
   556 
       
   557 			// Add comment from comment tag
       
   558 			if len(sec.Comment) == 0 {
       
   559 				sec.Comment = tpField.Tag.Get("comment")
       
   560 			}
       
   561 
       
   562 			if err = sec.reflectFrom(field); err != nil {
       
   563 				return fmt.Errorf("error reflecting field %q: %v", fieldName, err)
       
   564 			}
       
   565 			continue
       
   566 		}
       
   567 
       
   568 		key, err := s.GetKey(fieldName)
       
   569 		if err != nil {
       
   570 			key, _ = s.NewKey(fieldName, "")
       
   571 		}
       
   572 
       
   573 		// Add comment from comment tag
       
   574 		if len(key.Comment) == 0 {
       
   575 			key.Comment = tpField.Tag.Get("comment")
       
   576 		}
       
   577 
       
   578 		delim := parseDelim(tpField.Tag.Get("delim"))
       
   579 		if err = reflectWithProperType(tpField.Type, key, field, delim, allowShadow); err != nil {
       
   580 			return fmt.Errorf("error reflecting field %q: %v", fieldName, err)
       
   581 		}
       
   582 
       
   583 	}
       
   584 	return nil
       
   585 }
       
   586 
       
   587 // ReflectFrom reflects secion from given struct.
       
   588 func (s *Section) ReflectFrom(v interface{}) error {
       
   589 	typ := reflect.TypeOf(v)
       
   590 	val := reflect.ValueOf(v)
       
   591 	if typ.Kind() == reflect.Ptr {
       
   592 		typ = typ.Elem()
       
   593 		val = val.Elem()
       
   594 	} else {
       
   595 		return errors.New("cannot reflect from non-pointer struct")
       
   596 	}
       
   597 
       
   598 	return s.reflectFrom(val)
       
   599 }
       
   600 
       
   601 // ReflectFrom reflects file from given struct.
       
   602 func (f *File) ReflectFrom(v interface{}) error {
       
   603 	return f.Section("").ReflectFrom(v)
       
   604 }
       
   605 
       
   606 // ReflectFromWithMapper reflects data sources from given struct with name mapper.
       
   607 func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error {
       
   608 	cfg.NameMapper = mapper
       
   609 	return cfg.ReflectFrom(v)
       
   610 }
       
   611 
       
   612 // ReflectFrom reflects data sources from given struct.
       
   613 func ReflectFrom(cfg *File, v interface{}) error {
       
   614 	return ReflectFromWithMapper(cfg, v, nil)
       
   615 }