169
									
								
								vendor/github.com/imdario/mergo/merge.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										169
									
								
								vendor/github.com/imdario/mergo/merge.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -13,23 +13,39 @@ import ( | ||||
| 	"reflect" | ||||
| ) | ||||
|  | ||||
| func hasExportedField(dst reflect.Value) (exported bool) { | ||||
| func hasMergeableFields(dst reflect.Value) (exported bool) { | ||||
| 	for i, n := 0, dst.NumField(); i < n; i++ { | ||||
| 		field := dst.Type().Field(i) | ||||
| 		if field.Anonymous && dst.Field(i).Kind() == reflect.Struct { | ||||
| 			exported = exported || hasExportedField(dst.Field(i)) | ||||
| 		} else { | ||||
| 			exported = exported || hasMergeableFields(dst.Field(i)) | ||||
| 		} else if isExportedComponent(&field) { | ||||
| 			exported = exported || len(field.PkgPath) == 0 | ||||
| 		} | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func isExportedComponent(field *reflect.StructField) bool { | ||||
| 	pkgPath := field.PkgPath | ||||
| 	if len(pkgPath) > 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	c := field.Name[0] | ||||
| 	if 'a' <= c && c <= 'z' || c == '_' { | ||||
| 		return false | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| type Config struct { | ||||
| 	Overwrite               bool | ||||
| 	AppendSlice             bool | ||||
| 	Transformers            Transformers | ||||
| 	overwriteWithEmptyValue bool | ||||
| 	Overwrite                    bool | ||||
| 	AppendSlice                  bool | ||||
| 	TypeCheck                    bool | ||||
| 	Transformers                 Transformers | ||||
| 	overwriteWithEmptyValue      bool | ||||
| 	overwriteSliceWithEmptyValue bool | ||||
| 	sliceDeepCopy                bool | ||||
| 	debug                        bool | ||||
| } | ||||
|  | ||||
| type Transformers interface { | ||||
| @@ -41,8 +57,10 @@ type Transformers interface { | ||||
| // short circuiting on recursive types. | ||||
| func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) { | ||||
| 	overwrite := config.Overwrite | ||||
| 	typeCheck := config.TypeCheck | ||||
| 	overwriteWithEmptySrc := config.overwriteWithEmptyValue | ||||
| 	config.overwriteWithEmptyValue = false | ||||
| 	overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue | ||||
| 	sliceDeepCopy := config.sliceDeepCopy | ||||
|  | ||||
| 	if !src.IsValid() { | ||||
| 		return | ||||
| @@ -70,14 +88,14 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co | ||||
|  | ||||
| 	switch dst.Kind() { | ||||
| 	case reflect.Struct: | ||||
| 		if hasExportedField(dst) { | ||||
| 		if hasMergeableFields(dst) { | ||||
| 			for i, n := 0, dst.NumField(); i < n; i++ { | ||||
| 				if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
| 			if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) { | ||||
| 			if (isReflectNil(dst) || overwrite) && (!isEmptyValue(src) || overwriteWithEmptySrc) { | ||||
| 				dst.Set(src) | ||||
| 			} | ||||
| 		} | ||||
| @@ -85,6 +103,14 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co | ||||
| 		if dst.IsNil() && !src.IsNil() { | ||||
| 			dst.Set(reflect.MakeMap(dst.Type())) | ||||
| 		} | ||||
|  | ||||
| 		if src.Kind() != reflect.Map { | ||||
| 			if overwrite { | ||||
| 				dst.Set(src) | ||||
| 			} | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		for _, key := range src.MapKeys() { | ||||
| 			srcElement := src.MapIndex(key) | ||||
| 			if !srcElement.IsValid() { | ||||
| @@ -94,6 +120,9 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co | ||||
| 			switch srcElement.Kind() { | ||||
| 			case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice: | ||||
| 				if srcElement.IsNil() { | ||||
| 					if overwrite { | ||||
| 						dst.SetMapIndex(key, srcElement) | ||||
| 					} | ||||
| 					continue | ||||
| 				} | ||||
| 				fallthrough | ||||
| @@ -128,13 +157,34 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co | ||||
| 						dstSlice = reflect.ValueOf(dstElement.Interface()) | ||||
| 					} | ||||
|  | ||||
| 					if (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice { | ||||
| 					if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice && !sliceDeepCopy { | ||||
| 						if typeCheck && srcSlice.Type() != dstSlice.Type() { | ||||
| 							return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type()) | ||||
| 						} | ||||
| 						dstSlice = srcSlice | ||||
| 					} else if config.AppendSlice { | ||||
| 						if srcSlice.Type() != dstSlice.Type() { | ||||
| 							return fmt.Errorf("cannot append two slice with different type (%s, %s)", srcSlice.Type(), dstSlice.Type()) | ||||
| 							return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type()) | ||||
| 						} | ||||
| 						dstSlice = reflect.AppendSlice(dstSlice, srcSlice) | ||||
| 					} else if sliceDeepCopy { | ||||
| 						i := 0 | ||||
| 						for ; i < srcSlice.Len() && i < dstSlice.Len(); i++ { | ||||
| 							srcElement := srcSlice.Index(i) | ||||
| 							dstElement := dstSlice.Index(i) | ||||
|  | ||||
| 							if srcElement.CanInterface() { | ||||
| 								srcElement = reflect.ValueOf(srcElement.Interface()) | ||||
| 							} | ||||
| 							if dstElement.CanInterface() { | ||||
| 								dstElement = reflect.ValueOf(dstElement.Interface()) | ||||
| 							} | ||||
|  | ||||
| 							if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil { | ||||
| 								return | ||||
| 							} | ||||
| 						} | ||||
|  | ||||
| 					} | ||||
| 					dst.SetMapIndex(key, dstSlice) | ||||
| 				} | ||||
| @@ -143,7 +193,7 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			if srcElement.IsValid() && (overwrite || (!dstElement.IsValid() || isEmptyValue(dstElement))) { | ||||
| 			if srcElement.IsValid() && ((srcElement.Kind() != reflect.Ptr && overwrite) || !dstElement.IsValid() || isEmptyValue(dstElement)) { | ||||
| 				if dst.IsNil() { | ||||
| 					dst.Set(reflect.MakeMap(dst.Type())) | ||||
| 				} | ||||
| @@ -154,22 +204,41 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co | ||||
| 		if !dst.CanSet() { | ||||
| 			break | ||||
| 		} | ||||
| 		if (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice { | ||||
| 		if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice && !sliceDeepCopy { | ||||
| 			dst.Set(src) | ||||
| 		} else if config.AppendSlice { | ||||
| 			if src.Type() != dst.Type() { | ||||
| 				return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type()) | ||||
| 			} | ||||
| 			dst.Set(reflect.AppendSlice(dst, src)) | ||||
| 		} else if sliceDeepCopy { | ||||
| 			for i := 0; i < src.Len() && i < dst.Len(); i++ { | ||||
| 				srcElement := src.Index(i) | ||||
| 				dstElement := dst.Index(i) | ||||
| 				if srcElement.CanInterface() { | ||||
| 					srcElement = reflect.ValueOf(srcElement.Interface()) | ||||
| 				} | ||||
| 				if dstElement.CanInterface() { | ||||
| 					dstElement = reflect.ValueOf(dstElement.Interface()) | ||||
| 				} | ||||
|  | ||||
| 				if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	case reflect.Ptr: | ||||
| 		fallthrough | ||||
| 	case reflect.Interface: | ||||
| 		if src.IsNil() { | ||||
| 		if isReflectNil(src) { | ||||
| 			if overwriteWithEmptySrc && dst.CanSet() && src.Type().AssignableTo(dst.Type()) { | ||||
| 				dst.Set(src) | ||||
| 			} | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		if src.Kind() != reflect.Interface { | ||||
| 			if dst.IsNil() || overwrite { | ||||
| 			if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) { | ||||
| 				if dst.CanSet() && (overwrite || isEmptyValue(dst)) { | ||||
| 					dst.Set(src) | ||||
| 				} | ||||
| @@ -186,18 +255,36 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co | ||||
| 			} | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		if dst.IsNil() || overwrite { | ||||
| 			if dst.CanSet() && (overwrite || isEmptyValue(dst)) { | ||||
| 				dst.Set(src) | ||||
| 			} | ||||
| 		} else if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil { | ||||
| 			return | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		if dst.Elem().Kind() == src.Elem().Kind() { | ||||
| 			if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 			break | ||||
| 		} | ||||
| 	default: | ||||
| 		if dst.CanSet() && (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst)) { | ||||
| 			dst.Set(src) | ||||
| 		mustSet := (isEmptyValue(dst) || overwrite) && (!isEmptyValue(src) || overwriteWithEmptySrc) | ||||
| 		v := fmt.Sprintf("%v", src) | ||||
| 		if v == "TestIssue106" { | ||||
| 			fmt.Println(mustSet) | ||||
| 			fmt.Println(dst.CanSet()) | ||||
| 		} | ||||
| 		if mustSet { | ||||
| 			if dst.CanSet() { | ||||
| 				dst.Set(src) | ||||
| 			} else { | ||||
| 				dst = src | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| @@ -209,7 +296,7 @@ func Merge(dst, src interface{}, opts ...func(*Config)) error { | ||||
| 	return merge(dst, src, opts...) | ||||
| } | ||||
|  | ||||
| // MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overriden by | ||||
| // MergeWithOverwrite will do the same as Merge except that non-empty dst attributes will be overridden by | ||||
| // non-empty src attribute values. | ||||
| // Deprecated: use Merge(…) with WithOverride | ||||
| func MergeWithOverwrite(dst, src interface{}, opts ...func(*Config)) error { | ||||
| @@ -228,12 +315,37 @@ func WithOverride(config *Config) { | ||||
| 	config.Overwrite = true | ||||
| } | ||||
|  | ||||
| // WithAppendSlice will make merge append slices instead of overwriting it | ||||
| // WithOverwriteWithEmptyValue will make merge override non empty dst attributes with empty src attributes values. | ||||
| func WithOverwriteWithEmptyValue(config *Config) { | ||||
| 	config.Overwrite = true | ||||
| 	config.overwriteWithEmptyValue = true | ||||
| } | ||||
|  | ||||
| // WithOverrideEmptySlice will make merge override empty dst slice with empty src slice. | ||||
| func WithOverrideEmptySlice(config *Config) { | ||||
| 	config.overwriteSliceWithEmptyValue = true | ||||
| } | ||||
|  | ||||
| // WithAppendSlice will make merge append slices instead of overwriting it. | ||||
| func WithAppendSlice(config *Config) { | ||||
| 	config.AppendSlice = true | ||||
| } | ||||
|  | ||||
| // WithTypeCheck will make merge check types while overwriting it (must be used with WithOverride). | ||||
| func WithTypeCheck(config *Config) { | ||||
| 	config.TypeCheck = true | ||||
| } | ||||
|  | ||||
| // WithSliceDeepCopy will merge slice element one by one with Overwrite flag. | ||||
| func WithSliceDeepCopy(config *Config) { | ||||
| 	config.sliceDeepCopy = true | ||||
| 	config.Overwrite = true | ||||
| } | ||||
|  | ||||
| func merge(dst, src interface{}, opts ...func(*Config)) error { | ||||
| 	if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr { | ||||
| 		return ErrNonPointerAgument | ||||
| 	} | ||||
| 	var ( | ||||
| 		vDst, vSrc reflect.Value | ||||
| 		err        error | ||||
| @@ -253,3 +365,16 @@ func merge(dst, src interface{}, opts ...func(*Config)) error { | ||||
| 	} | ||||
| 	return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config) | ||||
| } | ||||
|  | ||||
| // IsReflectNil is the reflect value provided nil | ||||
| func isReflectNil(v reflect.Value) bool { | ||||
| 	k := v.Kind() | ||||
| 	switch k { | ||||
| 	case reflect.Interface, reflect.Slice, reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr: | ||||
| 		// Both interface and slice are nil if first word is 0. | ||||
| 		// Both are always bigger than a word; assume flagIndir. | ||||
| 		return v.IsNil() | ||||
| 	default: | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Shengjing Zhu
					Shengjing Zhu