...

Source file src/gopkg.in/ini.v1/struct.go

Documentation: gopkg.in/ini.v1

     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  }
   748  

View as plain text