Skip to content

Commit dd8f762

Browse files
committed
Proposal for generics-based Setter
1 parent c6a54bc commit dd8f762

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

setter/setter.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,21 @@ func SetDefault(dest interface{}, defaultValue ...interface{}) {
5353
}
5454
}
5555

56+
func SetDefaultNew[T comparable](dest *T, defaultValues ...T) {
57+
if IsZeroNew(*dest) {
58+
for _, value := range defaultValues {
59+
if !IsZeroNew(value) {
60+
*dest = value
61+
}
62+
}
63+
}
64+
}
65+
66+
func IsZeroNew[T comparable](value T) bool {
67+
var zero T
68+
return value == zero
69+
}
70+
5671
// Assign the first value that is not empty or of zero value.
5772
// This panics if the value is not a pointer or if value and
5873
// default value are not of the same type.

setter/setter_test.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,112 @@ func TestIsNil(t *testing.T) {
145145
assert.True(t, setter.IsNil(thing))
146146
assert.False(t, setter.IsNil(&MyImplementation{}))
147147
}
148+
149+
// ---------------------------------------------------------
150+
151+
var newRes string
152+
153+
func BenchmarkSetterNew(b *testing.B) {
154+
var r string
155+
for i := 0; i < b.N; i++ {
156+
setter.SetDefaultNew(&r, "", "", "42")
157+
}
158+
newRes = r
159+
}
160+
161+
var oldRes string
162+
163+
func BenchmarkSetter(b *testing.B) {
164+
var r string
165+
for i := 0; i < b.N; i++ {
166+
setter.SetDefault(&r, "", "", "42")
167+
}
168+
oldRes = r
169+
}
170+
171+
func TestSetterNew_IfEmpty(t *testing.T) {
172+
var conf struct {
173+
Foo string
174+
Bar int
175+
}
176+
assert.Equal(t, "", conf.Foo)
177+
assert.Equal(t, 0, conf.Bar)
178+
179+
// Should apply the default values
180+
setter.SetDefaultNew(&conf.Foo, "default")
181+
setter.SetDefaultNew(&conf.Bar, 200)
182+
183+
assert.Equal(t, "default", conf.Foo)
184+
assert.Equal(t, 200, conf.Bar)
185+
186+
conf.Foo = "thrawn"
187+
conf.Bar = 500
188+
189+
// Should NOT apply the default values
190+
setter.SetDefaultNew(&conf.Foo, "default")
191+
setter.SetDefaultNew(&conf.Bar, 200)
192+
193+
assert.Equal(t, "thrawn", conf.Foo)
194+
assert.Equal(t, 500, conf.Bar)
195+
}
196+
197+
func TestSetterNew_IfDefaultPrecedence(t *testing.T) {
198+
var conf struct {
199+
Foo string
200+
Bar string
201+
}
202+
assert.Equal(t, "", conf.Foo)
203+
assert.Equal(t, "", conf.Bar)
204+
205+
// Should use the final default value
206+
envValue := ""
207+
setter.SetDefaultNew(&conf.Foo, envValue, "default")
208+
assert.Equal(t, "default", conf.Foo)
209+
210+
// Should use envValue
211+
envValue = "bar"
212+
setter.SetDefaultNew(&conf.Bar, envValue, "default")
213+
assert.Equal(t, "bar", conf.Bar)
214+
}
215+
216+
func TestSetterNew_IsEmpty(t *testing.T) {
217+
var count64 int64
218+
var thing string
219+
220+
// Should return true
221+
assert.Equal(t, true, setter.IsZeroNew(count64))
222+
assert.Equal(t, true, setter.IsZeroNew(thing))
223+
224+
thing = "thrawn"
225+
count64 = int64(1)
226+
assert.Equal(t, false, setter.IsZeroNew(count64))
227+
assert.Equal(t, false, setter.IsZeroNew(thing))
228+
}
229+
230+
// Not possible now given compiler warnings
231+
// func TestSetterNew_IfEmptyTypePanic(t *testing.T) {
232+
// defer func() {
233+
// if r := recover(); r != nil {
234+
// assert.Equal(t, "reflect.Set: value of type int is not assignable to type string", r)
235+
// }
236+
// }()
237+
238+
// var thing string
239+
// // Should panic
240+
// setter.SetDefaultNew(&thing, 1)
241+
// assert.Fail(t, "Should have caught panic")
242+
// }
243+
244+
// Not possible now given argument is now a pointer to T
245+
// func TestSetterNew_IfEmptyNonPtrPanic(t *testing.T) {
246+
// defer func() {
247+
// if r := recover(); r != nil {
248+
// assert.Equal(t, "setter.SetDefault: Expected first argument to be of type reflect.Ptr", r)
249+
// }
250+
// }()
251+
252+
// var thing string
253+
// // Should panic
254+
// setter.SetDefaultNew(thing, "thrawn")
255+
// assert.Fail(t, "Should have caught panic")
256+
// }

0 commit comments

Comments
 (0)