1package reflect2 2 3import ( 4 "github.com/modern-go/concurrent" 5 "reflect" 6 "unsafe" 7) 8 9type 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 36type 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 45type ArrayType interface { 46 ListType 47 Len() int 48} 49 50type 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 66type 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 75type 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 89type 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 104type MapIterator interface { 105 HasNext() bool 106 Next() (key interface{}, elem interface{}) 107 UnsafeNext() (key unsafe.Pointer, elem unsafe.Pointer) 108} 109 110type PtrType interface { 111 Type 112 Elem() Type 113} 114 115type InterfaceType interface { 116 NumMethod() int 117} 118 119type Config struct { 120 UseSafeImplementation bool 121} 122 123type API interface { 124 TypeOf(obj interface{}) Type 125 Type2(type1 reflect.Type) Type 126} 127 128var ConfigUnsafe = Config{UseSafeImplementation: false}.Froze() 129var ConfigSafe = Config{UseSafeImplementation: true}.Froze() 130 131type frozenConfig struct { 132 useSafeImplementation bool 133 cache *concurrent.Map 134} 135 136func (cfg Config) Froze() *frozenConfig { 137 return &frozenConfig{ 138 useSafeImplementation: cfg.UseSafeImplementation, 139 cache: concurrent.NewMap(), 140 } 141} 142 143func (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 152func (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 166func (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 210func TypeOf(obj interface{}) Type { 211 return ConfigUnsafe.TypeOf(obj) 212} 213 214func TypeOfPtr(obj interface{}) PtrType { 215 return TypeOf(obj).(PtrType) 216} 217 218func Type2(type1 reflect.Type) Type { 219 if type1 == nil { 220 return nil 221 } 222 return ConfigUnsafe.Type2(type1) 223} 224 225func PtrTo(typ Type) Type { 226 return Type2(reflect.PtrTo(typ.Type1())) 227} 228 229func PtrOf(obj interface{}) unsafe.Pointer { 230 return unpackEFace(obj).data 231} 232 233func RTypeOf(obj interface{}) uintptr { 234 return uintptr(unpackEFace(obj).rtype) 235} 236 237func IsNil(obj interface{}) bool { 238 if obj == nil { 239 return true 240 } 241 return unpackEFace(obj).data == nil 242} 243 244func 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 252func 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 260func 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 285func NoEscape(p unsafe.Pointer) unsafe.Pointer { 286 x := uintptr(p) 287 return unsafe.Pointer(x ^ 0) 288} 289 290func 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} 299