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) error {
82 strs := key.Strings(delim)
90 sliceOf := field.Type().Elem().Kind()
95 vals = key.Ints(delim)
97 vals = key.Int64s(delim)
99 vals = key.Uints(delim)
101 vals = key.Uint64s(delim)
102 case reflect.Float64:
103 vals = key.Float64s(delim)
105 vals = key.Times(delim)
107 return fmt.Errorf("unsupported type '[]%s'", sliceOf)
110 slice := reflect.MakeSlice(field.Type(), numVals, numVals)
111 for i := 0; i < numVals; i++ {
114 slice.Index(i).Set(reflect.ValueOf(vals.([]string)[i]))
116 slice.Index(i).Set(reflect.ValueOf(vals.([]int)[i]))
118 slice.Index(i).Set(reflect.ValueOf(vals.([]int64)[i]))
120 slice.Index(i).Set(reflect.ValueOf(vals.([]uint)[i]))
122 slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i]))
123 case reflect.Float64:
124 slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i]))
126 slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i]))
133 // setWithProperType sets proper value to field based on its type,
134 // but it does not return error for failing parsing,
135 // because we want to use default value that is already assigned to strcut.
136 func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error {
139 if len(key.String()) == 0 {
142 field.SetString(key.String())
144 boolVal, err := key.Bool()
148 field.SetBool(boolVal)
149 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
150 durationVal, err := key.Duration()
152 if err == nil && int(durationVal) > 0 {
153 field.Set(reflect.ValueOf(durationVal))
157 intVal, err := key.Int64()
158 if err != nil || intVal == 0 {
162 // byte is an alias for uint8, so supporting uint8 breaks support for byte
163 case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
164 durationVal, err := key.Duration()
166 if err == nil && int(durationVal) > 0 {
167 field.Set(reflect.ValueOf(durationVal))
171 uintVal, err := key.Uint64()
175 field.SetUint(uintVal)
177 case reflect.Float32, reflect.Float64:
178 floatVal, err := key.Float64()
182 field.SetFloat(floatVal)
184 timeVal, err := key.Time()
188 field.Set(reflect.ValueOf(timeVal))
190 return setSliceWithProperType(key, field, delim)
192 return fmt.Errorf("unsupported type '%s'", t)
197 func (s *Section) mapTo(val reflect.Value) error {
198 if val.Kind() == reflect.Ptr {
203 for i := 0; i < typ.NumField(); i++ {
204 field := val.Field(i)
205 tpField := typ.Field(i)
207 tag := tpField.Tag.Get("ini")
212 opts := strings.SplitN(tag, ",", 2) // strip off possible omitempty
213 fieldName := s.parseFieldName(tpField.Name, opts[0])
214 if len(fieldName) == 0 || !field.CanSet() {
218 isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous
219 isStruct := tpField.Type.Kind() == reflect.Struct
221 field.Set(reflect.New(tpField.Type.Elem()))
224 if isAnonymous || isStruct {
225 if sec, err := s.f.GetSection(fieldName); err == nil {
226 if err = sec.mapTo(field); err != nil {
227 return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
233 if key, err := s.GetKey(fieldName); err == nil {
234 if err = setWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil {
235 return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
242 // MapTo maps section to given struct.
243 func (s *Section) MapTo(v interface{}) error {
244 typ := reflect.TypeOf(v)
245 val := reflect.ValueOf(v)
246 if typ.Kind() == reflect.Ptr {
250 return errors.New("cannot map to non-pointer struct")
256 // MapTo maps file to given struct.
257 func (f *File) MapTo(v interface{}) error {
258 return f.Section("").MapTo(v)
261 // MapTo maps data sources to given struct with name mapper.
262 func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
263 cfg, err := Load(source, others...)
267 cfg.NameMapper = mapper
271 // MapTo maps data sources to given struct.
272 func MapTo(v, source interface{}, others ...interface{}) error {
273 return MapToWithMapper(v, nil, source, others...)
276 // reflectSliceWithProperType does the opposite thing as setSliceWithProperType.
277 func reflectSliceWithProperType(key *Key, field reflect.Value, delim string) error {
278 slice := field.Slice(0, field.Len())
279 if field.Len() == 0 {
284 sliceOf := field.Type().Elem().Kind()
285 for i := 0; i < field.Len(); i++ {
288 buf.WriteString(slice.Index(i).String())
289 case reflect.Int, reflect.Int64:
290 buf.WriteString(fmt.Sprint(slice.Index(i).Int()))
291 case reflect.Uint, reflect.Uint64:
292 buf.WriteString(fmt.Sprint(slice.Index(i).Uint()))
293 case reflect.Float64:
294 buf.WriteString(fmt.Sprint(slice.Index(i).Float()))
296 buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339))
298 return fmt.Errorf("unsupported type '[]%s'", sliceOf)
300 buf.WriteString(delim)
302 key.SetValue(buf.String()[:buf.Len()-1])
306 // reflectWithProperType does the opposite thing as setWithProperType.
307 func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error {
310 key.SetValue(field.String())
312 key.SetValue(fmt.Sprint(field.Bool()))
313 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
314 key.SetValue(fmt.Sprint(field.Int()))
315 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
316 key.SetValue(fmt.Sprint(field.Uint()))
317 case reflect.Float32, reflect.Float64:
318 key.SetValue(fmt.Sprint(field.Float()))
320 key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339)))
322 return reflectSliceWithProperType(key, field, delim)
324 return fmt.Errorf("unsupported type '%s'", t)
329 // CR: copied from encoding/json/encode.go with modifications of time.Time support.
330 // TODO: add more test coverage.
331 func isEmptyValue(v reflect.Value) bool {
333 case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
337 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
339 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
341 case reflect.Float32, reflect.Float64:
342 return v.Float() == 0
344 return v.Interface().(time.Time).IsZero()
345 case reflect.Interface, reflect.Ptr:
351 func (s *Section) reflectFrom(val reflect.Value) error {
352 if val.Kind() == reflect.Ptr {
357 for i := 0; i < typ.NumField(); i++ {
358 field := val.Field(i)
359 tpField := typ.Field(i)
361 tag := tpField.Tag.Get("ini")
366 opts := strings.SplitN(tag, ",", 2)
367 if len(opts) == 2 && opts[1] == "omitempty" && isEmptyValue(field) {
371 fieldName := s.parseFieldName(tpField.Name, opts[0])
372 if len(fieldName) == 0 || !field.CanSet() {
376 if (tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous) ||
377 (tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") {
378 // Note: The only error here is section doesn't exist.
379 sec, err := s.f.GetSection(fieldName)
381 // Note: fieldName can never be empty here, ignore error.
382 sec, _ = s.f.NewSection(fieldName)
384 if err = sec.reflectFrom(field); err != nil {
385 return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
390 // Note: Same reason as secion.
391 key, err := s.GetKey(fieldName)
393 key, _ = s.NewKey(fieldName, "")
395 if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil {
396 return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
403 // ReflectFrom reflects secion from given struct.
404 func (s *Section) ReflectFrom(v interface{}) error {
405 typ := reflect.TypeOf(v)
406 val := reflect.ValueOf(v)
407 if typ.Kind() == reflect.Ptr {
411 return errors.New("cannot reflect from non-pointer struct")
414 return s.reflectFrom(val)
417 // ReflectFrom reflects file from given struct.
418 func (f *File) ReflectFrom(v interface{}) error {
419 return f.Section("").ReflectFrom(v)
422 // ReflectFrom reflects data sources from given struct with name mapper.
423 func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error {
424 cfg.NameMapper = mapper
425 return cfg.ReflectFrom(v)
428 // ReflectFrom reflects data sources from given struct.
429 func ReflectFrom(cfg *File, v interface{}) error {
430 return ReflectFromWithMapper(cfg, v, nil)