aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/vmihailenco/msgpack/types.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/vmihailenco/msgpack/types.go')
-rw-r--r--vendor/github.com/vmihailenco/msgpack/types.go310
1 files changed, 310 insertions, 0 deletions
diff --git a/vendor/github.com/vmihailenco/msgpack/types.go b/vendor/github.com/vmihailenco/msgpack/types.go
new file mode 100644
index 0000000..6a1bf7f
--- /dev/null
+++ b/vendor/github.com/vmihailenco/msgpack/types.go
@@ -0,0 +1,310 @@
1package msgpack
2
3import (
4 "reflect"
5 "sync"
6)
7
8var errorType = reflect.TypeOf((*error)(nil)).Elem()
9
10var customEncoderType = reflect.TypeOf((*CustomEncoder)(nil)).Elem()
11var customDecoderType = reflect.TypeOf((*CustomDecoder)(nil)).Elem()
12
13var marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
14var unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
15
16type encoderFunc func(*Encoder, reflect.Value) error
17type decoderFunc func(*Decoder, reflect.Value) error
18
19var typEncMap = make(map[reflect.Type]encoderFunc)
20var typDecMap = make(map[reflect.Type]decoderFunc)
21
22// Register registers encoder and decoder functions for a value.
23// This is low level API and in most cases you should prefer implementing
24// Marshaler/CustomEncoder and Unmarshaler/CustomDecoder interfaces.
25func Register(value interface{}, enc encoderFunc, dec decoderFunc) {
26 typ := reflect.TypeOf(value)
27 if enc != nil {
28 typEncMap[typ] = enc
29 }
30 if dec != nil {
31 typDecMap[typ] = dec
32 }
33}
34
35//------------------------------------------------------------------------------
36
37var structs = newStructCache(false)
38var jsonStructs = newStructCache(true)
39
40type structCache struct {
41 mu sync.RWMutex
42 m map[reflect.Type]*fields
43
44 useJSONTag bool
45}
46
47func newStructCache(useJSONTag bool) *structCache {
48 return &structCache{
49 m: make(map[reflect.Type]*fields),
50
51 useJSONTag: useJSONTag,
52 }
53}
54
55func (m *structCache) Fields(typ reflect.Type) *fields {
56 m.mu.RLock()
57 fs, ok := m.m[typ]
58 m.mu.RUnlock()
59 if ok {
60 return fs
61 }
62
63 m.mu.Lock()
64 fs, ok = m.m[typ]
65 if !ok {
66 fs = getFields(typ, m.useJSONTag)
67 m.m[typ] = fs
68 }
69 m.mu.Unlock()
70
71 return fs
72}
73
74//------------------------------------------------------------------------------
75
76type field struct {
77 name string
78 index []int
79 omitEmpty bool
80 encoder encoderFunc
81 decoder decoderFunc
82}
83
84func (f *field) value(v reflect.Value) reflect.Value {
85 return fieldByIndex(v, f.index)
86}
87
88func (f *field) Omit(strct reflect.Value) bool {
89 return f.omitEmpty && isEmptyValue(f.value(strct))
90}
91
92func (f *field) EncodeValue(e *Encoder, strct reflect.Value) error {
93 return f.encoder(e, f.value(strct))
94}
95
96func (f *field) DecodeValue(d *Decoder, strct reflect.Value) error {
97 return f.decoder(d, f.value(strct))
98}
99
100//------------------------------------------------------------------------------
101
102type fields struct {
103 Table map[string]*field
104 List []*field
105 AsArray bool
106
107 hasOmitEmpty bool
108}
109
110func newFields(numField int) *fields {
111 return &fields{
112 Table: make(map[string]*field, numField),
113 List: make([]*field, 0, numField),
114 }
115}
116
117func (fs *fields) Add(field *field) {
118 fs.Table[field.name] = field
119 fs.List = append(fs.List, field)
120 if field.omitEmpty {
121 fs.hasOmitEmpty = true
122 }
123}
124
125func (fs *fields) OmitEmpty(strct reflect.Value) []*field {
126 if !fs.hasOmitEmpty {
127 return fs.List
128 }
129
130 fields := make([]*field, 0, len(fs.List))
131 for _, f := range fs.List {
132 if !f.Omit(strct) {
133 fields = append(fields, f)
134 }
135 }
136 return fields
137}
138
139func getFields(typ reflect.Type, useJSONTag bool) *fields {
140 numField := typ.NumField()
141 fs := newFields(numField)
142
143 var omitEmpty bool
144 for i := 0; i < numField; i++ {
145 f := typ.Field(i)
146
147 tag := f.Tag.Get("msgpack")
148 if useJSONTag && tag == "" {
149 tag = f.Tag.Get("json")
150 }
151
152 name, opt := parseTag(tag)
153 if name == "-" {
154 continue
155 }
156
157 if f.Name == "_msgpack" {
158 if opt.Contains("asArray") {
159 fs.AsArray = true
160 }
161 if opt.Contains("omitempty") {
162 omitEmpty = true
163 }
164 }
165
166 if f.PkgPath != "" && !f.Anonymous {
167 continue
168 }
169
170 field := &field{
171 name: name,
172 index: f.Index,
173 omitEmpty: omitEmpty || opt.Contains("omitempty"),
174 encoder: getEncoder(f.Type),
175 decoder: getDecoder(f.Type),
176 }
177
178 if field.name == "" {
179 field.name = f.Name
180 }
181
182 if f.Anonymous && !opt.Contains("noinline") {
183 inline := opt.Contains("inline")
184 if inline {
185 inlineFields(fs, f.Type, field, useJSONTag)
186 } else {
187 inline = autoinlineFields(fs, f.Type, field, useJSONTag)
188 }
189 if inline {
190 fs.Table[field.name] = field
191 continue
192 }
193 }
194
195 fs.Add(field)
196 }
197 return fs
198}
199
200var encodeStructValuePtr uintptr
201var decodeStructValuePtr uintptr
202
203func init() {
204 encodeStructValuePtr = reflect.ValueOf(encodeStructValue).Pointer()
205 decodeStructValuePtr = reflect.ValueOf(decodeStructValue).Pointer()
206}
207
208func inlineFields(fs *fields, typ reflect.Type, f *field, useJSONTag bool) {
209 inlinedFields := getFields(typ, useJSONTag).List
210 for _, field := range inlinedFields {
211 if _, ok := fs.Table[field.name]; ok {
212 // Don't inline shadowed fields.
213 continue
214 }
215 field.index = append(f.index, field.index...)
216 fs.Add(field)
217 }
218}
219
220func autoinlineFields(fs *fields, typ reflect.Type, f *field, useJSONTag bool) bool {
221 var encoder encoderFunc
222 var decoder decoderFunc
223
224 if typ.Kind() == reflect.Struct {
225 encoder = f.encoder
226 decoder = f.decoder
227 } else {
228 for typ.Kind() == reflect.Ptr {
229 typ = typ.Elem()
230 encoder = getEncoder(typ)
231 decoder = getDecoder(typ)
232 }
233 if typ.Kind() != reflect.Struct {
234 return false
235 }
236 }
237
238 if reflect.ValueOf(encoder).Pointer() != encodeStructValuePtr {
239 return false
240 }
241 if reflect.ValueOf(decoder).Pointer() != decodeStructValuePtr {
242 return false
243 }
244
245 inlinedFields := getFields(typ, useJSONTag).List
246 for _, field := range inlinedFields {
247 if _, ok := fs.Table[field.name]; ok {
248 // Don't auto inline if there are shadowed fields.
249 return false
250 }
251 }
252
253 for _, field := range inlinedFields {
254 field.index = append(f.index, field.index...)
255 fs.Add(field)
256 }
257 return true
258}
259
260func isEmptyValue(v reflect.Value) bool {
261 switch v.Kind() {
262 case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
263 return v.Len() == 0
264 case reflect.Bool:
265 return !v.Bool()
266 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
267 return v.Int() == 0
268 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
269 return v.Uint() == 0
270 case reflect.Float32, reflect.Float64:
271 return v.Float() == 0
272 case reflect.Interface, reflect.Ptr:
273 return v.IsNil()
274 }
275 return false
276}
277
278func fieldByIndex(v reflect.Value, index []int) reflect.Value {
279 if len(index) == 1 {
280 return v.Field(index[0])
281 }
282 for i, x := range index {
283 if i > 0 {
284 var ok bool
285 v, ok = indirectNew(v)
286 if !ok {
287 return v
288 }
289 }
290 v = v.Field(x)
291 }
292 return v
293}
294
295func indirectNew(v reflect.Value) (reflect.Value, bool) {
296 if v.Kind() == reflect.Ptr {
297 if v.IsNil() {
298 if !v.CanSet() {
299 return v, false
300 }
301 elemType := v.Type().Elem()
302 if elemType.Kind() != reflect.Struct {
303 return v, false
304 }
305 v.Set(reflect.New(elemType))
306 }
307 v = v.Elem()
308 }
309 return v, true
310}