Skip to content

Commit b261fdc

Browse files
committed
feat(formatter-utils): improve stringify with reflect func
1 parent 14870b2 commit b261fdc

File tree

2 files changed

+153
-52
lines changed

2 files changed

+153
-52
lines changed

formatters/utils_service.go

Lines changed: 125 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -23,77 +23,149 @@ func (f *FormatterUtils) StringifyValues(ps *pool.State, v ...interface{}) {
2323
// StringifyValue writes into the buffer converted to string value that
2424
// it receives.
2525
func (f *FormatterUtils) StringifyValue(ps *pool.State, v interface{}) {
26-
switch v.(type) {
26+
switch t := v.(type) {
27+
case nil:
28+
ps.Buffer.WriteString("<nil>")
2729
case int:
28-
ps.Buffer.WriteInt(int64(v.(int)))
30+
ps.Buffer.WriteInt(int64(t))
2931
case int8:
30-
ps.Buffer.WriteInt(int64(v.(int8)))
32+
ps.Buffer.WriteInt(int64(t))
3133
case int16:
32-
ps.Buffer.WriteInt(int64(v.(int16)))
34+
ps.Buffer.WriteInt(int64(t))
3335
case int32:
34-
ps.Buffer.WriteInt(int64(v.(int32)))
36+
ps.Buffer.WriteInt(int64(t))
3537
case int64:
36-
ps.Buffer.WriteInt(v.(int64))
38+
ps.Buffer.WriteInt(t)
3739
case uint:
38-
ps.Buffer.WriteUint(uint64(v.(uint)))
40+
ps.Buffer.WriteUint(uint64(t))
3941
case uint8:
40-
ps.Buffer.WriteUint(uint64(v.(uint8)))
42+
ps.Buffer.WriteUint(uint64(t))
4143
case uint16:
42-
ps.Buffer.WriteUint(uint64(v.(uint16)))
44+
ps.Buffer.WriteUint(uint64(t))
4345
case uint32:
44-
ps.Buffer.WriteUint(uint64(v.(uint32)))
46+
ps.Buffer.WriteUint(uint64(t))
4547
case uint64:
46-
ps.Buffer.WriteUint(v.(uint64))
48+
ps.Buffer.WriteUint(t)
4749
case uintptr:
48-
ps.Buffer.WriteUint(uint64(v.(uintptr)))
50+
ps.Buffer.WriteUint(uint64(t))
4951
case string:
50-
ps.Buffer.WriteString(v.(string))
52+
ps.Buffer.WriteString(t)
5153
case bool:
52-
ps.Buffer.WriteBool(v.(bool))
54+
ps.Buffer.WriteBool(t)
5355
case float32:
54-
ps.Buffer.WriteFloat(float64(v.(float32)), 32)
56+
ps.Buffer.WriteFloat(float64(t), 32)
5557
case float64:
56-
ps.Buffer.WriteFloat(v.(float64), 64)
57-
case nil:
58-
ps.Buffer.WriteString("<nil>")
58+
ps.Buffer.WriteFloat(t, 64)
5959
case complex64:
60+
f.writeComplex(ps, complex128(t), 64)
6061
case complex128:
62+
f.writeComplex(ps, t, 128)
6163
default:
62-
f.StringifyValueWithReflect(ps, v)
64+
f.StringifyValueWithReflect(ps, reflect.ValueOf(v))
6365
}
6466
}
6567

6668
// StringifyValueWithReflect converts the given value using the reflect.
67-
func (f *FormatterUtils) StringifyValueWithReflect(ps *pool.State, v interface{}) {
68-
typeOfValue := reflect.TypeOf(v)
69-
switch typeOfValue.Kind() {
69+
func (f *FormatterUtils) StringifyValueWithReflect(ps *pool.State, value reflect.Value) {
70+
switch t := value.Kind(); t {
71+
case reflect.Invalid:
72+
ps.Buffer.WriteString("<invalid reflect.Value>")
73+
case reflect.Bool:
74+
ps.Buffer.WriteBool(value.Bool())
75+
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
76+
ps.Buffer.WriteInt(value.Int())
77+
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
78+
ps.Buffer.WriteUint(value.Uint())
79+
case reflect.Float32:
80+
ps.Buffer.WriteFloat(value.Float(), 32)
81+
case reflect.Float64:
82+
ps.Buffer.WriteFloat(value.Float(), 64)
83+
case reflect.Complex64:
84+
f.writeComplex(ps, value.Complex(), 64)
85+
case reflect.Complex128:
86+
f.writeComplex(ps, value.Complex(), 128)
87+
case reflect.String:
88+
ps.Buffer.WriteString(value.String())
89+
case reflect.Map:
90+
ps.Buffer.WriteString(value.Type().String())
91+
if value.IsNil() {
92+
ps.Buffer.WriteString("<nil>")
93+
return
94+
}
95+
ps.Buffer.WriteByte('{')
96+
ps.Buffer.WriteSpace()
97+
keys := value.MapKeys()
98+
for i, key := range keys {
99+
if i > 0 {
100+
ps.Buffer.WriteString(", ")
101+
}
102+
f.StringifyValueWithReflect(ps, key)
103+
ps.Buffer.WriteString(": ")
104+
f.StringifyValueWithReflect(ps, value.MapIndex(key))
105+
}
106+
ps.Buffer.WriteSpace()
107+
ps.Buffer.WriteByte('}')
70108
case reflect.Struct:
71-
f.StringifyStruct(ps, typeOfValue)
72-
default:
73-
ps.Buffer.WriteString(typeOfValue.Name())
74-
ps.Buffer.WriteString(typeOfValue.String())
75-
}
76-
}
109+
ps.Buffer.WriteString(value.Type().String())
110+
ps.Buffer.WriteByte('{')
111+
ps.Buffer.WriteSpace()
77112

78-
// StringifyStruct converts structure into a string.
79-
func (f *FormatterUtils) StringifyStruct(ps *pool.State, t reflect.Type) {
80-
ps.Buffer.WriteNewLine()
81-
ps.Buffer.WriteString(t.Name())
82-
ps.Buffer.WriteSpace()
83-
ps.Buffer.WriteByte('{')
84-
ps.Buffer.WriteNewLine()
85-
86-
for i := 0; i < t.NumField(); i++ {
87-
field := t.Field(i)
88-
ps.Buffer.WriteByte('\t')
89-
ps.Buffer.WriteString(field.Name)
90-
ps.Buffer.WriteString(": ")
91-
ps.Buffer.WriteString(field.Type.String())
92-
ps.Buffer.WriteNewLine()
93-
}
113+
for i := 0; i < value.NumField(); i++ {
114+
if i > 0 {
115+
ps.Buffer.WriteString(", ")
116+
}
94117

95-
ps.Buffer.WriteByte('}')
96-
ps.Buffer.WriteNewLine()
118+
field := value.Field(i)
119+
ps.Buffer.WriteString(value.Type().Field(i).Name)
120+
ps.Buffer.WriteString(": ")
121+
f.StringifyValueWithReflect(ps, field)
122+
}
123+
124+
ps.Buffer.WriteSpace()
125+
ps.Buffer.WriteByte('}')
126+
case reflect.Interface:
127+
v := value.Elem()
128+
if !v.IsValid() {
129+
ps.Buffer.WriteString(v.Type().String())
130+
} else {
131+
f.StringifyValue(ps, v.Interface())
132+
}
133+
case reflect.Array, reflect.Slice:
134+
ps.Buffer.WriteByte('[')
135+
for i := 0; i < value.Len(); i++ {
136+
if i > 0 {
137+
ps.Buffer.WriteByte(' ')
138+
}
139+
f.StringifyValueWithReflect(ps, value.Index(i))
140+
}
141+
ps.Buffer.WriteByte(']')
142+
case reflect.Ptr:
143+
if value.Pointer() != 0 {
144+
switch a := value.Elem(); value.Kind() {
145+
case reflect.Array, reflect.Slice, reflect.Struct, reflect.Map:
146+
ps.Buffer.WriteByte('&')
147+
f.StringifyValueWithReflect(ps, a)
148+
return
149+
}
150+
}
151+
fallthrough
152+
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
153+
switch value.Kind() {
154+
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
155+
ptr := value.Pointer()
156+
ps.Buffer.WriteByte('(')
157+
ps.Buffer.WriteString(value.Type().String())
158+
ps.Buffer.WriteString(")(")
159+
if ptr == 0 {
160+
ps.Buffer.WriteString("<nil>")
161+
} else {
162+
ps.Buffer.WriteUint(uint64(ptr))
163+
}
164+
ps.Buffer.WriteByte(')')
165+
}
166+
default:
167+
ps.Buffer.WriteString(value.String())
168+
}
97169
}
98170

99171
// StringifyByTemplate converts value into a string by the given format/template.
@@ -180,3 +252,10 @@ func (f *FormatterUtils) KeyValuesToMap(ps *pool.State, keyValues ...interface{}
180252
ps.Map.Set(key.(string), keyValues[i + 1])
181253
}
182254
}
255+
256+
func (f *FormatterUtils) writeComplex(ps *pool.State, v complex128, size int) {
257+
ps.Buffer.WriteByte('(')
258+
ps.Buffer.WriteFloat(real(v), size / 2)
259+
ps.Buffer.WriteFloat(imag(v), size / 2)
260+
ps.Buffer.WriteString("i)")
261+
}

formatters/utils_service_test.go

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"github.com/olehan/kek/buffer"
55
"github.com/olehan/kek/ds"
66
"github.com/olehan/kek/pool"
7+
"os"
8+
"reflect"
79
"strings"
810
"testing"
911
)
@@ -33,33 +35,53 @@ func TestFormatterUtils_StringifyValues(t *testing.T) {
3335
uint32Value := uint32(13411334)
3436
uint64Value := uint64(13524636364)
3537
uintptrValue := uintptr(346457456356)
36-
stringValue := string("oih24t9h334rad")
38+
stringValue := "oih24t9h334rad"
3739
boolValue := true
40+
mapValue := map[string]int{
41+
"value2": 1,
42+
"value1": 41,
43+
"longvaluegoeshere": 354345245,
44+
}
3845
float32Value := float32(245245.23423)
3946
float64Value := float64(2463621.351313)
4047
complex64Value := complex64(2346363623452.45235135134134)
4148
complex128Value := complex128(345346246134.13513513513413)
4249
structValue := struct {
4350
x int
4451
y int
52+
b bool
53+
f32 float32
54+
f64 float64
55+
u uint64
56+
c128 complex128
57+
c64 complex64
4558
a func() interface{}
4659
slice []string
60+
nilFunc func()
61+
nilMap map[string]bool
4762
}{
4863
x: 1,
4964
y: 2,
5065
a: func() interface{} {
5166
return ""
5267
},
53-
slice: []string{""},
68+
slice: []string{"a"},
5469
}
55-
interfaceSlice := []interface{}{}
70+
interfaceSlice := []interface{}{"stringval", 123}
5671

5772
state := _testFormatterPool.Get()
5873

5974
_testFormatter.StringifyValues(
6075
state,
6176
nil,
62-
_namedStruct{},
77+
_namedStruct{
78+
"sd",
79+
},
80+
&interfaceSlice,
81+
&_namedStruct{},
82+
mapValue,
83+
reflect.ValueOf(mapValue),
84+
os.Stdout,
6385
intValue,
6486
int8Value,
6587
int16Value,
@@ -75,10 +97,10 @@ func TestFormatterUtils_StringifyValues(t *testing.T) {
7597
boolValue,
7698
float32Value,
7799
float64Value,
78-
complex64Value,
79-
complex128Value,
80100
structValue,
81101
interfaceSlice,
102+
complex64Value,
103+
complex128Value,
82104
)
83105

84106
t.Log(string(state.Buffer))

0 commit comments

Comments
 (0)