Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/river/internal/reflectutil/walk.go
4096 views
1
package reflectutil
2
3
import (
4
"reflect"
5
6
"github.com/grafana/agent/pkg/river/internal/rivertags"
7
)
8
9
// GetOrAlloc returns the nested field of value corresponding to index.
10
// GetOrAlloc panics if not given a struct.
11
func GetOrAlloc(value reflect.Value, field rivertags.Field) reflect.Value {
12
return GetOrAllocIndex(value, field.Index)
13
}
14
15
// GetOrAllocIndex returns the nested field of value corresponding to index.
16
// GetOrAllocIndex panics if not given a struct.
17
//
18
// It is similar to [reflect/Value.FieldByIndex] but can handle traversing
19
// through nil pointers. If allocate is true, GetOrAllocIndex allocates any
20
// intermediate nil pointers while traversing the struct.
21
func GetOrAllocIndex(value reflect.Value, index []int) reflect.Value {
22
if len(index) == 1 {
23
return value.Field(index[0])
24
}
25
26
if value.Kind() != reflect.Struct {
27
panic("GetOrAlloc must be given a Struct, but found " + value.Kind().String())
28
}
29
30
for _, next := range index {
31
value = deferencePointer(value).Field(next)
32
}
33
34
return value
35
}
36
37
func deferencePointer(value reflect.Value) reflect.Value {
38
for value.Kind() == reflect.Pointer {
39
if value.IsNil() {
40
value.Set(reflect.New(value.Type().Elem()))
41
}
42
value = value.Elem()
43
}
44
45
return value
46
}
47
48
// Get returns the nested field of value corresponding to index. Get panics if
49
// not given a struct.
50
//
51
// It is similar to [reflect/Value.FieldByIndex] but can handle traversing
52
// through nil pointers. If Get traverses through a nil pointer, a non-settable
53
// zero value for the final field is returned.
54
func Get(value reflect.Value, field rivertags.Field) reflect.Value {
55
if len(field.Index) == 1 {
56
return value.Field(field.Index[0])
57
}
58
59
if value.Kind() != reflect.Struct {
60
panic("Get must be given a Struct, but found " + value.Kind().String())
61
}
62
63
for i, next := range field.Index {
64
for value.Kind() == reflect.Pointer {
65
if value.IsNil() {
66
return getZero(value, field.Index[i:])
67
}
68
value = value.Elem()
69
}
70
71
value = value.Field(next)
72
}
73
74
return value
75
}
76
77
// getZero returns a non-settable zero value while walking value.
78
func getZero(value reflect.Value, index []int) reflect.Value {
79
typ := value.Type()
80
81
for _, next := range index {
82
for typ.Kind() == reflect.Pointer {
83
typ = typ.Elem()
84
}
85
typ = typ.Field(next).Type
86
}
87
88
return reflect.Zero(typ)
89
}
90
91