Passed
Push — master ( 7f55c1...cbd69a )
by Nikita
01:47
created

decode.readValue   F

Complexity

Conditions 15

Size

Total Lines 60
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 15.7823

Importance

Changes 0
Metric Value
cc 15
eloc 43
dl 0
loc 60
c 0
b 0
f 0
ccs 28
cts 33
cp 0.8485
crap 15.7823
rs 2.9998
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like decode.readValue often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
package decode
2
3
import (
4
	"fmt"
5
	"io"
6
7
	"github.com/et-nik/binngo/binn"
8
	"github.com/et-nik/binngo/encode"
9
)
10
11
func readValue(btype binn.Type, reader io.Reader) ([]byte, error) {
12 1
	tp := btype &^ binn.StorageTypeMask
13
14 1
	var readingSize int
15 1
	var containerSize int
16
17 1
	var bytes []byte
18
19 1
	switch tp {
20
	case binn.StorageNoBytes:
21 1
		readingSize = 0
22
	case binn.StorageByte:
23 1
		readingSize = 1
24
	case binn.StorageWord:
25 1
		readingSize = 2
26
	case binn.StorageDWord:
27 1
		readingSize = 4
28
	case binn.StorageQWord:
29 1
		readingSize = 8
30
	case binn.StorageString:
31 1
		dataSize, _, err := readSize(reader)
32 1
		if err != nil {
33
			return nil, fmt.Errorf("failed to read string storage size: %w", err)
34
		}
35 1
		readingSize = dataSize + 1 // data size and null terminator
36
	case binn.StorageBlob:
37 1
		dataSize, _, err := readSize(reader)
38 1
		if err != nil {
39
			return nil, fmt.Errorf("failed to read string storage size: %w", err)
40
		}
41 1
		readingSize = dataSize
42
	case binn.StorageContainer:
43 1
		s, l, err := readSize(reader)
44 1
		if err != nil {
45
			return nil, fmt.Errorf("failed to read storage size: %w", err)
46
		}
47
48 1
		containerSize = s
49
50 1
		bytes = append(bytes, encode.Int(s)...)
51
52 1
		readingSize = containerSize - 1 - int(l) // minus container type byte and size byte
53
	default:
54
		return nil, ErrUnknownType
55
	}
56
57 1
	if readingSize == 0 {
58 1
		return []byte{byte(btype)}, nil
59
	}
60
61 1
	b := make([]byte, readingSize)
62
63 1
	_, err := reader.Read(b)
64 1
	bytes = append(bytes, b...)
65
66 1
	if err != nil {
67
		return nil, fmt.Errorf("failed to read storage: %w", err)
68
	}
69
70 1
	return bytes, nil
71
}
72
73
func readType(reader io.Reader) (binn.Type, readLen, error) {
74 1
	var bt = make([]byte, 1)
75
76 1
	_, err := reader.Read(bt)
77 1
	if err != nil {
78 1
		return binn.Null, 0, ErrFailedToReadType
79
	}
80
81 1
	return Type(bt), 1, nil
82
}
83
84
func readSize(reader io.Reader) (int, readLen, error) {
85 1
	var bsz = make([]byte, 1)
86 1
	_, err := reader.Read(bsz)
87 1
	if err != nil {
88
		return 0, 0, ErrFailedToReadSize
89
	}
90
91 1
	read := 1
92
93 1
	sz := int(Uint8(bsz))
94
95 1
	if sz > maxOneByteSize {
96
		var bszOtherBytes = make([]byte, 3)
97
		_, err := reader.Read(bszOtherBytes)
98
		if err != nil {
99
			return 0, 0, fmt.Errorf("failed to read long size: %w", err)
100
		}
101
		read += 3
102
		sz ^= 0x80000000
103
104
		sz = int(Uint32([]byte{
105
			byte(sz),
106
			bszOtherBytes[0],
107
			bszOtherBytes[1],
108
			bszOtherBytes[2],
109
		}))
110
	}
111
112 1
	return sz, readLen(read), nil
113
}
114