github.com/TBD54566975/ftl@v0.219.0/internal/reflect/reflect.go (about)

     1  // From: https://github.com/golang-design/reflect/blob/main/deepcopy.go
     2  
     3  // Copyright 2022 The golang.design Initiative Authors.
     4  // All rights reserved. Use of this source code is governed
     5  // by a MIT license that can be found in the LICENSE file.
     6  //
     7  // Written by Changkun Ou <changkun.de>
     8  
     9  // Package reflect implements the proposal https://go.dev/issue/51520.
    10  //
    11  // Warning: Not largely tested. Use it with care.
    12  // nolint
    13  package reflect
    14  
    15  import (
    16  	"fmt"
    17  	"reflect"
    18  	"strings"
    19  	"unsafe"
    20  )
    21  
    22  // DeepCopyOption represents an option to customize deep copied results.
    23  type DeepCopyOption func(opt *copyConfig)
    24  
    25  type copyConfig struct {
    26  	disallowCopyUnexported        bool
    27  	disallowCopyCircular          bool
    28  	disallowCopyBidirectionalChan bool
    29  	disallowCopyTypes             []reflect.Type
    30  }
    31  
    32  // DisallowCopyUnexported returns a DeepCopyOption that disables the behavior
    33  // of copying unexported fields.
    34  func DisallowCopyUnexported() DeepCopyOption {
    35  	return func(opt *copyConfig) {
    36  		opt.disallowCopyUnexported = true
    37  	}
    38  }
    39  
    40  // DisallowCopyCircular returns a DeepCopyOption that disables the behavior
    41  // of copying circular structures.
    42  func DisallowCopyCircular() DeepCopyOption {
    43  	return func(opt *copyConfig) {
    44  		opt.disallowCopyCircular = true
    45  	}
    46  }
    47  
    48  // DisallowCopyBidirectionalChan returns a DeepCopyOption that disables
    49  // the behavior of producing new channel when a bidirectional channel is copied.
    50  func DisallowCopyBidirectionalChan() DeepCopyOption {
    51  	return func(opt *copyConfig) {
    52  		opt.disallowCopyBidirectionalChan = true
    53  	}
    54  }
    55  
    56  // DisallowTypes returns a DeepCopyOption that disallows copying any types
    57  // that are in given values.
    58  func DisallowTypes(val ...any) DeepCopyOption {
    59  	return func(opt *copyConfig) {
    60  		for i := range val {
    61  			opt.disallowCopyTypes = append(opt.disallowCopyTypes, reflect.TypeOf(val[i]))
    62  		}
    63  	}
    64  }
    65  
    66  // DeepCopy copies src to dst recursively.
    67  //
    68  // Two values of identical type are deeply copied if one of the following
    69  // cases apply.
    70  //
    71  // Numbers, bools, strings are deeply copied and have different underlying
    72  // memory address.
    73  //
    74  // Slice and Array values are deeply copied, including its elements.
    75  //
    76  // Map values are deeply copied for all of its key and corresponding
    77  // values.
    78  //
    79  // Pointer values are deeply copied for their pointed value, and the
    80  // pointer points to the deeply copied value.
    81  //
    82  // Struct values are deeply copied for all fields, including exported
    83  // and unexported.
    84  //
    85  // Interface values are deeply copied if the underlying type can be
    86  // deeply copied.
    87  //
    88  // There are a few exceptions that may result in a deeply copied value not
    89  // deeply equal (asserted by DeepEqual(dst, src)) to the source value:
    90  //
    91  //  1. Func values are still refer to the same function
    92  //  2. Chan values are replaced by newly created channels
    93  //  3. One-way Chan values (receive or read-only) values are still refer
    94  //     to the same channel
    95  //
    96  // Note that while correct uses of DeepCopy do exist, they are not rare.
    97  // The use of DeepCopy often indicates the copying object does not contain
    98  // a singleton or is never meant to be copied, such as sync.Mutex, os.File,
    99  // net.Conn, js.Value, etc. In these cases, the copied value retains the
   100  // memory representations of the source value but may result in unexpected
   101  // consequences in follow-up usage, the caller should clear these values
   102  // depending on their usage context.
   103  //
   104  // To change these predefined behaviors, use provided DeepCopyOption.
   105  func DeepCopy[T any](src T, opts ...DeepCopyOption) (dst T) {
   106  	ptrs := map[uintptr]any{}
   107  	conf := &copyConfig{}
   108  	for _, opt := range opts {
   109  		opt(conf)
   110  	}
   111  
   112  	ret := copyAny(src, ptrs, conf)
   113  	if v, ok := ret.(T); ok {
   114  		dst = v
   115  		return
   116  	}
   117  	panic(fmt.Sprintf("reflect: internal error: copied value is not typed in %T, got %T", src, ret))
   118  }
   119  
   120  func copyAny(src any, ptrs map[uintptr]any, copyConf *copyConfig) (dst any) {
   121  	if len(copyConf.disallowCopyTypes) != 0 {
   122  		for i := range copyConf.disallowCopyTypes {
   123  			if reflect.TypeOf(src) == copyConf.disallowCopyTypes[i] {
   124  				panic(fmt.Sprintf("reflect: deep copying type %T is disallowed", src))
   125  			}
   126  		}
   127  	}
   128  
   129  	v := reflect.ValueOf(src)
   130  	if !v.IsValid() {
   131  		return src
   132  	}
   133  
   134  	// Look up the corresponding copy function.
   135  	switch v.Kind() {
   136  	case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
   137  		reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
   138  		reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64,
   139  		reflect.Complex64, reflect.Complex128, reflect.Func:
   140  		dst = copyPremitive(src, ptrs, copyConf)
   141  	case reflect.String:
   142  		dst = strings.Clone(src.(string))
   143  	case reflect.Slice:
   144  		dst = copySlice(src, ptrs, copyConf)
   145  	case reflect.Array:
   146  		dst = copyArray(src, ptrs, copyConf)
   147  	case reflect.Map:
   148  		dst = copyMap(src, ptrs, copyConf)
   149  	case reflect.Ptr, reflect.UnsafePointer:
   150  		dst = copyPointer(src, ptrs, copyConf)
   151  	case reflect.Struct:
   152  		dst = copyStruct(src, ptrs, copyConf)
   153  	case reflect.Interface:
   154  		dst = copyAny(src, ptrs, copyConf)
   155  	case reflect.Chan:
   156  		dst = copyChan(src, ptrs, copyConf)
   157  	default:
   158  		panic(fmt.Sprintf("reflect: internal error: unknown type %v", v.Kind()))
   159  	}
   160  	return
   161  }
   162  
   163  func copyPremitive(src any, ptr map[uintptr]any, copyConf *copyConfig) (dst any) {
   164  	kind := reflect.ValueOf(src).Kind()
   165  	switch kind {
   166  	case reflect.Array, reflect.Chan, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.Struct, reflect.UnsafePointer:
   167  		panic(fmt.Sprintf("reflect: internal error: type %v is not a primitive", kind))
   168  	}
   169  	dst = src
   170  	return
   171  }
   172  
   173  func copySlice(x any, ptrs map[uintptr]any, copyConf *copyConfig) any {
   174  	v := reflect.ValueOf(x)
   175  	kind := v.Kind()
   176  	if kind != reflect.Slice {
   177  		panic(fmt.Sprintf("reflect: internal error: type %v is not a slice", kind))
   178  	}
   179  
   180  	size := v.Len()
   181  	t := reflect.TypeOf(x)
   182  	dc := reflect.MakeSlice(t, size, size)
   183  	for i := 0; i < size; i++ {
   184  		iv := reflect.ValueOf(copyAny(v.Index(i).Interface(), ptrs, copyConf))
   185  		if iv.IsValid() {
   186  			dc.Index(i).Set(iv)
   187  		}
   188  	}
   189  	return dc.Interface()
   190  }
   191  
   192  func copyArray(x any, ptrs map[uintptr]any, copyConf *copyConfig) any {
   193  	v := reflect.ValueOf(x)
   194  	if v.Kind() != reflect.Array {
   195  		panic(fmt.Errorf("reflect: internal error: must be an Array; got %v", v.Kind()))
   196  	}
   197  	t := reflect.TypeOf(x)
   198  	size := t.Len()
   199  	dc := reflect.New(reflect.ArrayOf(size, t.Elem())).Elem()
   200  	for i := 0; i < size; i++ {
   201  		item := copyAny(v.Index(i).Interface(), ptrs, copyConf)
   202  		dc.Index(i).Set(reflect.ValueOf(item))
   203  	}
   204  	return dc.Interface()
   205  }
   206  
   207  func copyMap(x any, ptrs map[uintptr]any, copyConf *copyConfig) any {
   208  	v := reflect.ValueOf(x)
   209  	if v.Kind() != reflect.Map {
   210  		panic(fmt.Errorf("reflect: internal error: must be a Map; got %v", v.Kind()))
   211  	}
   212  	t := reflect.TypeOf(x)
   213  	dc := reflect.MakeMapWithSize(t, v.Len())
   214  	iter := v.MapRange()
   215  	for iter.Next() {
   216  		item := copyAny(iter.Value().Interface(), ptrs, copyConf)
   217  		k := copyAny(iter.Key().Interface(), ptrs, copyConf)
   218  		dc.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(item))
   219  	}
   220  	return dc.Interface()
   221  }
   222  
   223  func copyPointer(x any, ptrs map[uintptr]any, copyConf *copyConfig) any {
   224  	v := reflect.ValueOf(x)
   225  	t := reflect.TypeOf(x)
   226  
   227  	if v.Kind() != reflect.Pointer {
   228  		panic(fmt.Errorf("reflect: internal error: must be a Pointer or Ptr; got %v", v.Kind()))
   229  	}
   230  
   231  	if v.IsNil() {
   232  		return reflect.New(t).Elem().Interface()
   233  	}
   234  
   235  	addr := uintptr(v.UnsafePointer())
   236  	if dc, ok := ptrs[addr]; ok {
   237  		if copyConf.disallowCopyCircular {
   238  			panic("reflect: deep copy dircular value is disallowed")
   239  		}
   240  		return dc
   241  	}
   242  
   243  	dc := reflect.New(t.Elem())
   244  	ptrs[addr] = dc.Interface()
   245  
   246  	item := copyAny(v.Elem().Interface(), ptrs, copyConf)
   247  	iv := reflect.ValueOf(item)
   248  	if iv.IsValid() {
   249  		dc.Elem().Set(reflect.ValueOf(item))
   250  	}
   251  	return dc.Interface()
   252  }
   253  
   254  func copyStruct(x any, ptrs map[uintptr]any, copyConf *copyConfig) any {
   255  	v := reflect.ValueOf(x)
   256  	if v.Kind() != reflect.Struct {
   257  		panic(fmt.Errorf("reflect: internal error: must be a Struct; got %v", v.Kind()))
   258  	}
   259  	t := reflect.TypeOf(x)
   260  	dc := reflect.New(t)
   261  	for i := 0; i < t.NumField(); i++ {
   262  		if copyConf.disallowCopyUnexported {
   263  			f := t.Field(i)
   264  			if f.PkgPath != "" {
   265  				continue
   266  			}
   267  			item := copyAny(v.Field(i).Interface(), ptrs, copyConf)
   268  			dc.Elem().Field(i).Set(reflect.ValueOf(item))
   269  		} else {
   270  			item := copyAny(valueInterfaceUnsafe(v.Field(i)), ptrs, copyConf)
   271  			if iv := reflect.ValueOf(item); iv.IsValid() {
   272  				setField(dc.Elem().Field(i), iv)
   273  			}
   274  		}
   275  	}
   276  	return dc.Elem().Interface()
   277  }
   278  
   279  func copyChan(x any, ptrs map[uintptr]any, copyConf *copyConfig) any {
   280  	v := reflect.ValueOf(x)
   281  	if v.Kind() != reflect.Chan {
   282  		panic(fmt.Errorf("reflect: internal error: must be a Chan; got %v", v.Kind()))
   283  	}
   284  	t := reflect.TypeOf(x)
   285  	dir := t.ChanDir()
   286  	var dc any
   287  	switch dir {
   288  	case reflect.BothDir:
   289  		if !copyConf.disallowCopyBidirectionalChan {
   290  			dc = reflect.MakeChan(t, v.Cap()).Interface()
   291  		}
   292  		fallthrough
   293  	case reflect.SendDir, reflect.RecvDir:
   294  		dc = x
   295  	}
   296  	return dc
   297  }
   298  
   299  // valueInterfaceUnsafe overpasses the reflect package check regarding
   300  // unexported methods.
   301  func valueInterfaceUnsafe(v reflect.Value) any {
   302  	return reflect_valueInterface(v, false)
   303  }
   304  
   305  // setField sets the given value to the field value, regardless whether
   306  // the filed is exported or not.
   307  func setField(field reflect.Value, value reflect.Value) {
   308  	reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Set(value)
   309  }
   310  
   311  //go:linkname reflect_valueInterface reflect.valueInterface
   312  func reflect_valueInterface(v reflect.Value, safe bool) any