Scott Baker | e7144bc | 2019-10-01 14:16:47 -0700 | [diff] [blame] | 1 | package reflect2 |
| 2 | |
| 3 | import ( |
| 4 | "github.com/modern-go/concurrent" |
| 5 | "reflect" |
| 6 | "unsafe" |
| 7 | ) |
| 8 | |
| 9 | type Type interface { |
| 10 | Kind() reflect.Kind |
| 11 | // New return pointer to data of this type |
| 12 | New() interface{} |
| 13 | // UnsafeNew return the allocated space pointed by unsafe.Pointer |
| 14 | UnsafeNew() unsafe.Pointer |
| 15 | // PackEFace cast a unsafe pointer to object represented pointer |
| 16 | PackEFace(ptr unsafe.Pointer) interface{} |
| 17 | // Indirect dereference object represented pointer to this type |
| 18 | Indirect(obj interface{}) interface{} |
| 19 | // UnsafeIndirect dereference pointer to this type |
| 20 | UnsafeIndirect(ptr unsafe.Pointer) interface{} |
| 21 | // Type1 returns reflect.Type |
| 22 | Type1() reflect.Type |
| 23 | Implements(thatType Type) bool |
| 24 | String() string |
| 25 | RType() uintptr |
| 26 | // interface{} of this type has pointer like behavior |
| 27 | LikePtr() bool |
| 28 | IsNullable() bool |
| 29 | IsNil(obj interface{}) bool |
| 30 | UnsafeIsNil(ptr unsafe.Pointer) bool |
| 31 | Set(obj interface{}, val interface{}) |
| 32 | UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) |
| 33 | AssignableTo(anotherType Type) bool |
| 34 | } |
| 35 | |
| 36 | type ListType interface { |
| 37 | Type |
| 38 | Elem() Type |
| 39 | SetIndex(obj interface{}, index int, elem interface{}) |
| 40 | UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer) |
| 41 | GetIndex(obj interface{}, index int) interface{} |
| 42 | UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer |
| 43 | } |
| 44 | |
| 45 | type ArrayType interface { |
| 46 | ListType |
| 47 | Len() int |
| 48 | } |
| 49 | |
| 50 | type SliceType interface { |
| 51 | ListType |
| 52 | MakeSlice(length int, cap int) interface{} |
| 53 | UnsafeMakeSlice(length int, cap int) unsafe.Pointer |
| 54 | Grow(obj interface{}, newLength int) |
| 55 | UnsafeGrow(ptr unsafe.Pointer, newLength int) |
| 56 | Append(obj interface{}, elem interface{}) |
| 57 | UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer) |
| 58 | LengthOf(obj interface{}) int |
| 59 | UnsafeLengthOf(ptr unsafe.Pointer) int |
| 60 | SetNil(obj interface{}) |
| 61 | UnsafeSetNil(ptr unsafe.Pointer) |
| 62 | Cap(obj interface{}) int |
| 63 | UnsafeCap(ptr unsafe.Pointer) int |
| 64 | } |
| 65 | |
| 66 | type StructType interface { |
| 67 | Type |
| 68 | NumField() int |
| 69 | Field(i int) StructField |
| 70 | FieldByName(name string) StructField |
| 71 | FieldByIndex(index []int) StructField |
| 72 | FieldByNameFunc(match func(string) bool) StructField |
| 73 | } |
| 74 | |
| 75 | type StructField interface { |
| 76 | Offset() uintptr |
| 77 | Name() string |
| 78 | PkgPath() string |
| 79 | Type() Type |
| 80 | Tag() reflect.StructTag |
| 81 | Index() []int |
| 82 | Anonymous() bool |
| 83 | Set(obj interface{}, value interface{}) |
| 84 | UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer) |
| 85 | Get(obj interface{}) interface{} |
| 86 | UnsafeGet(obj unsafe.Pointer) unsafe.Pointer |
| 87 | } |
| 88 | |
| 89 | type MapType interface { |
| 90 | Type |
| 91 | Key() Type |
| 92 | Elem() Type |
| 93 | MakeMap(cap int) interface{} |
| 94 | UnsafeMakeMap(cap int) unsafe.Pointer |
| 95 | SetIndex(obj interface{}, key interface{}, elem interface{}) |
| 96 | UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer) |
| 97 | TryGetIndex(obj interface{}, key interface{}) (interface{}, bool) |
| 98 | GetIndex(obj interface{}, key interface{}) interface{} |
| 99 | UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer |
| 100 | Iterate(obj interface{}) MapIterator |
| 101 | UnsafeIterate(obj unsafe.Pointer) MapIterator |
| 102 | } |
| 103 | |
| 104 | type MapIterator interface { |
| 105 | HasNext() bool |
| 106 | Next() (key interface{}, elem interface{}) |
| 107 | UnsafeNext() (key unsafe.Pointer, elem unsafe.Pointer) |
| 108 | } |
| 109 | |
| 110 | type PtrType interface { |
| 111 | Type |
| 112 | Elem() Type |
| 113 | } |
| 114 | |
| 115 | type InterfaceType interface { |
| 116 | NumMethod() int |
| 117 | } |
| 118 | |
| 119 | type Config struct { |
| 120 | UseSafeImplementation bool |
| 121 | } |
| 122 | |
| 123 | type API interface { |
| 124 | TypeOf(obj interface{}) Type |
| 125 | Type2(type1 reflect.Type) Type |
| 126 | } |
| 127 | |
| 128 | var ConfigUnsafe = Config{UseSafeImplementation: false}.Froze() |
| 129 | var ConfigSafe = Config{UseSafeImplementation: true}.Froze() |
| 130 | |
| 131 | type frozenConfig struct { |
| 132 | useSafeImplementation bool |
| 133 | cache *concurrent.Map |
| 134 | } |
| 135 | |
| 136 | func (cfg Config) Froze() *frozenConfig { |
| 137 | return &frozenConfig{ |
| 138 | useSafeImplementation: cfg.UseSafeImplementation, |
| 139 | cache: concurrent.NewMap(), |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | func (cfg *frozenConfig) TypeOf(obj interface{}) Type { |
| 144 | cacheKey := uintptr(unpackEFace(obj).rtype) |
| 145 | typeObj, found := cfg.cache.Load(cacheKey) |
| 146 | if found { |
| 147 | return typeObj.(Type) |
| 148 | } |
| 149 | return cfg.Type2(reflect.TypeOf(obj)) |
| 150 | } |
| 151 | |
| 152 | func (cfg *frozenConfig) Type2(type1 reflect.Type) Type { |
| 153 | if type1 == nil { |
| 154 | return nil |
| 155 | } |
| 156 | cacheKey := uintptr(unpackEFace(type1).data) |
| 157 | typeObj, found := cfg.cache.Load(cacheKey) |
| 158 | if found { |
| 159 | return typeObj.(Type) |
| 160 | } |
| 161 | type2 := cfg.wrapType(type1) |
| 162 | cfg.cache.Store(cacheKey, type2) |
| 163 | return type2 |
| 164 | } |
| 165 | |
| 166 | func (cfg *frozenConfig) wrapType(type1 reflect.Type) Type { |
| 167 | safeType := safeType{Type: type1, cfg: cfg} |
| 168 | switch type1.Kind() { |
| 169 | case reflect.Struct: |
| 170 | if cfg.useSafeImplementation { |
| 171 | return &safeStructType{safeType} |
| 172 | } |
| 173 | return newUnsafeStructType(cfg, type1) |
| 174 | case reflect.Array: |
| 175 | if cfg.useSafeImplementation { |
| 176 | return &safeSliceType{safeType} |
| 177 | } |
| 178 | return newUnsafeArrayType(cfg, type1) |
| 179 | case reflect.Slice: |
| 180 | if cfg.useSafeImplementation { |
| 181 | return &safeSliceType{safeType} |
| 182 | } |
| 183 | return newUnsafeSliceType(cfg, type1) |
| 184 | case reflect.Map: |
| 185 | if cfg.useSafeImplementation { |
| 186 | return &safeMapType{safeType} |
| 187 | } |
| 188 | return newUnsafeMapType(cfg, type1) |
| 189 | case reflect.Ptr, reflect.Chan, reflect.Func: |
| 190 | if cfg.useSafeImplementation { |
| 191 | return &safeMapType{safeType} |
| 192 | } |
| 193 | return newUnsafePtrType(cfg, type1) |
| 194 | case reflect.Interface: |
| 195 | if cfg.useSafeImplementation { |
| 196 | return &safeMapType{safeType} |
| 197 | } |
| 198 | if type1.NumMethod() == 0 { |
| 199 | return newUnsafeEFaceType(cfg, type1) |
| 200 | } |
| 201 | return newUnsafeIFaceType(cfg, type1) |
| 202 | default: |
| 203 | if cfg.useSafeImplementation { |
| 204 | return &safeType |
| 205 | } |
| 206 | return newUnsafeType(cfg, type1) |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | func TypeOf(obj interface{}) Type { |
| 211 | return ConfigUnsafe.TypeOf(obj) |
| 212 | } |
| 213 | |
| 214 | func TypeOfPtr(obj interface{}) PtrType { |
| 215 | return TypeOf(obj).(PtrType) |
| 216 | } |
| 217 | |
| 218 | func Type2(type1 reflect.Type) Type { |
| 219 | if type1 == nil { |
| 220 | return nil |
| 221 | } |
| 222 | return ConfigUnsafe.Type2(type1) |
| 223 | } |
| 224 | |
| 225 | func PtrTo(typ Type) Type { |
| 226 | return Type2(reflect.PtrTo(typ.Type1())) |
| 227 | } |
| 228 | |
| 229 | func PtrOf(obj interface{}) unsafe.Pointer { |
| 230 | return unpackEFace(obj).data |
| 231 | } |
| 232 | |
| 233 | func RTypeOf(obj interface{}) uintptr { |
| 234 | return uintptr(unpackEFace(obj).rtype) |
| 235 | } |
| 236 | |
| 237 | func IsNil(obj interface{}) bool { |
| 238 | if obj == nil { |
| 239 | return true |
| 240 | } |
| 241 | return unpackEFace(obj).data == nil |
| 242 | } |
| 243 | |
| 244 | func IsNullable(kind reflect.Kind) bool { |
| 245 | switch kind { |
| 246 | case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func, reflect.Slice, reflect.Interface: |
| 247 | return true |
| 248 | } |
| 249 | return false |
| 250 | } |
| 251 | |
| 252 | func likePtrKind(kind reflect.Kind) bool { |
| 253 | switch kind { |
| 254 | case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func: |
| 255 | return true |
| 256 | } |
| 257 | return false |
| 258 | } |
| 259 | |
| 260 | func likePtrType(typ reflect.Type) bool { |
| 261 | if likePtrKind(typ.Kind()) { |
| 262 | return true |
| 263 | } |
| 264 | if typ.Kind() == reflect.Struct { |
| 265 | if typ.NumField() != 1 { |
| 266 | return false |
| 267 | } |
| 268 | return likePtrType(typ.Field(0).Type) |
| 269 | } |
| 270 | if typ.Kind() == reflect.Array { |
| 271 | if typ.Len() != 1 { |
| 272 | return false |
| 273 | } |
| 274 | return likePtrType(typ.Elem()) |
| 275 | } |
| 276 | return false |
| 277 | } |
| 278 | |
| 279 | // NoEscape hides a pointer from escape analysis. noescape is |
| 280 | // the identity function but escape analysis doesn't think the |
| 281 | // output depends on the input. noescape is inlined and currently |
| 282 | // compiles down to zero instructions. |
| 283 | // USE CAREFULLY! |
| 284 | //go:nosplit |
| 285 | func NoEscape(p unsafe.Pointer) unsafe.Pointer { |
| 286 | x := uintptr(p) |
| 287 | return unsafe.Pointer(x ^ 0) |
| 288 | } |
| 289 | |
| 290 | func UnsafeCastString(str string) []byte { |
| 291 | stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&str)) |
| 292 | sliceHeader := &reflect.SliceHeader{ |
| 293 | Data: stringHeader.Data, |
| 294 | Cap: stringHeader.Len, |
| 295 | Len: stringHeader.Len, |
| 296 | } |
| 297 | return *(*[]byte)(unsafe.Pointer(sliceHeader)) |
| 298 | } |