-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdefault.go
59 lines (56 loc) · 1.7 KB
/
default.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package reflectutils
import (
"reflect"
"github.com/pkg/errors"
)
// FillInDefaultValues will look at struct tags, looking for a
// "default" tag. If it finds one and the value in the struct
// is not set, then it will try to turn the string into a value.
// A pointer that is not nil is considered set and will not be
// overrridden.
//
// It can handle fields with supported types. The supported types
// are: any type that implements encoding.TextUnmarshaler;
// time.Duration; and any types preregistered with
// RegisterStringSetter(); pointers to any of the above types.
//
// The argument must be a pointer to a struct. Anything else will
// return error. A nil pointer is not allowed.
func FillInDefaultValues(pointerToStruct any) error {
ptr := reflect.ValueOf(pointerToStruct)
if ptr.Kind() != reflect.Ptr {
return errors.Errorf("cannot fill in defaults for anything (%s) but a valid pointer", ptr.Kind())
}
if ptr.IsNil() {
return errors.Errorf("cannot fill in defaults for a nil pointer")
}
valueType := ptr.Type().Elem()
if valueType.Kind() != reflect.Struct {
return errors.Errorf("cannot fill in defaults for non-structs (%s)", valueType)
}
var firstError error
WalkStructElements(valueType, func(field reflect.StructField) bool {
tag, ok := LookupTag(field.Tag, "default")
if !ok {
return true
}
value := ptr.Elem().FieldByIndex(field.Index)
if !value.CanSet() {
return true
}
if !value.IsZero() {
return true
}
setter, err := MakeStringSetter(field.Type)
if err != nil {
firstError = err // override since this is worse
return true
}
err = setter(value, tag.Value)
if err != nil && firstError == nil {
firstError = err
}
return true
})
return firstError
}