1// Copyright 2013 Dario Castañé. All rights reserved. 2// Copyright 2009 The Go Authors. All rights reserved. 3// Use of this source code is governed by a BSD-style 4// license that can be found in the LICENSE file. 5 6// Based on src/pkg/reflect/deepequal.go from official 7// golang's stdlib. 8 9package mergo 10 11import ( 12 "errors" 13 "reflect" 14) 15 16// Errors reported by Mergo when it finds invalid arguments. 17var ( 18 ErrNilArguments = errors.New("src and dst must not be nil") 19 ErrDifferentArgumentsTypes = errors.New("src and dst must be of same type") 20 ErrNotSupported = errors.New("only structs and maps are supported") 21 ErrExpectedMapAsDestination = errors.New("dst was expected to be a map") 22 ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct") 23 ErrNonPointerAgument = errors.New("dst must be a pointer") 24) 25 26// During deepMerge, must keep track of checks that are 27// in progress. The comparison algorithm assumes that all 28// checks in progress are true when it reencounters them. 29// Visited are stored in a map indexed by 17 * a1 + a2; 30type visit struct { 31 ptr uintptr 32 typ reflect.Type 33 next *visit 34} 35 36// From src/pkg/encoding/json/encode.go. 37func isEmptyValue(v reflect.Value) bool { 38 switch v.Kind() { 39 case reflect.Array, reflect.Map, reflect.Slice, reflect.String: 40 return v.Len() == 0 41 case reflect.Bool: 42 return !v.Bool() 43 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 44 return v.Int() == 0 45 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 46 return v.Uint() == 0 47 case reflect.Float32, reflect.Float64: 48 return v.Float() == 0 49 case reflect.Interface, reflect.Ptr: 50 if v.IsNil() { 51 return true 52 } 53 return isEmptyValue(v.Elem()) 54 case reflect.Func: 55 return v.IsNil() 56 case reflect.Invalid: 57 return true 58 } 59 return false 60} 61 62func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) { 63 if dst == nil || src == nil { 64 err = ErrNilArguments 65 return 66 } 67 vDst = reflect.ValueOf(dst).Elem() 68 if vDst.Kind() != reflect.Struct && vDst.Kind() != reflect.Map { 69 err = ErrNotSupported 70 return 71 } 72 vSrc = reflect.ValueOf(src) 73 // We check if vSrc is a pointer to dereference it. 74 if vSrc.Kind() == reflect.Ptr { 75 vSrc = vSrc.Elem() 76 } 77 return 78} 79