1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- package toml
- import (
- "fmt"
- "reflect"
- "strings"
- )
- const fieldTagName = "toml"
- // fieldCache maps normalized field names to their position in a struct.
- type fieldCache struct {
- named map[string]fieldInfo // fields with an explicit name in tag
- auto map[string]fieldInfo // fields with auto-assigned normalized names
- }
- type fieldInfo struct {
- index []int
- name string
- ignored bool
- }
- func makeFieldCache(cfg *Config, rt reflect.Type) fieldCache {
- named, auto := make(map[string]fieldInfo), make(map[string]fieldInfo)
- for i := 0; i < rt.NumField(); i++ {
- ft := rt.Field(i)
- // skip unexported fields
- if ft.PkgPath != "" && !ft.Anonymous {
- continue
- }
- col, _ := extractTag(ft.Tag.Get(fieldTagName))
- info := fieldInfo{index: ft.Index, name: ft.Name, ignored: col == "-"}
- if col == "" || col == "-" {
- auto[cfg.NormFieldName(rt, ft.Name)] = info
- } else {
- named[col] = info
- }
- }
- return fieldCache{named, auto}
- }
- func (fc fieldCache) findField(cfg *Config, rv reflect.Value, name string) (reflect.Value, string, error) {
- info, found := fc.named[name]
- if !found {
- info, found = fc.auto[cfg.NormFieldName(rv.Type(), name)]
- }
- if !found {
- if cfg.MissingField == nil {
- return reflect.Value{}, "", fmt.Errorf("field corresponding to `%s' is not defined in %v", name, rv.Type())
- } else {
- return reflect.Value{}, "", cfg.MissingField(rv.Type(), name)
- }
- } else if info.ignored {
- return reflect.Value{}, "", fmt.Errorf("field corresponding to `%s' in %v cannot be set through TOML", name, rv.Type())
- }
- return rv.FieldByIndex(info.index), info.name, nil
- }
- func extractTag(tag string) (col, rest string) {
- tags := strings.SplitN(tag, ",", 2)
- if len(tags) == 2 {
- return strings.TrimSpace(tags[0]), strings.TrimSpace(tags[1])
- }
- return strings.TrimSpace(tags[0]), ""
- }
|