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
26 // NameMapper represents a ini tag name mapper.
27 type NameMapper func(string) string
29 // Built-in name getters.
31 // AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE.
32 AllCapsUnderscore NameMapper = func(raw string) string {
33 newstr := make([]rune, 0, len(raw))
34 for i, chr := range raw {
35 if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
37 newstr = append(newstr, '_')
40 newstr = append(newstr, unicode.ToUpper(chr))
44 // TitleUnderscore converts to format title_underscore.
45 TitleUnderscore NameMapper = func(raw string) string {
46 newstr := make([]rune, 0, len(raw))
47 for i, chr := range raw {
48 if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
50 newstr = append(newstr, '_')
54 newstr = append(newstr, chr)
60 func (s *Section) parseFieldName(raw, actual string) string {
64 if s.f.NameMapper != nil {
65 return s.f.NameMapper(raw)
70 func parseDelim(actual string) string {
77 var reflectTime = reflect.TypeOf(time.Now()).Kind()
79 // setWithProperType sets proper value to field based on its type,
80 // but it does not return error for failing parsing,
81 // because we want to use default value that is already assigned to strcut.
82 func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error {
85 if len(key.String()) == 0 {
88 field.SetString(key.String())
90 boolVal, err := key.Bool()
94 field.SetBool(boolVal)
95 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
96 durationVal, err := key.Duration()
98 field.Set(reflect.ValueOf(durationVal))
102 intVal, err := key.Int64()
107 // byte is an alias for uint8, so supporting uint8 breaks support for byte
108 case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
109 durationVal, err := key.Duration()
111 field.Set(reflect.ValueOf(durationVal))
115 uintVal, err := key.Uint64()
119 field.SetUint(uintVal)
121 case reflect.Float64:
122 floatVal, err := key.Float64()
126 field.SetFloat(floatVal)
128 timeVal, err := key.Time()
132 field.Set(reflect.ValueOf(timeVal))
134 vals := key.Strings(delim)
140 sliceOf := field.Type().Elem().Kind()
142 var times []time.Time
143 if sliceOf == reflectTime {
144 times = key.Times(delim)
147 slice := reflect.MakeSlice(field.Type(), numVals, numVals)
148 for i := 0; i < numVals; i++ {
151 slice.Index(i).Set(reflect.ValueOf(times[i]))
153 slice.Index(i).Set(reflect.ValueOf(vals[i]))
158 return fmt.Errorf("unsupported type '%s'", t)
163 func (s *Section) mapTo(val reflect.Value) error {
164 if val.Kind() == reflect.Ptr {
169 for i := 0; i < typ.NumField(); i++ {
170 field := val.Field(i)
171 tpField := typ.Field(i)
173 tag := tpField.Tag.Get("ini")
178 fieldName := s.parseFieldName(tpField.Name, tag)
179 if len(fieldName) == 0 || !field.CanSet() {
183 isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous
184 isStruct := tpField.Type.Kind() == reflect.Struct
186 field.Set(reflect.New(tpField.Type.Elem()))
189 if isAnonymous || isStruct {
190 if sec, err := s.f.GetSection(fieldName); err == nil {
191 if err = sec.mapTo(field); err != nil {
192 return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
198 if key, err := s.GetKey(fieldName); err == nil {
199 if err = setWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil {
200 return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
207 // MapTo maps section to given struct.
208 func (s *Section) MapTo(v interface{}) error {
209 typ := reflect.TypeOf(v)
210 val := reflect.ValueOf(v)
211 if typ.Kind() == reflect.Ptr {
215 return errors.New("cannot map to non-pointer struct")
221 // MapTo maps file to given struct.
222 func (f *File) MapTo(v interface{}) error {
223 return f.Section("").MapTo(v)
226 // MapTo maps data sources to given struct with name mapper.
227 func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
228 cfg, err := Load(source, others...)
232 cfg.NameMapper = mapper
236 // MapTo maps data sources to given struct.
237 func MapTo(v, source interface{}, others ...interface{}) error {
238 return MapToWithMapper(v, nil, source, others...)
241 // reflectWithProperType does the opposite thing with setWithProperType.
242 func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string) error {
245 key.SetValue(field.String())
247 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
248 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
251 key.SetValue(fmt.Sprint(field))
253 vals := field.Slice(0, field.Len())
254 if field.Len() == 0 {
259 isTime := fmt.Sprint(field.Type()) == "[]time.Time"
260 for i := 0; i < field.Len(); i++ {
262 buf.WriteString(vals.Index(i).Interface().(time.Time).Format(time.RFC3339))
264 buf.WriteString(fmt.Sprint(vals.Index(i)))
266 buf.WriteString(delim)
268 key.SetValue(buf.String()[:buf.Len()-1])
270 return fmt.Errorf("unsupported type '%s'", t)
275 func (s *Section) reflectFrom(val reflect.Value) error {
276 if val.Kind() == reflect.Ptr {
281 for i := 0; i < typ.NumField(); i++ {
282 field := val.Field(i)
283 tpField := typ.Field(i)
285 tag := tpField.Tag.Get("ini")
290 fieldName := s.parseFieldName(tpField.Name, tag)
291 if len(fieldName) == 0 || !field.CanSet() {
295 if (tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous) ||
296 (tpField.Type.Kind() == reflect.Struct) {
297 // Note: The only error here is section doesn't exist.
298 sec, err := s.f.GetSection(fieldName)
300 // Note: fieldName can never be empty here, ignore error.
301 sec, _ = s.f.NewSection(fieldName)
303 if err = sec.reflectFrom(field); err != nil {
304 return fmt.Errorf("error reflecting field(%s): %v", fieldName, err)
309 // Note: Same reason as secion.
310 key, err := s.GetKey(fieldName)
312 key, _ = s.NewKey(fieldName, "")
314 if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil {
315 return fmt.Errorf("error reflecting field(%s): %v", fieldName, err)
322 // ReflectFrom reflects secion from given struct.
323 func (s *Section) ReflectFrom(v interface{}) error {
324 typ := reflect.TypeOf(v)
325 val := reflect.ValueOf(v)
326 if typ.Kind() == reflect.Ptr {
330 return errors.New("cannot reflect from non-pointer struct")
333 return s.reflectFrom(val)
336 // ReflectFrom reflects file from given struct.
337 func (f *File) ReflectFrom(v interface{}) error {
338 return f.Section("").ReflectFrom(v)
341 // ReflectFrom reflects data sources from given struct with name mapper.
342 func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error {
343 cfg.NameMapper = mapper
344 return cfg.ReflectFrom(v)
347 // ReflectFrom reflects data sources from given struct.
348 func ReflectFrom(cfg *File, v interface{}) error {
349 return ReflectFromWithMapper(cfg, v, nil)