Skip to content

Commit 1134e1f

Browse files
ksw2000gaby
andauthored
🩹 fix: make SetValWithStruct set zero values and support more types #3167 (#3227)
* 🩹 fix: make SetValWithStruct set zero values and support more types * 🚨 test: check zero in int_slice * fix: SetValWithStruct does not exist in fiber v2 * 🩹fix: restrict supported types in SetValWithStruct * 🩹fix: golangci-lint --------- Co-authored-by: Juan Calderon-Perez <[email protected]>
1 parent a63bd34 commit 1134e1f

File tree

2 files changed

+54
-59
lines changed

2 files changed

+54
-59
lines changed

client/request.go

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,11 +1062,14 @@ func ReleaseFile(f *File) {
10621062
filePool.Put(f)
10631063
}
10641064

1065-
// SetValWithStruct Set some values using structs.
1066-
// `p` is a structure that implements the WithStruct interface,
1067-
// The field name can be specified by `tagName`.
1068-
// `v` is a struct include some data.
1069-
// Note: This method only supports simple types and nested structs are not currently supported.
1065+
// SetValWithStruct stores the fields of `v` into `p`.
1066+
// `tagName` specifies the key used to store into `p`. If not specified,
1067+
// the field name is used by default.
1068+
// `v` is a struct or a pointer to a struct containing some data.
1069+
// Fields in `v` should be string, int, int8, int16, int32, int64, uint,
1070+
// uint8, uint16, uint32, uint64, float32, float64, complex64,
1071+
// complex128 or bool. Arrays or slices are inserted sequentially with the
1072+
// same key. Other types are ignored.
10701073
func SetValWithStruct(p WithStruct, tagName string, v any) {
10711074
valueOfV := reflect.ValueOf(v)
10721075
typeOfV := reflect.TypeOf(v)
@@ -1080,25 +1083,31 @@ func SetValWithStruct(p WithStruct, tagName string, v any) {
10801083
}
10811084

10821085
// Boring type judge.
1083-
// TODO: cover more types and complex data structure.
1084-
var setVal func(name string, value reflect.Value)
1086+
var setVal func(name string, val reflect.Value)
10851087
setVal = func(name string, val reflect.Value) {
10861088
switch val.Kind() {
10871089
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
10881090
p.Add(name, strconv.Itoa(int(val.Int())))
1091+
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1092+
p.Add(name, strconv.FormatUint(val.Uint(), 10))
1093+
case reflect.Float32, reflect.Float64:
1094+
p.Add(name, strconv.FormatFloat(val.Float(), 'f', -1, 64))
1095+
case reflect.Complex64, reflect.Complex128:
1096+
p.Add(name, strconv.FormatComplex(val.Complex(), 'f', -1, 128))
10891097
case reflect.Bool:
10901098
if val.Bool() {
10911099
p.Add(name, "true")
1100+
} else {
1101+
p.Add(name, "false")
10921102
}
10931103
case reflect.String:
10941104
p.Add(name, val.String())
1095-
case reflect.Float32, reflect.Float64:
1096-
p.Add(name, strconv.FormatFloat(val.Float(), 'f', -1, 64))
10971105
case reflect.Slice, reflect.Array:
10981106
for i := 0; i < val.Len(); i++ {
10991107
setVal(name, val.Index(i))
11001108
}
11011109
default:
1110+
return
11021111
}
11031112
}
11041113

@@ -1113,9 +1122,6 @@ func SetValWithStruct(p WithStruct, tagName string, v any) {
11131122
name = field.Name
11141123
}
11151124
val := valueOfV.Field(i)
1116-
if val.IsZero() {
1117-
continue
1118-
}
11191125
// To cover slice and array, we delete the val then add it.
11201126
p.Del(name)
11211127
setVal(name, val)

client/request_test.go

Lines changed: 36 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1530,14 +1530,16 @@ func Test_Request_MaxRedirects(t *testing.T) {
15301530
func Test_SetValWithStruct(t *testing.T) {
15311531
t.Parallel()
15321532

1533-
// test SetValWithStruct vai QueryParam struct.
1533+
// test SetValWithStruct via QueryParam struct.
15341534
type args struct {
15351535
TString string
15361536
TSlice []string
15371537
TIntSlice []int `param:"int_slice"`
15381538
unexport int
15391539
TInt int
1540+
TUint uint
15401541
TFloat float64
1542+
TComplex complex128
15411543
TBool bool
15421544
}
15431545

@@ -1550,18 +1552,22 @@ func Test_SetValWithStruct(t *testing.T) {
15501552
SetValWithStruct(p, "param", args{
15511553
unexport: 5,
15521554
TInt: 5,
1555+
TUint: 5,
15531556
TString: "string",
15541557
TFloat: 3.1,
1558+
TComplex: 3 + 4i,
15551559
TBool: false,
15561560
TSlice: []string{"foo", "bar"},
1557-
TIntSlice: []int{1, 2},
1561+
TIntSlice: []int{0, 1, 2},
15581562
})
15591563

15601564
require.Equal(t, "", string(p.Peek("unexport")))
15611565
require.Equal(t, []byte("5"), p.Peek("TInt"))
1566+
require.Equal(t, []byte("5"), p.Peek("TUint"))
15621567
require.Equal(t, []byte("string"), p.Peek("TString"))
15631568
require.Equal(t, []byte("3.1"), p.Peek("TFloat"))
1564-
require.Equal(t, "", string(p.Peek("TBool")))
1569+
require.Equal(t, []byte("(3+4i)"), p.Peek("TComplex"))
1570+
require.Equal(t, []byte("false"), p.Peek("TBool"))
15651571
require.True(t, func() bool {
15661572
for _, v := range p.PeekMulti("TSlice") {
15671573
if string(v) == "foo" {
@@ -1580,6 +1586,15 @@ func Test_SetValWithStruct(t *testing.T) {
15801586
return false
15811587
}())
15821588

1589+
require.True(t, func() bool {
1590+
for _, v := range p.PeekMulti("int_slice") {
1591+
if string(v) == "0" {
1592+
return true
1593+
}
1594+
}
1595+
return false
1596+
}())
1597+
15831598
require.True(t, func() bool {
15841599
for _, v := range p.PeekMulti("int_slice") {
15851600
if string(v) == "1" {
@@ -1655,24 +1670,6 @@ func Test_SetValWithStruct(t *testing.T) {
16551670
}())
16561671
})
16571672

1658-
t.Run("the zero val should be ignore", func(t *testing.T) {
1659-
t.Parallel()
1660-
p := &QueryParam{
1661-
Args: fasthttp.AcquireArgs(),
1662-
}
1663-
SetValWithStruct(p, "param", &args{
1664-
TInt: 0,
1665-
TString: "",
1666-
TFloat: 0.0,
1667-
})
1668-
1669-
require.Equal(t, "", string(p.Peek("TInt")))
1670-
require.Equal(t, "", string(p.Peek("TString")))
1671-
require.Equal(t, "", string(p.Peek("TFloat")))
1672-
require.Empty(t, p.PeekMulti("TSlice"))
1673-
require.Empty(t, p.PeekMulti("int_slice"))
1674-
})
1675-
16761673
t.Run("error type should ignore", func(t *testing.T) {
16771674
t.Parallel()
16781675
p := &QueryParam{
@@ -1684,14 +1681,16 @@ func Test_SetValWithStruct(t *testing.T) {
16841681
}
16851682

16861683
func Benchmark_SetValWithStruct(b *testing.B) {
1687-
// test SetValWithStruct vai QueryParam struct.
1684+
// test SetValWithStruct via QueryParam struct.
16881685
type args struct {
16891686
TString string
16901687
TSlice []string
16911688
TIntSlice []int `param:"int_slice"`
16921689
unexport int
16931690
TInt int
1691+
TUint uint
16941692
TFloat float64
1693+
TComplex complex128
16951694
TBool bool
16961695
}
16971696

@@ -1707,19 +1706,23 @@ func Benchmark_SetValWithStruct(b *testing.B) {
17071706
SetValWithStruct(p, "param", args{
17081707
unexport: 5,
17091708
TInt: 5,
1709+
TUint: 5,
17101710
TString: "string",
17111711
TFloat: 3.1,
1712+
TComplex: 3 + 4i,
17121713
TBool: false,
17131714
TSlice: []string{"foo", "bar"},
1714-
TIntSlice: []int{1, 2},
1715+
TIntSlice: []int{0, 1, 2},
17151716
})
17161717
}
17171718

17181719
require.Equal(b, "", string(p.Peek("unexport")))
17191720
require.Equal(b, []byte("5"), p.Peek("TInt"))
1721+
require.Equal(b, []byte("5"), p.Peek("TUint"))
17201722
require.Equal(b, []byte("string"), p.Peek("TString"))
17211723
require.Equal(b, []byte("3.1"), p.Peek("TFloat"))
1722-
require.Equal(b, "", string(p.Peek("TBool")))
1724+
require.Equal(b, []byte("(3+4i)"), p.Peek("TComplex"))
1725+
require.Equal(b, []byte("false"), p.Peek("TBool"))
17231726
require.True(b, func() bool {
17241727
for _, v := range p.PeekMulti("TSlice") {
17251728
if string(v) == "foo" {
@@ -1738,6 +1741,15 @@ func Benchmark_SetValWithStruct(b *testing.B) {
17381741
return false
17391742
}())
17401743

1744+
require.True(b, func() bool {
1745+
for _, v := range p.PeekMulti("int_slice") {
1746+
if string(v) == "0" {
1747+
return true
1748+
}
1749+
}
1750+
return false
1751+
}())
1752+
17411753
require.True(b, func() bool {
17421754
for _, v := range p.PeekMulti("int_slice") {
17431755
if string(v) == "1" {
@@ -1817,29 +1829,6 @@ func Benchmark_SetValWithStruct(b *testing.B) {
18171829
}())
18181830
})
18191831

1820-
b.Run("the zero val should be ignore", func(b *testing.B) {
1821-
p := &QueryParam{
1822-
Args: fasthttp.AcquireArgs(),
1823-
}
1824-
1825-
b.ReportAllocs()
1826-
b.StartTimer()
1827-
1828-
for i := 0; i < b.N; i++ {
1829-
SetValWithStruct(p, "param", &args{
1830-
TInt: 0,
1831-
TString: "",
1832-
TFloat: 0.0,
1833-
})
1834-
}
1835-
1836-
require.Empty(b, string(p.Peek("TInt")))
1837-
require.Empty(b, string(p.Peek("TString")))
1838-
require.Empty(b, string(p.Peek("TFloat")))
1839-
require.Empty(b, p.PeekMulti("TSlice"))
1840-
require.Empty(b, p.PeekMulti("int_slice"))
1841-
})
1842-
18431832
b.Run("error type should ignore", func(b *testing.B) {
18441833
p := &QueryParam{
18451834
Args: fasthttp.AcquireArgs(),

0 commit comments

Comments
 (0)