summaryrefslogtreecommitdiff
path: root/vendor/github.com/gocarina/gocsv/reflect.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gocarina/gocsv/reflect.go')
-rw-r--r--vendor/github.com/gocarina/gocsv/reflect.go57
1 files changed, 45 insertions, 12 deletions
diff --git a/vendor/github.com/gocarina/gocsv/reflect.go b/vendor/github.com/gocarina/gocsv/reflect.go
index 9217e30..dfc63b3 100644
--- a/vendor/github.com/gocarina/gocsv/reflect.go
+++ b/vendor/github.com/gocarina/gocsv/reflect.go
@@ -35,19 +35,21 @@ func (f fieldInfo) matchesKey(key string) bool {
return false
}
+var structInfoCache sync.Map
var structMap = make(map[reflect.Type]*structInfo)
var structMapMutex sync.RWMutex
func getStructInfo(rType reflect.Type) *structInfo {
- structMapMutex.RLock()
- stInfo, ok := structMap[rType]
- structMapMutex.RUnlock()
+ stInfo, ok := structInfoCache.Load(rType)
if ok {
- return stInfo
+ return stInfo.(*structInfo)
}
+
fieldsList := getFieldInfos(rType, []int{})
stInfo = &structInfo{fieldsList}
- return stInfo
+ structInfoCache.Store(rType, stInfo)
+
+ return stInfo.(*structInfo)
}
func getFieldInfos(rType reflect.Type, parentIndexChain []int) []fieldInfo {
@@ -58,19 +60,40 @@ func getFieldInfos(rType reflect.Type, parentIndexChain []int) []fieldInfo {
if field.PkgPath != "" {
continue
}
- indexChain := append(parentIndexChain, i)
- // if the field is an embedded struct, create a fieldInfo for each of its fields
- if field.Anonymous && field.Type.Kind() == reflect.Struct {
- fieldsList = append(fieldsList, getFieldInfos(field.Type, indexChain)...)
+
+ var cpy = make([]int, len(parentIndexChain))
+ copy(cpy, parentIndexChain)
+ indexChain := append(cpy, i)
+
+ // if the field is a pointer to a struct, follow the pointer then create fieldinfo for each field
+ if field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct {
+ // unless it implements marshalText or marshalCSV. Structs that implement this
+ // should result in one value and not have their fields exposed
+ if !(canMarshal(field.Type.Elem())) {
+ fieldsList = append(fieldsList, getFieldInfos(field.Type.Elem(), indexChain)...)
+ }
+ }
+ // if the field is a struct, create a fieldInfo for each of its fields
+ if field.Type.Kind() == reflect.Struct {
+ // unless it implements marshalText or marshalCSV. Structs that implement this
+ // should result in one value and not have their fields exposed
+ if !(canMarshal(field.Type)) {
+ fieldsList = append(fieldsList, getFieldInfos(field.Type, indexChain)...)
+ }
+ }
+
+ // if the field is an embedded struct, ignore the csv tag
+ if field.Anonymous {
continue
}
+
fieldInfo := fieldInfo{IndexChain: indexChain}
- fieldTag := field.Tag.Get("csv")
+ fieldTag := field.Tag.Get(TagName)
fieldTags := strings.Split(fieldTag, TagSeparator)
filteredTags := []string{}
for _, fieldTagEntry := range fieldTags {
if fieldTagEntry != "omitempty" {
- filteredTags = append(filteredTags, fieldTagEntry)
+ filteredTags = append(filteredTags, normalizeName(fieldTagEntry))
} else {
fieldInfo.omitEmpty = true
}
@@ -81,7 +104,7 @@ func getFieldInfos(rType reflect.Type, parentIndexChain []int) []fieldInfo {
} else if len(filteredTags) > 0 && filteredTags[0] != "" {
fieldInfo.keys = filteredTags
} else {
- fieldInfo.keys = []string{field.Name}
+ fieldInfo.keys = []string{normalizeName(field.Name)}
}
fieldsList = append(fieldsList, fieldInfo)
}
@@ -105,3 +128,13 @@ func getConcreteReflectValueAndType(in interface{}) (reflect.Value, reflect.Type
}
return value, value.Type()
}
+
+var errorInterface = reflect.TypeOf((*error)(nil)).Elem()
+
+func isErrorType(outType reflect.Type) bool {
+ if outType.Kind() != reflect.Interface {
+ return false
+ }
+
+ return outType.Implements(errorInterface)
+}