...

Source file src/github.com/mohae/deepcopy/deepcopy.go

Documentation: github.com/mohae/deepcopy

     1  // deepcopy makes deep copies of things. A standard copy will copy the
     2  // pointers: deep copy copies the values pointed to.  Unexported field
     3  // values are not copied.
     4  //
     5  // Copyright (c)2014-2016, Joel Scoble (github.com/mohae), all rights reserved.
     6  // License: MIT, for more details check the included LICENSE file.
     7  package deepcopy
     8  
     9  import (
    10  	"reflect"
    11  	"time"
    12  )
    13  
    14  // Interface for delegating copy process to type
    15  type Interface interface {
    16  	DeepCopy() interface{}
    17  }
    18  
    19  // Iface is an alias to Copy; this exists for backwards compatibility reasons.
    20  func Iface(iface interface{}) interface{} {
    21  	return Copy(iface)
    22  }
    23  
    24  // Copy creates a deep copy of whatever is passed to it and returns the copy
    25  // in an interface{}.  The returned value will need to be asserted to the
    26  // correct type.
    27  func Copy(src interface{}) interface{} {
    28  	if src == nil {
    29  		return nil
    30  	}
    31  
    32  	// Make the interface a reflect.Value
    33  	original := reflect.ValueOf(src)
    34  
    35  	// Make a copy of the same type as the original.
    36  	cpy := reflect.New(original.Type()).Elem()
    37  
    38  	// Recursively copy the original.
    39  	copyRecursive(original, cpy)
    40  
    41  	// Return the copy as an interface.
    42  	return cpy.Interface()
    43  }
    44  
    45  // copyRecursive does the actual copying of the interface. It currently has
    46  // limited support for what it can handle. Add as needed.
    47  func copyRecursive(original, cpy reflect.Value) {
    48  	// check for implement deepcopy.Interface
    49  	if original.CanInterface() {
    50  		if copier, ok := original.Interface().(Interface); ok {
    51  			cpy.Set(reflect.ValueOf(copier.DeepCopy()))
    52  			return
    53  		}
    54  	}
    55  
    56  	// handle according to original's Kind
    57  	switch original.Kind() {
    58  	case reflect.Ptr:
    59  		// Get the actual value being pointed to.
    60  		originalValue := original.Elem()
    61  
    62  		// if  it isn't valid, return.
    63  		if !originalValue.IsValid() {
    64  			return
    65  		}
    66  		cpy.Set(reflect.New(originalValue.Type()))
    67  		copyRecursive(originalValue, cpy.Elem())
    68  
    69  	case reflect.Interface:
    70  		// If this is a nil, don't do anything
    71  		if original.IsNil() {
    72  			return
    73  		}
    74  		// Get the value for the interface, not the pointer.
    75  		originalValue := original.Elem()
    76  
    77  		// Get the value by calling Elem().
    78  		copyValue := reflect.New(originalValue.Type()).Elem()
    79  		copyRecursive(originalValue, copyValue)
    80  		cpy.Set(copyValue)
    81  
    82  	case reflect.Struct:
    83  		t, ok := original.Interface().(time.Time)
    84  		if ok {
    85  			cpy.Set(reflect.ValueOf(t))
    86  			return
    87  		}
    88  		// Go through each field of the struct and copy it.
    89  		for i := 0; i < original.NumField(); i++ {
    90  			// The Type's StructField for a given field is checked to see if StructField.PkgPath
    91  			// is set to determine if the field is exported or not because CanSet() returns false
    92  			// for settable fields.  I'm not sure why.  -mohae
    93  			if original.Type().Field(i).PkgPath != "" {
    94  				continue
    95  			}
    96  			copyRecursive(original.Field(i), cpy.Field(i))
    97  		}
    98  
    99  	case reflect.Slice:
   100  		if original.IsNil() {
   101  			return
   102  		}
   103  		// Make a new slice and copy each element.
   104  		cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))
   105  		for i := 0; i < original.Len(); i++ {
   106  			copyRecursive(original.Index(i), cpy.Index(i))
   107  		}
   108  
   109  	case reflect.Map:
   110  		if original.IsNil() {
   111  			return
   112  		}
   113  		cpy.Set(reflect.MakeMap(original.Type()))
   114  		for _, key := range original.MapKeys() {
   115  			originalValue := original.MapIndex(key)
   116  			copyValue := reflect.New(originalValue.Type()).Elem()
   117  			copyRecursive(originalValue, copyValue)
   118  			copyKey := Copy(key.Interface())
   119  			cpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue)
   120  		}
   121  
   122  	default:
   123  		cpy.Set(original)
   124  	}
   125  }
   126  

View as plain text