github.com/influx6/npkg@v0.8.8/nreflect/deepcopy.go (about)

     1  package nreflect
     2  
     3  import (
     4  	"reflect"
     5  	"unsafe"
     6  
     7  	"github.com/influx6/npkg/nerror"
     8  	"github.com/jinzhu/copier"
     9  )
    10  
    11  // DeepCopy copies giving value returning a new distinct value,
    12  // else an error due to failure.
    13  //
    14  // DeepCopy will never attempt to duplicate the following types, as it will simply
    15  // return the value it received.
    16  //
    17  // 1. Channels
    18  // 2. Interface
    19  // 3. unsafe.Pointer
    20  // 4. Func
    21  //
    22  // For structs, we use github.com/jinzhu/copier for copying, so all rules in that library
    23  // applies here also.
    24  func DeepCopy(elem interface{}) (interface{}, error) {
    25  	var err error
    26  	var refValue reflect.Value
    27  
    28  	switch bm := elem.(type) {
    29  	case reflect.Type:
    30  		var base = ValueOf(bm)
    31  		if bm.Kind() == reflect.Ptr {
    32  			return base, nil
    33  		}
    34  		return IndirectValue(base), nil
    35  	case reflect.Value:
    36  		refValue, err = deepCopyValue(IndirectValue(bm), bm.Kind() == reflect.Ptr)
    37  	default:
    38  		var base = ValueOf(elem)
    39  		refValue, err = deepCopyValue(IndirectValue(base), base.Kind() == reflect.Ptr)
    40  	}
    41  
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  	return refValue.Interface(), nil
    46  }
    47  
    48  // DeepCopyValue uses the internal deepCopyValue function to make a copy of giving
    49  // reflect value type adequately ensuring to return a pointer if a pointer value
    50  // was giving to it else returning a value.
    51  //
    52  // DeepCopy will never attempt to duplicate the following types, as it will simply
    53  // return the value it received.
    54  //
    55  // 1. Channels
    56  // 2. Interface
    57  // 3. unsafe.Pointer
    58  // 4. Func
    59  //
    60  // For structs, we use github.com/jinzhu/copier for copying, so all rules in that library
    61  // applies here also.
    62  func DeepCopyValue(baseValue reflect.Value) (interface{}, error) {
    63  	var refValue, err = deepCopyValue(IndirectValue(baseValue), baseValue.Kind() == reflect.Ptr)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	return refValue.Interface(), nil
    68  }
    69  
    70  // deepCopyValue copies giving reflect.Value returning a new distinct value containing
    71  // copy of data, else an error due to failure.
    72  //
    73  // DeepCopy will never attempt to duplicate the following types, as it will simply
    74  // return the value it received.
    75  //
    76  // 1. Channels
    77  // 2. Interface
    78  // 3. unsafe.Pointer
    79  // 4. Func
    80  //
    81  // For structs, we use github.com/jinzhu/copier for copying, so all rules in that library
    82  // applies here also.
    83  func deepCopyValue(baseValue reflect.Value, pointerType bool) (reflect.Value, error) {
    84  	if !baseValue.IsValid() {
    85  		return baseValue, nil
    86  	}
    87  
    88  	var valueType = baseValue.Type()
    89  
    90  	switch baseValue.Kind() {
    91  	case reflect.Func:
    92  		return baseValue, nil
    93  	case reflect.Interface:
    94  		return baseValue, nil
    95  	case reflect.Chan:
    96  		return baseValue, nil
    97  	case reflect.UnsafePointer:
    98  		return baseValue, nil
    99  	case reflect.Map:
   100  		var newPtrVal = reflect.MakeMap(baseValue.Type())
   101  		var newValue = IndirectValue(newPtrVal)
   102  		if err := copyMap(&newValue, baseValue); err != nil {
   103  			return reflect.Value{}, err
   104  		}
   105  		if pointerType {
   106  			return newPtrVal, nil
   107  		}
   108  		return newValue, nil
   109  	case reflect.Struct:
   110  		var newPtrVal = reflect.New(valueType)
   111  		var newValue = IndirectValue(newPtrVal)
   112  		if err := copier.Copy(newPtrVal.Interface(), baseValue.Interface()); err != nil {
   113  			return reflect.Value{}, nerror.Wrap(err, "Failed to copy struct type %T", baseValue.Interface())
   114  		}
   115  		if pointerType {
   116  			return newPtrVal, nil
   117  		}
   118  		return newValue, nil
   119  	case reflect.Array:
   120  		var newPtrVal = reflect.New(valueType)
   121  		var newValue = IndirectValue(newPtrVal)
   122  		var copied = reflect.Copy(newValue, baseValue)
   123  		if copied != baseValue.Len() {
   124  			return reflect.Value{}, nerror.New("copied has different length to original")
   125  		}
   126  		if pointerType {
   127  			return newPtrVal, nil
   128  		}
   129  		return newValue, nil
   130  	case reflect.Slice:
   131  		var newPtrVal = reflect.MakeSlice(valueType, baseValue.Len(), baseValue.Cap())
   132  		var newValue = IndirectValue(newPtrVal)
   133  		var copied = reflect.Copy(newValue, baseValue)
   134  		if copied != baseValue.Len() {
   135  			return reflect.Value{}, nerror.New("copied has different length to original")
   136  		}
   137  		if pointerType {
   138  			return newPtrVal, nil
   139  		}
   140  		return newValue, nil
   141  	}
   142  
   143  	var newPtrValue = reflect.New(valueType)
   144  	if newPtrValue.CanSet() {
   145  		return reflect.Value{}, nerror.New("unable to set value for type %q", baseValue.Type())
   146  	}
   147  
   148  	var newValue = IndirectValue(newPtrValue)
   149  	newValue.Set(baseValue)
   150  	if pointerType {
   151  		return newPtrValue, nil
   152  	}
   153  	return newValue, nil
   154  }
   155  
   156  func copyMap(dest *reflect.Value, src reflect.Value) error {
   157  	if dest.Kind() != reflect.Map && src.Kind() != reflect.Map {
   158  		return nerror.New("unable to copy in between map and another type")
   159  	}
   160  
   161  	var keys = src.MapKeys()
   162  	for _, key := range keys {
   163  		newKey, err := deepCopyValue(IndirectValue(key), key.Kind() == reflect.Ptr)
   164  		if err != nil {
   165  			return err
   166  		}
   167  
   168  		var mapValue = src.MapIndex(key)
   169  		newValue, err := deepCopyValue(IndirectValue(mapValue), mapValue.Kind() == reflect.Ptr)
   170  		if err != nil {
   171  			return err
   172  		}
   173  		dest.SetMapIndex(newKey, newValue)
   174  	}
   175  	return nil
   176  }
   177  
   178  // func IndirectValue returns the reflect.Value if the provided value is a pointer kind.
   179  func IndirectValue(reflectValue reflect.Value) reflect.Value {
   180  	for reflectValue.Kind() == reflect.Ptr {
   181  		reflectValue = reflectValue.Elem()
   182  	}
   183  	return reflectValue
   184  }
   185  
   186  // func IndirectType returns the reflect.Type if the provided value is a pointer kind.
   187  func IndirectType(reflectType reflect.Type) reflect.Type {
   188  	for reflectType.Kind() == reflect.Ptr || reflectType.Kind() == reflect.Slice {
   189  		reflectType = reflectType.Elem()
   190  	}
   191  	return reflectType
   192  }
   193  
   194  // ValueOf returns giving value of elem, if elem is a reflect.Type returns
   195  // a new reflect.Value for giving type.
   196  func ValueOf(elem interface{}) reflect.Value {
   197  	if telem, ok := elem.(reflect.Value); ok {
   198  		return telem
   199  	}
   200  	if telem, ok := elem.(reflect.Type); ok {
   201  		return reflect.New(telem)
   202  	}
   203  	return reflect.ValueOf(elem)
   204  }
   205  
   206  // TypeOf returns giving type of elem.
   207  func TypeOf(elem interface{}) reflect.Type {
   208  	if telem, ok := elem.(reflect.Type); ok {
   209  		return telem
   210  	}
   211  	if telem, ok := elem.(reflect.Value); ok {
   212  		return telem.Type()
   213  	}
   214  	return reflect.TypeOf(elem)
   215  }
   216  
   217  // CopyStringMap returns a new copy of a giving string map.
   218  func CopyStringMap(src map[string]string) map[string]string {
   219  	var dest = make(map[string]string, len(src))
   220  	for key, value := range src {
   221  		dest[key] = value
   222  	}
   223  	return dest
   224  }
   225  
   226  // CopyStringKeyMap returns a new copy of a giving string keyed map.
   227  func CopyStringKeyMap(src map[string]interface{}) (map[string]interface{}, error) {
   228  	var dest = make(map[string]interface{}, len(src))
   229  	for key, value := range src {
   230  		var myValue, err = DeepCopy(value)
   231  		if err != nil {
   232  			return dest, err
   233  		}
   234  		dest[key] = myValue
   235  	}
   236  	return dest, nil
   237  }
   238  
   239  // CopyInterfaceKeyMap returns a new copy of a giving interface keyed map.
   240  func CopyInterfaceKeyMap(src map[interface{}]interface{}) (map[interface{}]interface{}, error) {
   241  	var dest = make(map[interface{}]interface{}, len(src))
   242  	for key, value := range src {
   243  		myValue, err := DeepCopy(value)
   244  		if err != nil {
   245  			return dest, err
   246  		}
   247  		myKey, err := DeepCopy(key)
   248  		if err != nil {
   249  			return dest, err
   250  		}
   251  		dest[myKey] = myValue
   252  	}
   253  	return dest, nil
   254  }
   255  
   256  // CopyBytes returns a new copy of giving byte slice.
   257  func CopyBytes(bu []byte) []byte {
   258  	var cu = make([]byte, len(bu))
   259  	copy(cu, bu)
   260  	return cu
   261  }
   262  
   263  //*****************************************************
   264  // unsafe methods
   265  //*****************************************************
   266  
   267  // byte2String converts a byte slice into a string.
   268  func bytes2String(bc []byte) string {
   269  	return *(*string)(unsafe.Pointer(&bc))
   270  }
   271  
   272  // string2Bytes converts a string into a byte slice.
   273  func string2Bytes(bc string) []byte {
   274  	return *(*[]byte)(unsafe.Pointer(&bc))
   275  }