encode.newTypeEncoder   F
last analyzed

Complexity

Conditions 24

Size

Total Lines 82
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 111.3649

Importance

Changes 0
Metric Value
cc 24
eloc 57
dl 0
loc 82
ccs 21
cts 45
cp 0.4667
crap 111.3649
rs 0
c 0
b 0
f 0
nop 1

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 encode.newTypeEncoder 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 encode
2
3
import (
4
	"encoding"
5
	"reflect"
6
	"sync"
7
8
	"github.com/et-nik/binngo/binn"
9
)
10
11
type encoderFunc func(v reflect.Value) ([]byte, error)
12
13
var encoderCache sync.Map // map[reflect.Type]encoderFunc
14
15
var (
16
	marshalerType     = reflect.TypeOf((*Marshaler)(nil)).Elem()
17
	textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
18
)
19
20
type Marshaler interface {
21
	MarshalBINN() ([]byte, error)
22
}
23
24
func marshal(v interface{}) ([]byte, error) {
25 1
	rv := reflect.ValueOf(v)
26
27 1
	if !rv.IsValid() {
28
		return nil, ErrInvalidValue
29
	}
30
31 1
	if !rv.IsValid() {
32
		return nil, ErrInvalidValue
33
	}
34
35 1
	enc := loadEncodeFunc(rv.Type())
36
37 1
	return enc(rv)
38
}
39
40
func loadEncodeFunc(t reflect.Type) encoderFunc {
41 1
	if fi, ok := encoderCache.Load(t); ok {
42 1
		return fi.(encoderFunc)
43
	}
44
45 1
	var (
46
		wg sync.WaitGroup
47
		f  encoderFunc
48
	)
49 1
	wg.Add(1)
50 1
	fi, loaded := encoderCache.LoadOrStore(t, encoderFunc(func(v reflect.Value) ([]byte, error) {
51
		wg.Wait()
52
		return f(v)
53
	}))
54 1
	if loaded {
55
		return fi.(encoderFunc)
56
	}
57
58 1
	f = newTypeEncoder(t)
59 1
	wg.Done()
60 1
	encoderCache.Store(t, f)
61 1
	return f
62
}
63
64
//nolint:funlen
65
func newTypeEncoder(t reflect.Type) encoderFunc {
66 1
	if t.Implements(marshalerType) {
67 1
		return marshalerEncoder
68
	}
69 1
	if t.Implements(textMarshalerType) {
70
		return textMarshalerEncoder
71
	}
72
73 1
	switch t.Kind() {
74
	case reflect.Bool:
75
		return func(v reflect.Value) ([]byte, error) {
76
			if v.Bool() {
77
				return []byte{binn.True}, nil
78
			}
79
			return []byte{binn.False}, nil
80
		}
81
	case reflect.Struct:
82 1
		return newStructEncoder(t)
83
	case reflect.Map:
84 1
		return newMapEncoder(t)
85
	case reflect.Interface:
86 1
		return func(v reflect.Value) ([]byte, error) {
87 1
			if v.IsNil() {
88
				return []byte{binn.Null}, nil
89
			}
90
91 1
			return loadEncodeFunc(v.Elem().Type())(v.Elem())
92
		}
93
	case reflect.String:
94 1
		return func(v reflect.Value) ([]byte, error) {
95 1
			var bytes []byte
96
97 1
			bytes = append(bytes, Uint8(binn.StringType)...)
98 1
			bytes = append(bytes, String(v.String())...)
99 1
			bytes = append(bytes, 0x00)
100
101 1
			return bytes, nil
102
		}
103
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
104 1
		return func(v reflect.Value) ([]byte, error) {
105 1
			var bytes []byte
106
107 1
			bytes = append(bytes, Uint8(uint8(detectIntType(int(v.Int()))))...)
108 1
			bytes = append(bytes, Int(int(v.Int()))...)
109
110 1
			return bytes, nil
111
		}
112
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
113
		return func(v reflect.Value) ([]byte, error) {
114
			var bytes []byte
115
116
			bytes = append(bytes, Uint8(uint8(detectUintType(uint(v.Uint()))))...)
117
			bytes = append(bytes, Uint(uint(v.Uint()))...)
118
119
			return bytes, nil
120
		}
121
	case reflect.Float32:
122
		return func(v reflect.Value) ([]byte, error) {
123
			var bytes []byte
124
125
			bytes = append(bytes, Uint8(binn.Float32Type)...)
126
			bytes = append(bytes, Float32(float32(v.Float()))...)
127
128
			return bytes, nil
129
		}
130
	case reflect.Float64:
131
		return func(v reflect.Value) ([]byte, error) {
132
			var bytes []byte
133
134
			bytes = append(bytes, Uint8(binn.Float64Type)...)
135
			bytes = append(bytes, Float64(v.Float())...)
136
137
			return bytes, nil
138
		}
139
	case reflect.Slice, reflect.Array:
140 1
		return newArrayEncoder(t)
141
	case reflect.Ptr:
142
		return newPtrEncoder(t)
143
	}
144
145
	return func(v reflect.Value) ([]byte, error) {
146
		return nil, &UnsupportedTypeError{t}
147
	}
148
}
149
150
func marshalerEncoder(v reflect.Value) ([]byte, error) {
151 1
	if v.Kind() == reflect.Ptr && v.IsNil() {
152
		return []byte{0x00}, nil
153
	}
154 1
	m, ok := v.Interface().(Marshaler)
155 1
	if !ok {
156
		return []byte{0x00}, nil
157
	}
158 1
	b, err := m.MarshalBINN()
159 1
	if err != nil {
160
		return nil, &MarshalerError{v.Type(), err, "MarshalBINN"}
161
	}
162
163 1
	return b, nil
164
}
165