github.com/wfusion/gofusion@v1.1.14/common/utils/clone/structtype.go (about)

     1  // Copyright 2019 Huan Du. All rights reserved.
     2  // Licensed under the MIT license that can be found in the LICENSE file.
     3  
     4  package clone
     5  
     6  import (
     7  	"crypto/elliptic"
     8  	"fmt"
     9  	"reflect"
    10  	"sync"
    11  	"sync/atomic"
    12  	"time"
    13  	"unsafe"
    14  )
    15  
    16  type structType struct {
    17  	PointerFields []structFieldType
    18  	fn            Func
    19  }
    20  
    21  type structFieldType struct {
    22  	Offset uintptr // The offset from the beginning of the struct.
    23  	Index  int     // The index of the field.
    24  }
    25  
    26  var zeroStructType = structType{}
    27  
    28  func init() {
    29  	// Some well-known scalar-like structs.
    30  	MarkAsScalar(reflect.TypeOf(time.Time{}))
    31  	MarkAsScalar(reflect.TypeOf(reflect.Value{}))
    32  
    33  	// Special case for elliptic.Curve which is used by TLS ECC certificate.
    34  	// Package crypto/tls uses elliptic.Curve as enum values
    35  	// so that they should be treated as opaque pointers.
    36  	//
    37  	// As elliptic.Curve is an interface, it can be *elliptic.CurveParam or elliptic.p256Curve.
    38  	MarkAsOpaquePointer(reflect.TypeOf(&elliptic.CurveParams{}))
    39  	curves := []elliptic.Curve{
    40  		elliptic.P224(),
    41  		elliptic.P256(),
    42  		elliptic.P384(),
    43  		elliptic.P521(),
    44  	}
    45  
    46  	for _, curve := range curves {
    47  		MarkAsOpaquePointer(reflect.ValueOf(curve).Type())
    48  	}
    49  
    50  	// Special case for reflect.Type (actually *reflect.rtype):
    51  	// The *reflect.rtype should not be copied as it is immutable and
    52  	// may point to a variable that actual type is not reflect.rtype,
    53  	// e.g. *reflect.arrayType or *reflect.chanType.
    54  	MarkAsOpaquePointer(reflect.TypeOf(reflect.TypeOf(0)))
    55  
    56  	// Some well-known no-copy structs.
    57  	//
    58  	// Almost all structs defined in package "sync" and "go.uber.org/atomic" are set
    59  	// except `sync.Once` which can be safely cloned with a correct done value.
    60  	SetCustomFunc(reflect.TypeOf(sync.Mutex{}), emptyCloneFunc)
    61  	SetCustomFunc(reflect.TypeOf(sync.RWMutex{}), emptyCloneFunc)
    62  	SetCustomFunc(reflect.TypeOf(sync.WaitGroup{}), emptyCloneFunc)
    63  	SetCustomFunc(reflect.TypeOf(sync.Cond{}), func(allocator *Allocator, old, new reflect.Value) {
    64  		// Copy the New func from old value.
    65  		oldL := old.FieldByName("L")
    66  		newL := allocator.Clone(oldL)
    67  		new.FieldByName("L").Set(newL)
    68  	})
    69  	SetCustomFunc(reflect.TypeOf(sync.Pool{}), func(allocator *Allocator, old, new reflect.Value) {
    70  		// Copy the New func from old value.
    71  		oldFn := old.FieldByName("New")
    72  		newFn := allocator.Clone(oldFn)
    73  		new.FieldByName("New").Set(newFn)
    74  	})
    75  	SetCustomFunc(reflect.TypeOf(sync.Map{}), func(allocator *Allocator, old, new reflect.Value) {
    76  		if !old.CanAddr() {
    77  			return
    78  		}
    79  
    80  		// Clone all values inside sync.Map.
    81  		oldMap := old.Addr().Interface().(*sync.Map)
    82  		newMap := new.Addr().Interface().(*sync.Map)
    83  		oldMap.Range(func(key, value interface{}) bool {
    84  			k := clone(allocator, key)
    85  			v := clone(allocator, value)
    86  			newMap.Store(k, v)
    87  			return true
    88  		})
    89  	})
    90  	SetCustomFunc(reflect.TypeOf(atomic.Value{}), func(allocator *Allocator, old, new reflect.Value) {
    91  		if !old.CanAddr() {
    92  			return
    93  		}
    94  
    95  		// Clone value inside atomic.Value.
    96  		oldValue := old.Addr().Interface().(*atomic.Value)
    97  		newValue := new.Addr().Interface().(*atomic.Value)
    98  		v := oldValue.Load()
    99  		cloned := clone(allocator, v)
   100  		newValue.Store(cloned)
   101  	})
   102  }
   103  
   104  // MarkAsScalar marks t as a scalar type in heap allocator,
   105  // so that all clone methods will copy t by value.
   106  // If t is not struct or pointer to struct, MarkAsScalar ignores t.
   107  //
   108  // In the most cases, it's not necessary to call it explicitly.
   109  // If a struct type contains scalar type fields only, the struct will be marked as scalar automatically.
   110  //
   111  // Here is a list of types marked as scalar by default:
   112  //   - time.Time
   113  //   - reflect.Value
   114  func markAsScalar(t reflect.Type) {
   115  	defaultAllocator.MarkAsScalar(t)
   116  }
   117  
   118  // MarkAsOpaquePointer marks t as an opaque pointer in heap allocator,
   119  // so that all clone methods will copy t by value.
   120  // If t is not a pointer, MarkAsOpaquePointer ignores t.
   121  //
   122  // Here is a list of types marked as opaque pointers by default:
   123  //   - `elliptic.Curve`, which is `*elliptic.CurveParam` or `elliptic.p256Curve`;
   124  //   - `reflect.Type`, which is `*reflect.rtype` defined in `runtime`.
   125  func markAsOpaquePointer(t reflect.Type) {
   126  	defaultAllocator.MarkAsOpaquePointer(t)
   127  }
   128  
   129  // Func is a custom func to clone value from old to new.
   130  // The new is a zero value
   131  // which `new.CanSet()` and `new.CanAddr()` is guaranteed to be true.
   132  //
   133  // Func must update the new to return result.
   134  type Func func(allocator *Allocator, old, new reflect.Value)
   135  
   136  // emptyCloneFunc is used to disable shadow copy.
   137  // It's useful when cloning sync.Mutex as cloned value must be a zero value.
   138  func emptyCloneFunc(allocator *Allocator, old, new reflect.Value) {}
   139  
   140  // SetCustomFunc sets a custom clone function for type t in heap allocator.
   141  // If t is not struct or pointer to struct, SetCustomFunc ignores t.
   142  //
   143  // If fn is nil, remove the custom clone function for type t.
   144  func setCustomFunc(t reflect.Type, fn Func) {
   145  	defaultAllocator.SetCustomFunc(t, fn)
   146  }
   147  
   148  // Init creates a new value of src.Type() and shadow copies all content from src.
   149  // If noCustomFunc is set to true, custom clone function will be ignored.
   150  //
   151  // Init returns true if the value is cloned by a custom func.
   152  // Caller should skip cloning struct fields in depth.
   153  func (st *structType) Init(allocator *Allocator, src, nv reflect.Value, noCustomFunc bool) (done bool) {
   154  	dst := nv.Elem()
   155  
   156  	if !noCustomFunc && st.fn != nil {
   157  		if !src.CanInterface() {
   158  			src = forceClearROFlag(src)
   159  		}
   160  
   161  		st.fn(allocator, src, dst)
   162  		done = true
   163  		return
   164  	}
   165  
   166  	ptr := unsafe.Pointer(nv.Pointer())
   167  	shadowCopy(src, ptr)
   168  	done = len(st.PointerFields) == 0
   169  	return
   170  }
   171  
   172  func (st *structType) CanShadowCopy() bool {
   173  	return len(st.PointerFields) == 0 && st.fn == nil
   174  }
   175  
   176  // IsScalar returns true if k should be considered as a scalar type.
   177  //
   178  // For the sake of performance, string is considered as a scalar type unless arena is enabled.
   179  // If we need to deep copy string value in some cases, we can create a new allocator with custom isScalar function
   180  // in which we can return false when k is reflect.String.
   181  //
   182  //	// Create a new allocator which treats string as non-scalar type.
   183  //	allocator := NewAllocator(nil, &AllocatorMethods{
   184  //		IsScalar: func(k reflect.Kind) bool {
   185  //			return k != reflect.String && IsScalar(k)
   186  //		},
   187  //	})
   188  func IsScalar(k reflect.Kind) bool {
   189  	switch k {
   190  	case reflect.Bool,
   191  		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
   192  		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
   193  		reflect.Float32, reflect.Float64,
   194  		reflect.Complex64, reflect.Complex128,
   195  		reflect.Func,
   196  		reflect.UnsafePointer,
   197  		reflect.Invalid:
   198  		return true
   199  
   200  	case reflect.String:
   201  		// If arena is not enabled, string can be copied as scalar safely
   202  		// as it's immutable by design.
   203  		return !arenaIsEnabled
   204  	}
   205  
   206  	return false
   207  }
   208  
   209  func copyScalarValue(src reflect.Value) reflect.Value {
   210  	if src.CanInterface() {
   211  		return src
   212  	}
   213  
   214  	// src is an unexported field value. Copy its value.
   215  	switch src.Kind() {
   216  	case reflect.Bool:
   217  		return reflect.ValueOf(src.Bool())
   218  
   219  	case reflect.Int:
   220  		return reflect.ValueOf(int(src.Int()))
   221  	case reflect.Int8:
   222  		return reflect.ValueOf(int8(src.Int()))
   223  	case reflect.Int16:
   224  		return reflect.ValueOf(int16(src.Int()))
   225  	case reflect.Int32:
   226  		return reflect.ValueOf(int32(src.Int()))
   227  	case reflect.Int64:
   228  		return reflect.ValueOf(src.Int())
   229  
   230  	case reflect.Uint:
   231  		return reflect.ValueOf(uint(src.Uint()))
   232  	case reflect.Uint8:
   233  		return reflect.ValueOf(uint8(src.Uint()))
   234  	case reflect.Uint16:
   235  		return reflect.ValueOf(uint16(src.Uint()))
   236  	case reflect.Uint32:
   237  		return reflect.ValueOf(uint32(src.Uint()))
   238  	case reflect.Uint64:
   239  		return reflect.ValueOf(src.Uint())
   240  	case reflect.Uintptr:
   241  		return reflect.ValueOf(uintptr(src.Uint()))
   242  
   243  	case reflect.Float32:
   244  		return reflect.ValueOf(float32(src.Float()))
   245  	case reflect.Float64:
   246  		return reflect.ValueOf(src.Float())
   247  
   248  	case reflect.Complex64:
   249  		return reflect.ValueOf(complex64(src.Complex()))
   250  	case reflect.Complex128:
   251  		return reflect.ValueOf(src.Complex())
   252  
   253  	case reflect.String:
   254  		return reflect.ValueOf(src.String())
   255  	case reflect.Func:
   256  		t := src.Type()
   257  
   258  		if src.IsNil() {
   259  			return reflect.Zero(t)
   260  		}
   261  
   262  		// Don't use this trick unless we have no choice.
   263  		return forceClearROFlag(src)
   264  	case reflect.UnsafePointer:
   265  		return reflect.ValueOf(unsafe.Pointer(src.Pointer()))
   266  	}
   267  
   268  	panic(fmt.Errorf("go-clone: <bug> impossible type `%v` when cloning private field", src.Type()))
   269  }
   270  
   271  var typeOfInterface = reflect.TypeOf((*interface{})(nil)).Elem()
   272  
   273  // forceClearROFlag clears all RO flags in v to make v accessible.
   274  // It's a hack based on the fact that InterfaceData is always available on RO data.
   275  // This hack can be broken in any Go version.
   276  // Don't use it unless we have no choice, e.g. copying func in some edge cases.
   277  func forceClearROFlag(v reflect.Value) reflect.Value {
   278  	var i interface{}
   279  	indirect := 0
   280  
   281  	// Save flagAddr.
   282  	for v.CanAddr() {
   283  		v = v.Addr()
   284  		indirect++
   285  	}
   286  
   287  	v = v.Convert(typeOfInterface)
   288  	nv := reflect.ValueOf(&i)
   289  	*(*interfaceData)(unsafe.Pointer(nv.Pointer())) = parseReflectValue(v)
   290  	cleared := nv.Elem().Elem()
   291  
   292  	for indirect > 0 {
   293  		cleared = cleared.Elem()
   294  		indirect--
   295  	}
   296  
   297  	return cleared
   298  }