1 // Copyright 2014 Unknwon
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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
27 // NameMapper represents a ini tag name mapper.
28 type NameMapper func(string) string
30 // Built-in name getters.
32 // AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE.
33 AllCapsUnderscore 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 {
38 newstr = append(newstr, '_')
41 newstr = append(newstr, unicode.ToUpper(chr))
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 {
51 newstr = append(newstr, '_')
55 newstr = append(newstr, chr)
61 func (s *Section) parseFieldName(raw, actual string) string {
65 if s.f.NameMapper != nil {
66 return s.f.NameMapper(raw)
71 func parseDelim(actual string) string {
78 var reflectTime = reflect.TypeOf(time.Now()).Kind()
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 {
84 strs = key.StringsWithShadows(delim)
86 strs = key.Strings(delim)
97 sliceOf := field.Type().Elem().Kind()
102 vals, err = key.parseInts(strs, true, false)
104 vals, err = key.parseInt64s(strs, true, false)
106 vals, err = key.parseUints(strs, true, false)
108 vals, err = key.parseUint64s(strs, true, false)
109 case reflect.Float64:
110 vals, err = key.parseFloat64s(strs, true, false)
112 vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false)
114 return fmt.Errorf("unsupported type '[]%s'", sliceOf)
116 if err != nil && isStrict {
120 slice := reflect.MakeSlice(field.Type(), numVals, numVals)
121 for i := 0; i < numVals; i++ {
124 slice.Index(i).Set(reflect.ValueOf(vals.([]string)[i]))
126 slice.Index(i).Set(reflect.ValueOf(vals.([]int)[i]))
128 slice.Index(i).Set(reflect.ValueOf(vals.([]int64)[i]))
130 slice.Index(i).Set(reflect.ValueOf(vals.([]uint)[i]))
132 slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i]))
133 case reflect.Float64:
134 slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i]))
136 slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i]))
143 func wrapStrictError(err error, isStrict bool) error {
150 // setWithProperType sets proper value to field based on its type,
151 // but it does not return error for failing parsing,
152 // because we want to use default value that is already assigned to struct.
153 func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error {
156 if len(key.String()) == 0 {
159 field.SetString(key.String())
161 boolVal, err := key.Bool()
163 return wrapStrictError(err, isStrict)
165 field.SetBool(boolVal)
166 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
167 durationVal, err := key.Duration()
169 if err == nil && int64(durationVal) > 0 {
170 field.Set(reflect.ValueOf(durationVal))
174 intVal, err := key.Int64()
176 return wrapStrictError(err, isStrict)
179 // byte is an alias for uint8, so supporting uint8 breaks support for byte
180 case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
181 durationVal, err := key.Duration()
183 if err == nil && uint64(durationVal) > 0 {
184 field.Set(reflect.ValueOf(durationVal))
188 uintVal, err := key.Uint64()
190 return wrapStrictError(err, isStrict)
192 field.SetUint(uintVal)
194 case reflect.Float32, reflect.Float64:
195 floatVal, err := key.Float64()
197 return wrapStrictError(err, isStrict)
199 field.SetFloat(floatVal)
201 timeVal, err := key.Time()
203 return wrapStrictError(err, isStrict)
205 field.Set(reflect.ValueOf(timeVal))
207 return setSliceWithProperType(key, field, delim, allowShadow, isStrict)
209 switch t.Elem().Kind() {
211 boolVal, err := key.Bool()
213 return wrapStrictError(err, isStrict)
215 field.Set(reflect.ValueOf(&boolVal))
217 return fmt.Errorf("unsupported type '%s'", t)
220 return fmt.Errorf("unsupported type '%s'", t)
225 func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool) {
226 opts := strings.SplitN(tag, ",", 3)
229 omitEmpty = opts[1] == "omitempty"
232 allowShadow = opts[2] == "allowshadow"
234 return rawName, omitEmpty, allowShadow
237 func (s *Section) mapTo(val reflect.Value, isStrict bool) error {
238 if val.Kind() == reflect.Ptr {
243 for i := 0; i < typ.NumField(); i++ {
244 field := val.Field(i)
245 tpField := typ.Field(i)
247 tag := tpField.Tag.Get("ini")
252 rawName, _, allowShadow := parseTagOptions(tag)
253 fieldName := s.parseFieldName(tpField.Name, rawName)
254 if len(fieldName) == 0 || !field.CanSet() {
258 isStruct := tpField.Type.Kind() == reflect.Struct
259 isStructPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct
260 isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous
262 field.Set(reflect.New(tpField.Type.Elem()))
265 if isAnonymous || isStruct || isStructPtr {
266 if sec, err := s.f.GetSection(fieldName); err == nil {
267 // Only set the field to non-nil struct value if we have
268 // a section for it. Otherwise, we end up with a non-nil
269 // struct ptr even though there is no data.
270 if isStructPtr && field.IsNil() {
271 field.Set(reflect.New(tpField.Type.Elem()))
273 if err = sec.mapTo(field, isStrict); err != nil {
274 return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
280 if key, err := s.GetKey(fieldName); err == nil {
281 delim := parseDelim(tpField.Tag.Get("delim"))
282 if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil {
283 return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
290 // MapTo maps section to given struct.
291 func (s *Section) MapTo(v interface{}) error {
292 typ := reflect.TypeOf(v)
293 val := reflect.ValueOf(v)
294 if typ.Kind() == reflect.Ptr {
298 return errors.New("cannot map to non-pointer struct")
301 return s.mapTo(val, false)
304 // StrictMapTo maps section to given struct in strict mode,
305 // which returns all possible error including value parsing error.
306 func (s *Section) StrictMapTo(v interface{}) error {
307 typ := reflect.TypeOf(v)
308 val := reflect.ValueOf(v)
309 if typ.Kind() == reflect.Ptr {
313 return errors.New("cannot map to non-pointer struct")
316 return s.mapTo(val, true)
319 // MapTo maps file to given struct.
320 func (f *File) MapTo(v interface{}) error {
321 return f.Section("").MapTo(v)
324 // StrictMapTo maps file to given struct in strict mode,
325 // which returns all possible error including value parsing error.
326 func (f *File) StrictMapTo(v interface{}) error {
327 return f.Section("").StrictMapTo(v)
330 // MapToWithMapper maps data sources to given struct with name mapper.
331 func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
332 cfg, err := Load(source, others...)
336 cfg.NameMapper = mapper
340 // StrictMapToWithMapper maps data sources to given struct with name mapper in strict mode,
341 // which returns all possible error including value parsing error.
342 func StrictMapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
343 cfg, err := Load(source, others...)
347 cfg.NameMapper = mapper
348 return cfg.StrictMapTo(v)
351 // MapTo maps data sources to given struct.
352 func MapTo(v, source interface{}, others ...interface{}) error {
353 return MapToWithMapper(v, nil, source, others...)
356 // StrictMapTo maps data sources to given struct in strict mode,
357 // which returns all possible error including value parsing error.
358 func StrictMapTo(v, source interface{}, others ...interface{}) error {
359 return StrictMapToWithMapper(v, nil, source, others...)
362 // reflectSliceWithProperType does the opposite thing as setSliceWithProperType.
363 func reflectSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow bool) error {
364 slice := field.Slice(0, field.Len())
365 if field.Len() == 0 {
368 sliceOf := field.Type().Elem().Kind()
371 var keyWithShadows *Key
372 for i := 0; i < field.Len(); i++ {
376 val = slice.Index(i).String()
377 case reflect.Int, reflect.Int64:
378 val = fmt.Sprint(slice.Index(i).Int())
379 case reflect.Uint, reflect.Uint64:
380 val = fmt.Sprint(slice.Index(i).Uint())
381 case reflect.Float64:
382 val = fmt.Sprint(slice.Index(i).Float())
384 val = slice.Index(i).Interface().(time.Time).Format(time.RFC3339)
386 return fmt.Errorf("unsupported type '[]%s'", sliceOf)
390 keyWithShadows = newKey(key.s, key.name, val)
392 keyWithShadows.AddShadow(val)
400 for i := 0; i < field.Len(); i++ {
403 buf.WriteString(slice.Index(i).String())
404 case reflect.Int, reflect.Int64:
405 buf.WriteString(fmt.Sprint(slice.Index(i).Int()))
406 case reflect.Uint, reflect.Uint64:
407 buf.WriteString(fmt.Sprint(slice.Index(i).Uint()))
408 case reflect.Float64:
409 buf.WriteString(fmt.Sprint(slice.Index(i).Float()))
411 buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339))
413 return fmt.Errorf("unsupported type '[]%s'", sliceOf)
415 buf.WriteString(delim)
417 key.SetValue(buf.String()[:buf.Len()-len(delim)])
421 // reflectWithProperType does the opposite thing as setWithProperType.
422 func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow bool) error {
425 key.SetValue(field.String())
427 key.SetValue(fmt.Sprint(field.Bool()))
428 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
429 key.SetValue(fmt.Sprint(field.Int()))
430 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
431 key.SetValue(fmt.Sprint(field.Uint()))
432 case reflect.Float32, reflect.Float64:
433 key.SetValue(fmt.Sprint(field.Float()))
435 key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339)))
437 return reflectSliceWithProperType(key, field, delim, allowShadow)
440 return reflectWithProperType(t.Elem(), key, field.Elem(), delim, allowShadow)
443 return fmt.Errorf("unsupported type '%s'", t)
448 // CR: copied from encoding/json/encode.go with modifications of time.Time support.
449 // TODO: add more test coverage.
450 func isEmptyValue(v reflect.Value) bool {
452 case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
456 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
458 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
460 case reflect.Float32, reflect.Float64:
461 return v.Float() == 0
462 case reflect.Interface, reflect.Ptr:
465 t, ok := v.Interface().(time.Time)
466 return ok && t.IsZero()
471 func (s *Section) reflectFrom(val reflect.Value) error {
472 if val.Kind() == reflect.Ptr {
477 for i := 0; i < typ.NumField(); i++ {
478 field := val.Field(i)
479 tpField := typ.Field(i)
481 tag := tpField.Tag.Get("ini")
486 rawName, omitEmpty, allowShadow := parseTagOptions(tag)
487 if omitEmpty && isEmptyValue(field) {
491 fieldName := s.parseFieldName(tpField.Name, rawName)
492 if len(fieldName) == 0 || !field.CanSet() {
496 if (tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous) ||
497 (tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") {
498 // Note: The only error here is section doesn't exist.
499 sec, err := s.f.GetSection(fieldName)
501 // Note: fieldName can never be empty here, ignore error.
502 sec, _ = s.f.NewSection(fieldName)
505 // Add comment from comment tag
506 if len(sec.Comment) == 0 {
507 sec.Comment = tpField.Tag.Get("comment")
510 if err = sec.reflectFrom(field); err != nil {
511 return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
516 // Note: Same reason as secion.
517 key, err := s.GetKey(fieldName)
519 key, _ = s.NewKey(fieldName, "")
522 // Add comment from comment tag
523 if len(key.Comment) == 0 {
524 key.Comment = tpField.Tag.Get("comment")
527 if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim")), allowShadow); err != nil {
528 return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
535 // ReflectFrom reflects secion from given struct.
536 func (s *Section) ReflectFrom(v interface{}) error {
537 typ := reflect.TypeOf(v)
538 val := reflect.ValueOf(v)
539 if typ.Kind() == reflect.Ptr {
543 return errors.New("cannot reflect from non-pointer struct")
546 return s.reflectFrom(val)
549 // ReflectFrom reflects file from given struct.
550 func (f *File) ReflectFrom(v interface{}) error {
551 return f.Section("").ReflectFrom(v)
554 // ReflectFromWithMapper reflects data sources from given struct with name mapper.
555 func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error {
556 cfg.NameMapper = mapper
557 return cfg.ReflectFrom(v)
560 // ReflectFrom reflects data sources from given struct.
561 func ReflectFrom(cfg *File, v interface{}) error {
562 return ReflectFromWithMapper(cfg, v, nil)