github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/reflectkit/reflect_accessor.go (about)

     1  // Copyright 2020 Insolar Network Ltd.
     2  // All rights reserved.
     3  // This material is licensed under the Insolar License version 1.0,
     4  // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md.
     5  
     6  package reflectkit
     7  
     8  import (
     9  	"reflect"
    10  	"unsafe"
    11  )
    12  
    13  //go:generate minimock -i github.com/insolar/vanilla/reflectkit.TypedReceiver -o ./mocks -s _mock.go -g
    14  type TypedReceiver interface {
    15  	ReceiveBool(reflect.Kind, bool)
    16  	ReceiveInt(reflect.Kind, int64)
    17  	ReceiveUint(reflect.Kind, uint64)
    18  	ReceiveFloat(reflect.Kind, float64)
    19  	ReceiveComplex(reflect.Kind, complex128)
    20  	ReceiveString(reflect.Kind, string)
    21  	ReceiveZero(reflect.Kind)
    22  	ReceiveNil(reflect.Kind)
    23  	ReceiveIface(reflect.Kind, interface{})
    24  	ReceiveElse(t reflect.Kind, v interface{}, isZero bool)
    25  }
    26  
    27  type FieldGetterFunc func(reflect.Value) reflect.Value
    28  type ValueToReceiverFunc func(value reflect.Value, out TypedReceiver)
    29  type IfaceToReceiverFunc func(value interface{}, k reflect.Kind, out TypedReceiver)
    30  type IfaceToReceiverFactoryFunc func(t reflect.Type, checkZero bool) IfaceToReceiverFunc
    31  type ValueToReceiverFactoryFunc func(unexported bool, t reflect.Type, checkZero bool) (bool, ValueToReceiverFunc)
    32  
    33  func ValueToReceiverFactory(k reflect.Kind, custom IfaceToReceiverFactoryFunc) ValueToReceiverFactoryFunc {
    34  	switch k {
    35  	// ======== Simple values, are safe to read from unexported fields ============
    36  	case reflect.Bool:
    37  		return func(_ bool, _ reflect.Type, checkZero bool) (bool, ValueToReceiverFunc) {
    38  			return false, func(value reflect.Value, outFn TypedReceiver) {
    39  				v := value.Bool()
    40  				if !checkZero || v {
    41  					outFn.ReceiveBool(value.Kind(), v)
    42  				} else {
    43  					outFn.ReceiveZero(value.Kind())
    44  				}
    45  			}
    46  		}
    47  
    48  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    49  		return func(_ bool, _ reflect.Type, checkZero bool) (bool, ValueToReceiverFunc) {
    50  			return false, func(value reflect.Value, outFn TypedReceiver) {
    51  				v := value.Int()
    52  				if !checkZero || v != 0 {
    53  					outFn.ReceiveInt(value.Kind(), v)
    54  				} else {
    55  					outFn.ReceiveZero(value.Kind())
    56  				}
    57  			}
    58  		}
    59  
    60  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
    61  		return func(_ bool, _ reflect.Type, checkZero bool) (bool, ValueToReceiverFunc) {
    62  			return false, func(value reflect.Value, outFn TypedReceiver) {
    63  				v := value.Uint()
    64  				if !checkZero || v != 0 {
    65  					outFn.ReceiveUint(value.Kind(), v)
    66  				} else {
    67  					outFn.ReceiveZero(value.Kind())
    68  				}
    69  			}
    70  		}
    71  
    72  	case reflect.Float32, reflect.Float64:
    73  		return func(_ bool, _ reflect.Type, checkZero bool) (bool, ValueToReceiverFunc) {
    74  			return false, func(value reflect.Value, outFn TypedReceiver) {
    75  				v := value.Float()
    76  				if !checkZero || v != 0 {
    77  					outFn.ReceiveFloat(value.Kind(), v)
    78  				} else {
    79  					outFn.ReceiveZero(value.Kind())
    80  				}
    81  			}
    82  		}
    83  
    84  	case reflect.Complex64, reflect.Complex128:
    85  		return func(_ bool, _ reflect.Type, checkZero bool) (bool, ValueToReceiverFunc) {
    86  			return false, func(value reflect.Value, outFn TypedReceiver) {
    87  				v := value.Complex()
    88  				if !checkZero || v != 0 {
    89  					outFn.ReceiveComplex(value.Kind(), v)
    90  				} else {
    91  					outFn.ReceiveZero(value.Kind())
    92  				}
    93  			}
    94  		}
    95  
    96  	case reflect.String:
    97  		return func(_ bool, _ reflect.Type, checkZero bool) (bool, ValueToReceiverFunc) {
    98  			return false, func(value reflect.Value, outFn TypedReceiver) {
    99  				v := value.String()
   100  				if !checkZero || v != "" {
   101  					outFn.ReceiveString(value.Kind(), v)
   102  				} else {
   103  					outFn.ReceiveZero(value.Kind())
   104  				}
   105  			}
   106  		}
   107  
   108  	// ============ Types that require special handling for unexported fields ===========
   109  
   110  	// nillable types fully defined at compile time
   111  	case reflect.Func, reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan: //, reflect.UnsafePointer:
   112  		return func(unexported bool, t reflect.Type, checkZero bool) (bool, ValueToReceiverFunc) {
   113  			if custom != nil {
   114  				if fn := custom(t, checkZero); fn != nil {
   115  					return unexported, func(value reflect.Value, outFn TypedReceiver) {
   116  						if value.IsNil() {
   117  							outFn.ReceiveNil(k)
   118  						} else {
   119  							fn(value.Interface(), value.Kind(), outFn)
   120  						}
   121  					}
   122  				}
   123  			}
   124  			return unexported, func(value reflect.Value, outFn TypedReceiver) {
   125  				if value.IsNil() { // avoids interface nil
   126  					outFn.ReceiveNil(k)
   127  				} else {
   128  					outFn.ReceiveElse(value.Kind(), value.Interface(), false)
   129  				}
   130  			}
   131  		}
   132  
   133  	// nillable types fully undefined at compile time
   134  	case reflect.Interface:
   135  		return func(unexported bool, t reflect.Type, checkZero bool) (b bool, getterFunc ValueToReceiverFunc) {
   136  			if custom != nil {
   137  				if fn := custom(t, checkZero); fn != nil {
   138  					return unexported, func(value reflect.Value, outFn TypedReceiver) {
   139  						v := value.Interface()
   140  						fn(v, value.Elem().Kind(), outFn)
   141  					}
   142  				}
   143  			}
   144  
   145  			return unexported, func(value reflect.Value, outFn TypedReceiver) {
   146  				if value.IsNil() {
   147  					outFn.ReceiveNil(value.Kind())
   148  				} else {
   149  					v := value.Interface()
   150  					outFn.ReceiveElse(value.Kind(), v, false)
   151  				}
   152  			}
   153  		}
   154  
   155  	// non-nillable
   156  	case reflect.Struct, reflect.Array:
   157  		return func(unexported bool, t reflect.Type, checkZero bool) (b bool, getterFunc ValueToReceiverFunc) {
   158  			valueFn := custom(t, checkZero)
   159  			if checkZero {
   160  				zeroValue := reflect.Zero(t).Interface()
   161  				return unexported, func(value reflect.Value, outFn TypedReceiver) {
   162  					if v := value.Interface(); valueFn == nil {
   163  						outFn.ReceiveElse(value.Kind(), v, v == zeroValue)
   164  					} else {
   165  						valueFn(v, value.Kind(), outFn)
   166  					}
   167  				}
   168  			}
   169  			return unexported, func(value reflect.Value, outFn TypedReceiver) {
   170  				if v := value.Interface(); valueFn == nil {
   171  					outFn.ReceiveElse(value.Kind(), v, false)
   172  				} else {
   173  					valueFn(v, value.Kind(), outFn)
   174  				}
   175  			}
   176  		}
   177  
   178  	// ============ Excluded ===================
   179  	// reflect.UnsafePointer
   180  	default:
   181  		return nil
   182  	}
   183  }
   184  
   185  func MakeAddressable(value reflect.Value) reflect.Value {
   186  	if value.CanAddr() {
   187  		return value
   188  	}
   189  	valueCopy := reflect.New(value.Type()).Elem()
   190  	valueCopy.Set(value)
   191  	return valueCopy
   192  }
   193  
   194  func FieldValueGetter(index int, fd reflect.StructField, useAddr bool, baseOffset uintptr) FieldGetterFunc {
   195  	if !useAddr {
   196  		return func(value reflect.Value) reflect.Value {
   197  			return value.Field(index)
   198  		}
   199  	}
   200  
   201  	fieldOffset := fd.Offset + baseOffset
   202  	fieldType := fd.Type
   203  
   204  	return func(value reflect.Value) reflect.Value {
   205  		return offsetFieldGetter(value, fieldOffset, fieldType)
   206  	}
   207  }
   208  
   209  func offsetFieldGetter(v reflect.Value, fieldOffset uintptr, fieldType reflect.Type) reflect.Value {
   210  	// base has to be here as a separate variable because of new checkptr check in go 1.14
   211  	// By default it is enabled when -race flag is present.
   212  	// It checks the following: If the result of pointer arithmetic points into
   213  	// a Go heap object, one of the unsafe.Pointer-typed operands must point
   214  	// into the same object.
   215  	// See go release notes for details: https://golang.org/doc/go1.14#compiler
   216  	base := unsafe.Pointer(v.UnsafeAddr())
   217  	return reflect.NewAt(fieldType, unsafe.Pointer(uintptr(base)+fieldOffset)).Elem()
   218  }