Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/river/internal/value/value_object.go
4096 views
1
package value
2
3
import (
4
"reflect"
5
6
"github.com/grafana/agent/pkg/river/internal/reflectutil"
7
)
8
9
// structWrapper allows for partially traversing structs which contain fields
10
// representing blocks. This is required due to how block names and labels
11
// change the object representation.
12
//
13
// If a block name is a.b.c, then it is represented as three nested objects:
14
//
15
// {
16
// a = {
17
// b = {
18
// c = { /* block contents */ },
19
// },
20
// }
21
// }
22
//
23
// Similarly, if a block name is labeled (a.b.c "label"), then the label is the
24
// top-level key after c.
25
//
26
// structWrapper exposes Len, Keys, and Key methods similar to Value to allow
27
// traversing through the synthetic object. The values it returns are
28
// structWrappers.
29
//
30
// Code in value.go MUST check to see if a struct is a structWrapper *before*
31
// checking the value kind to ensure the appropriate methods are invoked.
32
type structWrapper struct {
33
structVal reflect.Value
34
fields *objectFields
35
label string // Non-empty string if this struct is wrapped in a label.
36
}
37
38
func wrapStruct(val reflect.Value, keepLabel bool) structWrapper {
39
if val.Kind() != reflect.Struct {
40
panic("river/value: wrapStruct called on non-struct value")
41
}
42
43
fields := getCachedTags(val.Type())
44
45
var label string
46
if f, ok := fields.LabelField(); ok && keepLabel {
47
label = reflectutil.Get(val, f).String()
48
}
49
50
return structWrapper{
51
structVal: val,
52
fields: fields,
53
label: label,
54
}
55
}
56
57
// Value turns sw into a value.
58
func (sw structWrapper) Value() Value {
59
return Value{
60
rv: reflect.ValueOf(sw),
61
ty: TypeObject,
62
}
63
}
64
65
func (sw structWrapper) Len() int {
66
if len(sw.label) > 0 {
67
return 1
68
}
69
return sw.fields.Len()
70
}
71
72
func (sw structWrapper) Keys() []string {
73
if len(sw.label) > 0 {
74
return []string{sw.label}
75
}
76
return sw.fields.Keys()
77
}
78
79
func (sw structWrapper) Key(key string) (index Value, ok bool) {
80
if len(sw.label) > 0 {
81
if key != sw.label {
82
return
83
}
84
next := reflect.ValueOf(structWrapper{
85
structVal: sw.structVal,
86
fields: sw.fields,
87
// Unset the label now that we've traversed it
88
})
89
return Value{rv: next, ty: TypeObject}, true
90
}
91
92
keyType := sw.fields.Has(key)
93
94
switch keyType {
95
case objectKeyTypeInvalid:
96
return // No such key
97
98
case objectKeyTypeNestedField:
99
// Continue traversing.
100
nextNode, _ := sw.fields.NestedField(key)
101
return Value{
102
rv: reflect.ValueOf(structWrapper{
103
structVal: sw.structVal,
104
fields: nextNode,
105
}),
106
ty: TypeObject,
107
}, true
108
109
case objectKeyTypeField:
110
f, _ := sw.fields.Field(key)
111
val, err := sw.structVal.FieldByIndexErr(f.Index)
112
if err != nil {
113
return Null, true
114
}
115
return makeValue(val), true
116
}
117
118
panic("river/value: unreachable")
119
}
120
121