Passed
Push — master ( fd8660...f4d29e )
by Nikita
01:40
created

decode.decodeUnmarshalerStorage   A

Complexity

Conditions 4

Size

Total Lines 21
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4.128

Importance

Changes 0
Metric Value
cc 4
eloc 16
dl 0
loc 21
ccs 12
cts 15
cp 0.8
crap 4.128
rs 9.6
c 0
b 0
f 0
nop 3
1
package decode
2
3
import (
4
	"bytes"
5
	"io"
6
	"reflect"
7
	"sync"
8
9
	"github.com/cstockton/go-conv"
10
	"github.com/et-nik/binngo/binn"
11
	"github.com/et-nik/binngo/encode"
12
)
13
14
const (
15
	maxOneByteSize = 127
16
)
17
18
type decodeFunc func(reader io.Reader, v interface{}) error
19
20
var decoderCache sync.Map // map[binn.Type]decodeFunc
21
22
type readLen int
23
24
func decode(reader io.Reader, v interface{}) error {
25 1
	rv := reflect.ValueOf(v)
26 1
	rt := reflect.TypeOf(v)
27 1
	if rv.Kind() != reflect.Ptr || rv.IsNil() {
28
		return &InvalidUnmarshalError{rt}
29
	}
30
31 1
	containerType, _, err := readType(reader)
32 1
	if err != nil {
33
		return err
34
	}
35
36 1
	if rt.Implements(unmarshalerType) && isStorageContainer(containerType) {
37 1
		return decodeUnmarshalerStorage(containerType, reader, v)
38
	}
39
40 1
	return decodeStorage(containerType, reader, v)
41
}
42
43
func decodeUnmarshalerStorage(containerType binn.Type, reader io.Reader, v interface{}) error {
44 1
	size, _, err := readSize(reader)
45 1
	if err != nil {
46
		return err
47
	}
48 1
	buf := make([]byte, size)
49 1
	_, err = reader.Read(buf)
50 1
	if err != nil {
51
		return err
52
	}
53 1
	var data []byte
54 1
	data = append(data, encode.Uint8(uint8(containerType))...)
55 1
	data = append(data, encode.Size(size, true)...)
56 1
	data = append(data, buf...)
57
58 1
	err = decodeUnmarshaler(data, v)
59 1
	if err != nil {
60
		return err
61
	}
62
63 1
	return nil
64
}
65
66
func decodeStorage(containerType binn.Type, reader io.Reader, v interface{}) error {
67 1
	decoder := loadDecodeFunc(containerType)
68 1
	return decoder(reader, v)
69
}
70
71
func decodeItem(rt reflect.Type, btype binn.Type, bval []byte) (interface{}, error) {
72 1
	var v interface{}
73 1
	var err error
74
75 1
	switch btype {
76
	case binn.Null:
77
		return nil, nil
78
	case binn.True:
79 1
		return true, nil
80
	case binn.False:
81 1
		return false, nil
82
	case binn.Uint8Type:
83 1
		v = Uint8(bval)
84
	case binn.Uint16Type:
85 1
		v = Uint16(bval)
86
	case binn.Uint32Type:
87 1
		v = Uint32(bval)
88
	case binn.Uint64Type:
89 1
		v = Uint64(bval)
90
	case binn.Int8Type:
91 1
		v = Int8(bval)
92
	case binn.Int16Type:
93 1
		v = Int16(bval)
94
	case binn.Int32Type:
95 1
		v = Int32(bval)
96
	case binn.Int64Type:
97 1
		v = Int64(bval)
98
	case binn.Float32Type:
99 1
		v = Float32(bval)
100
	case binn.Float64Type:
101 1
		v = Float64(bval)
102
	case binn.StringType:
103 1
		v = String(bval[:len(bval)-1])
104
	case binn.BlobType:
105 1
		v = bval
106
	case binn.ListType:
107 1
		var l []interface{}
108 1
		br := bytes.NewReader(bval)
109 1
		_, wasReadLen, _ := readSize(br)
110 1
		cnt, wasReadCnt, _ := readSize(br)
111 1
		wasRead := wasReadLen + wasReadCnt
112
113 1
		err = decodeListItems(br, &l, len(bval)-int(wasRead), wasRead, cnt)
114 1
		if err != nil {
115
			return nil, err
116
		}
117
118 1
		return l, nil
119
	case binn.MapType:
120 1
		br := bytes.NewReader(bval)
121 1
		sz, rlsize, _ := readSize(br)
122 1
		cnt, rlcnt, _ := readSize(br)
123
124 1
		mapType := reflect.MapOf(reflect.TypeOf(int(0)), rt.Elem())
125 1
		ptr := reflect.New(mapType)
126 1
		ptr.Elem().Set(reflect.MakeMap(mapType))
127 1
		m := ptr.Interface()
128
129 1
		err = decodeMapItems(br, m, sz, rlsize+rlcnt, cnt)
130 1
		if err != nil {
131
			return nil, err
132
		}
133
134 1
		return reflect.ValueOf(m).Elem().Interface(), nil
135
	case binn.ObjectType:
136 1
		var obj interface{}
137 1
		if rt.Kind() == reflect.Interface {
138
			obj = map[string]interface{}{}
139
		} else {
140 1
			ptr := reflect.New(rt)
141 1
			obj = ptr.Interface()
142
		}
143
144 1
		br := bytes.NewReader(bval)
145
146 1
		err = decodeStorage(btype, br, &obj)
147
148 1
		if err != nil {
149
			return nil, err
150
		}
151
152 1
		return obj, nil
153
	}
154
155 1
	if rt.Kind() == reflect.Interface {
156 1
		v, err = convertToKind(kindMapper[btype], v)
157 1
		if err != nil {
158
			return nil, err
159
		}
160
	} else {
161 1
		v, err = convertToType(rt, v)
162 1
		if err != nil {
163
			return nil, err
164
		}
165
	}
166
167 1
	return v, nil
168
}
169
170
func loadDecodeFunc(bt binn.Type) decodeFunc {
171 1
	if fi, ok := decoderCache.Load(bt); ok {
172 1
		return fi.(decodeFunc)
173
	}
174
175 1
	var (
176
		wg sync.WaitGroup
177
		f  decodeFunc
178
	)
179 1
	wg.Add(1)
180 1
	fi, loaded := decoderCache.LoadOrStore(bt, decodeFunc(func(reader io.Reader, v interface{}) error {
181
		wg.Wait()
182
		return f(reader, v)
183
	}))
184 1
	if loaded {
185
		return fi.(decodeFunc)
186
	}
187
188 1
	f = newTypeDecoder(bt)
189 1
	wg.Done()
190 1
	decoderCache.Store(bt, f)
191 1
	return f
192
}
193
194
func newTypeDecoder(bt binn.Type) decodeFunc {
195 1
	switch bt {
196
	case binn.ListType:
197 1
		return decodeList
198
	case binn.MapType:
199 1
		return decodeMap
200
	case binn.ObjectType:
201 1
		return decodeObject
202
	case binn.Null:
203 1
		return func(_ io.Reader, _ interface{}) error {
204 1
			return nil
205
		}
206
	}
207
208 1
	decoder := newValueDecoder(bt)
209 1
	return decoder.DecodeValue
210
}
211
212
func convertToType(rt reflect.Type, val interface{}) (interface{}, error) {
213 1
	switch rt.Kind() {
214
	case reflect.Interface:
215
		return val, nil
216
	case reflect.Ptr:
217
		return convertToType(rt.Elem(), val)
218
	default:
219 1
		return convertToKind(rt.Kind(), val)
220
	}
221
}
222
223
func convertToKind(rk reflect.Kind, v interface{}) (interface{}, error) {
224 1
	switch rk {
225
	case reflect.Int:
226 1
		return conv.Int(v)
227
	case reflect.Int8:
228 1
		return conv.Int8(v)
229
	case reflect.Int16:
230 1
		return conv.Int16(v)
231
	case reflect.Int32:
232 1
		return conv.Int32(v)
233
	case reflect.Int64:
234 1
		return conv.Int64(v)
235
	case reflect.Uint:
236
		return conv.Uint(v)
237
	case reflect.Uint8:
238 1
		return conv.Uint8(v)
239
	case reflect.Uint16:
240 1
		return conv.Uint16(v)
241
	case reflect.Uint32:
242 1
		return conv.Int32(v)
243
	case reflect.Uint64:
244
		return conv.Uint64(v)
245
	case reflect.Bool:
246
		return conv.Bool(v)
247
	case reflect.String:
248 1
		return conv.String(v)
249
	}
250
251 1
	return v, nil
252
}
253