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 }