Passed
Push — master ( e0dc57...7f55c1 )
by Nikita
01:39
created

decode.convertToType   A

Complexity

Conditions 4

Size

Total Lines 8
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 6

Importance

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