Blame vendor/github.com/aws/aws-sdk-go/aws/awsutil/copy.go

Packit 63bb0d
package awsutil
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"io"
Packit 63bb0d
	"reflect"
Packit 63bb0d
	"time"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
// Copy deeply copies a src structure to dst. Useful for copying request and
Packit 63bb0d
// response structures.
Packit 63bb0d
//
Packit 63bb0d
// Can copy between structs of different type, but will only copy fields which
Packit 63bb0d
// are assignable, and exist in both structs. Fields which are not assignable,
Packit 63bb0d
// or do not exist in both structs are ignored.
Packit 63bb0d
func Copy(dst, src interface{}) {
Packit 63bb0d
	dstval := reflect.ValueOf(dst)
Packit 63bb0d
	if !dstval.IsValid() {
Packit 63bb0d
		panic("Copy dst cannot be nil")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	rcopy(dstval, reflect.ValueOf(src), true)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// CopyOf returns a copy of src while also allocating the memory for dst.
Packit 63bb0d
// src must be a pointer type or this operation will fail.
Packit 63bb0d
func CopyOf(src interface{}) (dst interface{}) {
Packit 63bb0d
	dsti := reflect.New(reflect.TypeOf(src).Elem())
Packit 63bb0d
	dst = dsti.Interface()
Packit 63bb0d
	rcopy(dsti, reflect.ValueOf(src), true)
Packit 63bb0d
	return
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// rcopy performs a recursive copy of values from the source to destination.
Packit 63bb0d
//
Packit 63bb0d
// root is used to skip certain aspects of the copy which are not valid
Packit 63bb0d
// for the root node of a object.
Packit 63bb0d
func rcopy(dst, src reflect.Value, root bool) {
Packit 63bb0d
	if !src.IsValid() {
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	switch src.Kind() {
Packit 63bb0d
	case reflect.Ptr:
Packit 63bb0d
		if _, ok := src.Interface().(io.Reader); ok {
Packit 63bb0d
			if dst.Kind() == reflect.Ptr && dst.Elem().CanSet() {
Packit 63bb0d
				dst.Elem().Set(src)
Packit 63bb0d
			} else if dst.CanSet() {
Packit 63bb0d
				dst.Set(src)
Packit 63bb0d
			}
Packit 63bb0d
		} else {
Packit 63bb0d
			e := src.Type().Elem()
Packit 63bb0d
			if dst.CanSet() && !src.IsNil() {
Packit 63bb0d
				if _, ok := src.Interface().(*time.Time); !ok {
Packit 63bb0d
					dst.Set(reflect.New(e))
Packit 63bb0d
				} else {
Packit 63bb0d
					tempValue := reflect.New(e)
Packit 63bb0d
					tempValue.Elem().Set(src.Elem())
Packit 63bb0d
					// Sets time.Time's unexported values
Packit 63bb0d
					dst.Set(tempValue)
Packit 63bb0d
				}
Packit 63bb0d
			}
Packit 63bb0d
			if src.Elem().IsValid() {
Packit 63bb0d
				// Keep the current root state since the depth hasn't changed
Packit 63bb0d
				rcopy(dst.Elem(), src.Elem(), root)
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
	case reflect.Struct:
Packit 63bb0d
		t := dst.Type()
Packit 63bb0d
		for i := 0; i < t.NumField(); i++ {
Packit 63bb0d
			name := t.Field(i).Name
Packit 63bb0d
			srcVal := src.FieldByName(name)
Packit 63bb0d
			dstVal := dst.FieldByName(name)
Packit 63bb0d
			if srcVal.IsValid() && dstVal.CanSet() {
Packit 63bb0d
				rcopy(dstVal, srcVal, false)
Packit 63bb0d
			}
Packit 63bb0d
		}
Packit 63bb0d
	case reflect.Slice:
Packit 63bb0d
		if src.IsNil() {
Packit 63bb0d
			break
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		s := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
Packit 63bb0d
		dst.Set(s)
Packit 63bb0d
		for i := 0; i < src.Len(); i++ {
Packit 63bb0d
			rcopy(dst.Index(i), src.Index(i), false)
Packit 63bb0d
		}
Packit 63bb0d
	case reflect.Map:
Packit 63bb0d
		if src.IsNil() {
Packit 63bb0d
			break
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		s := reflect.MakeMap(src.Type())
Packit 63bb0d
		dst.Set(s)
Packit 63bb0d
		for _, k := range src.MapKeys() {
Packit 63bb0d
			v := src.MapIndex(k)
Packit 63bb0d
			v2 := reflect.New(v.Type()).Elem()
Packit 63bb0d
			rcopy(v2, v, false)
Packit 63bb0d
			dst.SetMapIndex(k, v2)
Packit 63bb0d
		}
Packit 63bb0d
	default:
Packit 63bb0d
		// Assign the value if possible. If its not assignable, the value would
Packit 63bb0d
		// need to be converted and the impact of that may be unexpected, or is
Packit 63bb0d
		// not compatible with the dst type.
Packit 63bb0d
		if src.Type().AssignableTo(dst.Type()) {
Packit 63bb0d
			dst.Set(src)
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
}