Path: blob/main/pkg/river/internal/value/value_object.go
4096 views
package value12import (3"reflect"45"github.com/grafana/agent/pkg/river/internal/reflectutil"6)78// structWrapper allows for partially traversing structs which contain fields9// representing blocks. This is required due to how block names and labels10// change the object representation.11//12// If a block name is a.b.c, then it is represented as three nested objects:13//14// {15// a = {16// b = {17// c = { /* block contents */ },18// },19// }20// }21//22// Similarly, if a block name is labeled (a.b.c "label"), then the label is the23// top-level key after c.24//25// structWrapper exposes Len, Keys, and Key methods similar to Value to allow26// traversing through the synthetic object. The values it returns are27// structWrappers.28//29// Code in value.go MUST check to see if a struct is a structWrapper *before*30// checking the value kind to ensure the appropriate methods are invoked.31type structWrapper struct {32structVal reflect.Value33fields *objectFields34label string // Non-empty string if this struct is wrapped in a label.35}3637func wrapStruct(val reflect.Value, keepLabel bool) structWrapper {38if val.Kind() != reflect.Struct {39panic("river/value: wrapStruct called on non-struct value")40}4142fields := getCachedTags(val.Type())4344var label string45if f, ok := fields.LabelField(); ok && keepLabel {46label = reflectutil.Get(val, f).String()47}4849return structWrapper{50structVal: val,51fields: fields,52label: label,53}54}5556// Value turns sw into a value.57func (sw structWrapper) Value() Value {58return Value{59rv: reflect.ValueOf(sw),60ty: TypeObject,61}62}6364func (sw structWrapper) Len() int {65if len(sw.label) > 0 {66return 167}68return sw.fields.Len()69}7071func (sw structWrapper) Keys() []string {72if len(sw.label) > 0 {73return []string{sw.label}74}75return sw.fields.Keys()76}7778func (sw structWrapper) Key(key string) (index Value, ok bool) {79if len(sw.label) > 0 {80if key != sw.label {81return82}83next := reflect.ValueOf(structWrapper{84structVal: sw.structVal,85fields: sw.fields,86// Unset the label now that we've traversed it87})88return Value{rv: next, ty: TypeObject}, true89}9091keyType := sw.fields.Has(key)9293switch keyType {94case objectKeyTypeInvalid:95return // No such key9697case objectKeyTypeNestedField:98// Continue traversing.99nextNode, _ := sw.fields.NestedField(key)100return Value{101rv: reflect.ValueOf(structWrapper{102structVal: sw.structVal,103fields: nextNode,104}),105ty: TypeObject,106}, true107108case objectKeyTypeField:109f, _ := sw.fields.Field(key)110val, err := sw.structVal.FieldByIndexErr(f.Index)111if err != nil {112return Null, true113}114return makeValue(val), true115}116117panic("river/value: unreachable")118}119120121