...

Source file src/github.com/aws/aws-sdk-go-v2/internal/awsutil/copy.go

Documentation: github.com/aws/aws-sdk-go-v2/internal/awsutil

     1  package awsutil
     2  
     3  import (
     4  	"io"
     5  	"reflect"
     6  	"time"
     7  )
     8  
     9  // Copy deeply copies a src structure to dst. Useful for copying request and
    10  // response structures.
    11  //
    12  // Can copy between structs of different type, but will only copy fields which
    13  // are assignable, and exist in both structs. Fields which are not assignable,
    14  // or do not exist in both structs are ignored.
    15  func Copy(dst, src interface{}) {
    16  	dstval := reflect.ValueOf(dst)
    17  	if !dstval.IsValid() {
    18  		panic("Copy dst cannot be nil")
    19  	}
    20  
    21  	rcopy(dstval, reflect.ValueOf(src), true)
    22  }
    23  
    24  // CopyOf returns a copy of src while also allocating the memory for dst.
    25  // src must be a pointer type or this operation will fail.
    26  func CopyOf(src interface{}) (dst interface{}) {
    27  	dsti := reflect.New(reflect.TypeOf(src).Elem())
    28  	dst = dsti.Interface()
    29  	rcopy(dsti, reflect.ValueOf(src), true)
    30  	return
    31  }
    32  
    33  // rcopy performs a recursive copy of values from the source to destination.
    34  //
    35  // root is used to skip certain aspects of the copy which are not valid
    36  // for the root node of a object.
    37  func rcopy(dst, src reflect.Value, root bool) {
    38  	if !src.IsValid() {
    39  		return
    40  	}
    41  
    42  	switch src.Kind() {
    43  	case reflect.Ptr:
    44  		if _, ok := src.Interface().(io.Reader); ok {
    45  			if dst.Kind() == reflect.Ptr && dst.Elem().CanSet() {
    46  				dst.Elem().Set(src)
    47  			} else if dst.CanSet() {
    48  				dst.Set(src)
    49  			}
    50  		} else {
    51  			e := src.Type().Elem()
    52  			if dst.CanSet() && !src.IsNil() {
    53  				if _, ok := src.Interface().(*time.Time); !ok {
    54  					if dst.Kind() == reflect.String {
    55  						dst.SetString(e.String())
    56  					} else {
    57  						dst.Set(reflect.New(e))
    58  					}
    59  				} else {
    60  					tempValue := reflect.New(e)
    61  					tempValue.Elem().Set(src.Elem())
    62  					// Sets time.Time's unexported values
    63  					dst.Set(tempValue)
    64  				}
    65  			}
    66  			if dst.Kind() != reflect.String && src.Elem().IsValid() {
    67  				// Keep the current root state since the depth hasn't changed
    68  				rcopy(dst.Elem(), src.Elem(), root)
    69  			}
    70  		}
    71  	case reflect.Struct:
    72  		t := dst.Type()
    73  		for i := 0; i < t.NumField(); i++ {
    74  			name := t.Field(i).Name
    75  			srcVal := src.FieldByName(name)
    76  			dstVal := dst.FieldByName(name)
    77  			if srcVal.IsValid() && dstVal.CanSet() {
    78  				rcopy(dstVal, srcVal, false)
    79  			}
    80  		}
    81  	case reflect.Slice:
    82  		if src.IsNil() {
    83  			break
    84  		}
    85  
    86  		s := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
    87  		dst.Set(s)
    88  		for i := 0; i < src.Len(); i++ {
    89  			rcopy(dst.Index(i), src.Index(i), false)
    90  		}
    91  	case reflect.Map:
    92  		if src.IsNil() {
    93  			break
    94  		}
    95  
    96  		s := reflect.MakeMap(src.Type())
    97  		dst.Set(s)
    98  		for _, k := range src.MapKeys() {
    99  			v := src.MapIndex(k)
   100  			v2 := reflect.New(v.Type()).Elem()
   101  			rcopy(v2, v, false)
   102  			dst.SetMapIndex(k, v2)
   103  		}
   104  	default:
   105  		// Assign the value if possible. If its not assignable, the value would
   106  		// need to be converted and the impact of that may be unexpected, or is
   107  		// not compatible with the dst type.
   108  		if src.Type().AssignableTo(dst.Type()) {
   109  			dst.Set(src)
   110  		}
   111  	}
   112  }
   113  

View as plain text