blob: 63b49c799194729a141e9e03029d8b86b58171f9 [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001package 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}