decode.readValue   F
last analyzed

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