summaryrefslogtreecommitdiff
path: root/vendor/github.com/jinzhu/copier/copier.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/jinzhu/copier/copier.go')
-rw-r--r--vendor/github.com/jinzhu/copier/copier.go174
1 files changed, 141 insertions, 33 deletions
diff --git a/vendor/github.com/jinzhu/copier/copier.go b/vendor/github.com/jinzhu/copier/copier.go
index 72bf65c78..412ff5497 100644
--- a/vendor/github.com/jinzhu/copier/copier.go
+++ b/vendor/github.com/jinzhu/copier/copier.go
@@ -3,9 +3,11 @@ package copier
import (
"database/sql"
"database/sql/driver"
+ "errors"
"fmt"
"reflect"
"strings"
+ "unicode"
)
// These flags define options for tag handling
@@ -32,6 +34,19 @@ type Option struct {
DeepCopy bool
}
+// Tag Flags
+type flags struct {
+ BitFlags map[string]uint8
+ SrcNames tagNameMapping
+ DestNames tagNameMapping
+}
+
+// Field Tag name mapping
+type tagNameMapping struct {
+ FieldNameToTag map[string]string
+ TagToFieldName map[string]string
+}
+
// Copy copy things
func Copy(toValue interface{}, fromValue interface{}) (err error) {
return copier(toValue, fromValue, Option{})
@@ -134,7 +149,8 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
}
if !set(to.Index(i), from.Index(i), opt.DeepCopy) {
- err = CopyWithOption(to.Index(i).Addr().Interface(), from.Index(i).Interface(), opt)
+ // ignore error while copy slice element
+ err = copier(to.Index(i).Addr().Interface(), from.Index(i).Interface(), opt)
if err != nil {
continue
}
@@ -148,7 +164,7 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
return
}
- if to.Kind() == reflect.Slice {
+ if from.Kind() == reflect.Slice || to.Kind() == reflect.Slice {
isSlice = true
if from.Kind() == reflect.Slice {
amount = from.Len()
@@ -180,9 +196,9 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
}
// Get tag options
- tagBitFlags := map[string]uint8{}
- if dest.IsValid() {
- tagBitFlags = getBitFlags(toType)
+ flgs, err := getFlags(dest, source, toType, fromType)
+ if err != nil {
+ return err
}
// check source
@@ -193,17 +209,18 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
name := field.Name
// Get bit flags for field
- fieldFlags, _ := tagBitFlags[name]
+ fieldFlags, _ := flgs.BitFlags[name]
// Check if we should ignore copying
if (fieldFlags & tagIgnore) != 0 {
continue
}
- if fromField := source.FieldByName(name); fromField.IsValid() && !shouldIgnore(fromField, opt.IgnoreEmpty) {
+ srcFieldName, destFieldName := getFieldName(name, flgs)
+ if fromField := source.FieldByName(srcFieldName); fromField.IsValid() && !shouldIgnore(fromField, opt.IgnoreEmpty) {
// process for nested anonymous field
destFieldNotSet := false
- if f, ok := dest.Type().FieldByName(name); ok {
+ if f, ok := dest.Type().FieldByName(destFieldName); ok {
for idx := range f.Index {
destField := dest.FieldByIndex(f.Index[:idx+1])
@@ -229,7 +246,7 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
break
}
- toField := dest.FieldByName(name)
+ toField := dest.FieldByName(destFieldName)
if toField.IsValid() {
if toField.CanSet() {
if !set(toField, fromField, opt.DeepCopy) {
@@ -239,16 +256,16 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
}
if fieldFlags != 0 {
// Note that a copy was made
- tagBitFlags[name] = fieldFlags | hasCopied
+ flgs.BitFlags[name] = fieldFlags | hasCopied
}
}
} else {
// try to set to method
var toMethod reflect.Value
if dest.CanAddr() {
- toMethod = dest.Addr().MethodByName(name)
+ toMethod = dest.Addr().MethodByName(destFieldName)
} else {
- toMethod = dest.MethodByName(name)
+ toMethod = dest.MethodByName(destFieldName)
}
if toMethod.IsValid() && toMethod.Type().NumIn() == 1 && fromField.Type().AssignableTo(toMethod.Type().In(0)) {
@@ -261,16 +278,17 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
// Copy from from method to dest field
for _, field := range deepFields(toType) {
name := field.Name
+ srcFieldName, destFieldName := getFieldName(name, flgs)
var fromMethod reflect.Value
if source.CanAddr() {
- fromMethod = source.Addr().MethodByName(name)
+ fromMethod = source.Addr().MethodByName(srcFieldName)
} else {
- fromMethod = source.MethodByName(name)
+ fromMethod = source.MethodByName(srcFieldName)
}
if fromMethod.IsValid() && fromMethod.Type().NumIn() == 0 && fromMethod.Type().NumOut() == 1 && !shouldIgnore(fromMethod, opt.IgnoreEmpty) {
- if toField := dest.FieldByName(name); toField.IsValid() && toField.CanSet() {
+ if toField := dest.FieldByName(destFieldName); toField.IsValid() && toField.CanSet() {
values := fromMethod.Call([]reflect.Value{})
if len(values) >= 1 {
set(toField, values[0], opt.DeepCopy)
@@ -280,25 +298,37 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
}
}
- if isSlice {
+ if isSlice && to.Kind() == reflect.Slice {
if dest.Addr().Type().AssignableTo(to.Type().Elem()) {
if to.Len() < i+1 {
to.Set(reflect.Append(to, dest.Addr()))
} else {
- set(to.Index(i), dest.Addr(), opt.DeepCopy)
+ if !set(to.Index(i), dest.Addr(), opt.DeepCopy) {
+ // ignore error while copy slice element
+ err = copier(to.Index(i).Addr().Interface(), dest.Addr().Interface(), opt)
+ if err != nil {
+ continue
+ }
+ }
}
} else if dest.Type().AssignableTo(to.Type().Elem()) {
if to.Len() < i+1 {
to.Set(reflect.Append(to, dest))
} else {
- set(to.Index(i), dest, opt.DeepCopy)
+ if !set(to.Index(i), dest, opt.DeepCopy) {
+ // ignore error while copy slice element
+ err = copier(to.Index(i).Addr().Interface(), dest.Interface(), opt)
+ if err != nil {
+ continue
+ }
+ }
}
}
} else if initDest {
to.Set(dest)
}
- err = checkBitFlags(tagBitFlags)
+ err = checkBitFlags(flgs.BitFlags)
}
return
@@ -432,46 +462,90 @@ func set(to, from reflect.Value, deepCopy bool) bool {
}
// parseTags Parses struct tags and returns uint8 bit flags.
-func parseTags(tag string) (flags uint8) {
+func parseTags(tag string) (flg uint8, name string, err error) {
for _, t := range strings.Split(tag, ",") {
switch t {
case "-":
- flags = tagIgnore
+ flg = tagIgnore
return
case "must":
- flags = flags | tagMust
+ flg = flg | tagMust
case "nopanic":
- flags = flags | tagNoPanic
+ flg = flg | tagNoPanic
+ default:
+ if unicode.IsUpper([]rune(t)[0]) {
+ name = strings.TrimSpace(t)
+ } else {
+ err = errors.New("copier field name tag must be start upper case")
+ }
}
}
return
}
-// getBitFlags Parses struct tags for bit flags.
-func getBitFlags(toType reflect.Type) map[string]uint8 {
- flags := map[string]uint8{}
- toTypeFields := deepFields(toType)
+// getTagFlags Parses struct tags for bit flags, field name.
+func getFlags(dest, src reflect.Value, toType, fromType reflect.Type) (flags, error) {
+ flgs := flags{
+ BitFlags: map[string]uint8{},
+ SrcNames: tagNameMapping{
+ FieldNameToTag: map[string]string{},
+ TagToFieldName: map[string]string{},
+ },
+ DestNames: tagNameMapping{
+ FieldNameToTag: map[string]string{},
+ TagToFieldName: map[string]string{},
+ },
+ }
+ var toTypeFields, fromTypeFields []reflect.StructField
+ if dest.IsValid() {
+ toTypeFields = deepFields(toType)
+ }
+ if src.IsValid() {
+ fromTypeFields = deepFields(fromType)
+ }
// Get a list dest of tags
for _, field := range toTypeFields {
tags := field.Tag.Get("copier")
if tags != "" {
- flags[field.Name] = parseTags(tags)
+ var name string
+ var err error
+ if flgs.BitFlags[field.Name], name, err = parseTags(tags); err != nil {
+ return flags{}, err
+ } else if name != "" {
+ flgs.DestNames.FieldNameToTag[field.Name] = name
+ flgs.DestNames.TagToFieldName[name] = field.Name
+ }
+ }
+ }
+
+ // Get a list source of tags
+ for _, field := range fromTypeFields {
+ tags := field.Tag.Get("copier")
+ if tags != "" {
+ var name string
+ var err error
+ if _, name, err = parseTags(tags); err != nil {
+ return flags{}, err
+ } else if name != "" {
+ flgs.SrcNames.FieldNameToTag[field.Name] = name
+ flgs.SrcNames.TagToFieldName[name] = field.Name
+ }
}
}
- return flags
+ return flgs, nil
}
// checkBitFlags Checks flags for error or panic conditions.
func checkBitFlags(flagsList map[string]uint8) (err error) {
// Check flag conditions were met
- for name, flags := range flagsList {
- if flags&hasCopied == 0 {
+ for name, flgs := range flagsList {
+ if flgs&hasCopied == 0 {
switch {
- case flags&tagMust != 0 && flags&tagNoPanic != 0:
+ case flgs&tagMust != 0 && flgs&tagNoPanic != 0:
err = fmt.Errorf("field %s has must tag but was not copied", name)
return
- case flags&(tagMust) != 0:
+ case flgs&(tagMust) != 0:
panic(fmt.Sprintf("Field %s has must tag but was not copied", name))
}
}
@@ -479,6 +553,40 @@ func checkBitFlags(flagsList map[string]uint8) (err error) {
return
}
+func getFieldName(fieldName string, flgs flags) (srcFieldName string, destFieldName string) {
+ // get dest field name
+ if srcTagName, ok := flgs.SrcNames.FieldNameToTag[fieldName]; ok {
+ destFieldName = srcTagName
+ if destTagName, ok := flgs.DestNames.TagToFieldName[srcTagName]; ok {
+ destFieldName = destTagName
+ }
+ } else {
+ if destTagName, ok := flgs.DestNames.TagToFieldName[fieldName]; ok {
+ destFieldName = destTagName
+ }
+ }
+ if destFieldName == "" {
+ destFieldName = fieldName
+ }
+
+ // get source field name
+ if destTagName, ok := flgs.DestNames.FieldNameToTag[fieldName]; ok {
+ srcFieldName = destTagName
+ if srcField, ok := flgs.SrcNames.TagToFieldName[destTagName]; ok {
+ srcFieldName = srcField
+ }
+ } else {
+ if srcField, ok := flgs.SrcNames.TagToFieldName[fieldName]; ok {
+ srcFieldName = srcField
+ }
+ }
+
+ if srcFieldName == "" {
+ srcFieldName = fieldName
+ }
+ return
+}
+
func driverValuer(v reflect.Value) (i driver.Valuer, ok bool) {
if !v.CanAddr() {