Skip to content

Commit b1a154e

Browse files
committed
add feature nested pointer support(#21)
1 parent 38926db commit b1a154e

File tree

4 files changed

+150
-9
lines changed

4 files changed

+150
-9
lines changed

README.md

+34
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,40 @@ fmt.Println(example.Bar) //Prints: 0
6666

6767
```
6868

69+
Pointer Set
70+
-------
71+
72+
Pointer field struct is a tricky usage to avoid covering existed values.
73+
74+
Take the basic example in the above section and change it slightly:
75+
```go
76+
77+
type ExamplePointer struct {
78+
Foo *bool `default:"true"` //<-- StructTag with a default key
79+
Bar *string `default:"example"`
80+
Qux *int `default:"22"`
81+
Oed *int64 `default:"64"`
82+
}
83+
84+
...
85+
86+
boolZero := false
87+
stringZero := ""
88+
intZero := 0
89+
example := ExamplePointer{
90+
Foo: &boolZero,
91+
Bar: &stringZero,
92+
Qux: &intZero,
93+
}
94+
defaults.SetDefaults(example)
95+
96+
fmt.Println(*example.Foo) //Prints: false (zero value `false` for bool but not for bool ptr)
97+
fmt.Println(*example.Bar) //Prints: "" (print "" which set in advance, not "example" for default)
98+
fmt.Println(*example.Qux) //Prints: 0 (0 instead of 22)
99+
fmt.Println(*example.Oed) //Prints: 64 (64, because the ptr addr is nil when SetDefaults)
100+
101+
```
102+
69103
License
70104
-------
71105

defaults.go

+78-9
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@ import (
1212
// the StructTag with name "default" and the directed value.
1313
//
1414
// Usage
15-
// type ExampleBasic struct {
16-
// Foo bool `default:"true"`
17-
// Bar string `default:"33"`
18-
// Qux int8
19-
// Dur time.Duration `default:"2m3s"`
20-
// }
2115
//
22-
// foo := &ExampleBasic{}
23-
// SetDefaults(foo)
16+
// type ExampleBasic struct {
17+
// Foo bool `default:"true"`
18+
// Bar string `default:"33"`
19+
// Qux int8
20+
// Dur time.Duration `default:"2m3s"`
21+
// }
22+
//
23+
// foo := &ExampleBasic{}
24+
// SetDefaults(foo)
2425
func SetDefaults(variable interface{}) {
2526
getDefaultFiller().Fill(variable)
2627
}
@@ -90,7 +91,11 @@ func newDefaultFiller() *Filler {
9091
types := make(map[TypeHash]FillerFunc, 1)
9192
types["time.Duration"] = func(field *FieldData) {
9293
d, _ := time.ParseDuration(field.TagValue)
93-
field.Value.Set(reflect.ValueOf(d))
94+
if field.Value.Kind() == reflect.Ptr {
95+
field.Value.Set(reflect.ValueOf(&d))
96+
} else {
97+
field.Value.Set(reflect.ValueOf(d))
98+
}
9499
}
95100

96101
funcs[reflect.Slice] = func(field *FieldData) {
@@ -134,6 +139,70 @@ func newDefaultFiller() *Filler {
134139
}
135140
}
136141

142+
funcs[reflect.Ptr] = func(field *FieldData) {
143+
if field.TagValue == "" {
144+
return
145+
}
146+
switch field.Value.Type().Elem().Kind() {
147+
case reflect.Bool:
148+
value, _ := strconv.ParseBool(field.TagValue)
149+
field.Value.Set(reflect.ValueOf(&value))
150+
case reflect.Int:
151+
v, _ := strconv.ParseInt(field.TagValue, 10, 64)
152+
value := int(v)
153+
field.Value.Set(reflect.ValueOf(&value))
154+
case reflect.Int8:
155+
v, _ := strconv.ParseInt(field.TagValue, 10, 64)
156+
value := int8(v)
157+
field.Value.Set(reflect.ValueOf(&value))
158+
case reflect.Int16:
159+
v, _ := strconv.ParseInt(field.TagValue, 10, 64)
160+
value := int16(v)
161+
field.Value.Set(reflect.ValueOf(&value))
162+
case reflect.Int32:
163+
v, _ := strconv.ParseInt(field.TagValue, 10, 64)
164+
value := int32(v)
165+
field.Value.Set(reflect.ValueOf(&value))
166+
case reflect.Int64:
167+
if field.Field.Type == reflect.TypeOf(time.Second) {
168+
value, _ := time.ParseDuration(field.TagValue)
169+
field.Value.Set(reflect.ValueOf(&value))
170+
} else {
171+
value, _ := strconv.ParseInt(field.TagValue, 10, 64)
172+
field.Value.Set(reflect.ValueOf(&value))
173+
}
174+
case reflect.Uint:
175+
v, _ := strconv.ParseUint(field.TagValue, 10, 64)
176+
value := uint(v)
177+
field.Value.Set(reflect.ValueOf(&value))
178+
case reflect.Uint8:
179+
v, _ := strconv.ParseUint(field.TagValue, 10, 64)
180+
value := uint8(v)
181+
field.Value.Set(reflect.ValueOf(&value))
182+
case reflect.Uint16:
183+
v, _ := strconv.ParseUint(field.TagValue, 10, 64)
184+
value := uint16(v)
185+
field.Value.Set(reflect.ValueOf(&value))
186+
case reflect.Uint32:
187+
v, _ := strconv.ParseUint(field.TagValue, 10, 64)
188+
value := uint32(v)
189+
field.Value.Set(reflect.ValueOf(&value))
190+
case reflect.Uint64:
191+
value, _ := strconv.ParseUint(field.TagValue, 10, 64)
192+
field.Value.Set(reflect.ValueOf(&value))
193+
case reflect.Float32:
194+
v, _ := strconv.ParseFloat(field.TagValue, 64)
195+
value := float32(v)
196+
field.Value.Set(reflect.ValueOf(&value))
197+
case reflect.Float64:
198+
value, _ := strconv.ParseFloat(field.TagValue, 64)
199+
field.Value.Set(reflect.ValueOf(&value))
200+
case reflect.String:
201+
tagValue := parseDateTimeString(field.TagValue)
202+
field.Value.Set(reflect.ValueOf(&tagValue))
203+
}
204+
}
205+
137206
return &Filler{FuncByKind: funcs, FuncByType: types, Tag: "default"}
138207
}
139208

defaults_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,22 @@ type ExampleBasic struct {
6161
StringSliceSlice [][]string `default:"[[1],[]]"`
6262

6363
DateTime string `default:"{{date:1,-10,0}} {{time:1,-5,10}}"`
64+
65+
BoolPtr *bool `default:"false"`
66+
IntPtr *int `default:"33"`
67+
Int8Ptr *int8 `default:"8"`
68+
Int16Ptr *int16 `default:"16"`
69+
Int32Ptr *int32 `default:"32"`
70+
Int64Ptr *int64 `default:"64"`
71+
UIntPtr *uint `default:"11"`
72+
UInt8Ptr *uint8 `default:"18"`
73+
UInt16Ptr *uint16 `default:"116"`
74+
UInt32Ptr *uint32 `default:"132"`
75+
UInt64Ptr *uint64 `default:"164"`
76+
Float32Ptr *float32 `default:"3.2"`
77+
Float64Ptr *float64 `default:"6.4"`
78+
DurationPtr *time.Duration `default:"1s"`
79+
SecondPtr *time.Duration `default:"1s"`
6480
}
6581

6682
func (s *DefaultsSuite) TestSetDefaultsBasic(c *C) {
@@ -106,6 +122,21 @@ func (s *DefaultsSuite) assertTypes(c *C, foo *ExampleBasic) {
106122
c.Assert(foo.IntSliceSlice, DeepEquals, [][]int{[]int{1}, []int{2}, []int{3}, []int{4}})
107123
c.Assert(foo.StringSliceSlice, DeepEquals, [][]string{[]string{"1"}, []string{}})
108124
c.Assert(foo.DateTime, Equals, "2020-08-10 12:55:10")
125+
c.Assert(*foo.BoolPtr, Equals, false)
126+
c.Assert(*foo.IntPtr, Equals, 33)
127+
c.Assert(*foo.Int8Ptr, Equals, int8(8))
128+
c.Assert(*foo.Int16Ptr, Equals, int16(16))
129+
c.Assert(*foo.Int32Ptr, Equals, int32(32))
130+
c.Assert(*foo.Int64Ptr, Equals, int64(64))
131+
c.Assert(*foo.UIntPtr, Equals, uint(11))
132+
c.Assert(*foo.UInt8Ptr, Equals, uint8(18))
133+
c.Assert(*foo.UInt16Ptr, Equals, uint16(116))
134+
c.Assert(*foo.UInt32Ptr, Equals, uint32(132))
135+
c.Assert(*foo.UInt64Ptr, Equals, uint64(164))
136+
c.Assert(*foo.Float32Ptr, Equals, float32(3.2))
137+
c.Assert(*foo.Float64Ptr, Equals, 6.4)
138+
c.Assert(*foo.DurationPtr, Equals, time.Second)
139+
c.Assert(*foo.SecondPtr, Equals, time.Second)
109140
}
110141

111142
func (s *DefaultsSuite) TestSetDefaultsWithValues(c *C) {
@@ -118,6 +149,9 @@ func (s *DefaultsSuite) TestSetDefaultsWithValues(c *C) {
118149
Children: []Child{{Name: "alice"}, {Name: "bob", Age: 2}},
119150
}
120151

152+
intzero := 0
153+
foo.IntPtr = &intzero
154+
121155
SetDefaults(foo)
122156

123157
c.Assert(foo.Integer, Equals, 55)
@@ -127,6 +161,8 @@ func (s *DefaultsSuite) TestSetDefaultsWithValues(c *C) {
127161
c.Assert(string(foo.Bytes), Equals, "foo")
128162
c.Assert(foo.Children[0].Age, Equals, 10)
129163
c.Assert(foo.Children[1].Age, Equals, 2)
164+
165+
c.Assert(*foo.IntPtr, Equals, 0)
130166
}
131167

132168
func (s *DefaultsSuite) BenchmarkLogic(c *C) {

filler.go

+2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ func (f *Filler) isEmpty(field *FieldData) bool {
8787
}
8888
case reflect.String:
8989
return field.Value.String() == ""
90+
case reflect.Ptr:
91+
return field.Value.IsZero()
9092
}
9193
return true
9294
}

0 commit comments

Comments
 (0)