Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/river/internal/value/decode.go
4096 views
1
package value
2
3
import (
4
"encoding"
5
"errors"
6
"fmt"
7
"reflect"
8
"time"
9
10
"github.com/grafana/agent/pkg/river/internal/reflectutil"
11
)
12
13
// Unmarshaler is a custom type which can be used to hook into the decoder.
14
type Unmarshaler interface {
15
// UnmarshalRiver is called when decoding a value. f should be invoked to
16
// continue decoding with a value to decode into.
17
UnmarshalRiver(f func(v interface{}) error) error
18
}
19
20
// Decode assigns a Value val to a Go pointer target. Pointers will be
21
// allocated as necessary when decoding.
22
//
23
// As a performance optimization, the underlying Go value of val will be
24
// assigned directly to target if the Go types match. This means that pointers,
25
// slices, and maps will be passed by reference. Callers should take care not
26
// to modify any Values after decoding, unless it is expected by the contract
27
// of the type (i.e., when the type exposes a goroutine-safe API). In other
28
// cases, new maps and slices will be allocated as necessary. Call DecodeCopy
29
// to make a copy of val instead.
30
//
31
// When a direct assignment is not done, Decode first checks to see if target
32
// implements the Unmarshaler or text.Unmarshaler interface, invoking methods
33
// as appropriate. It will also use time.ParseDuration if target is
34
// *time.Duration.
35
//
36
// Next, Decode will attempt to convert val to the type expected by target for
37
// assignment. If val or target implement ConvertibleCapsule, conversion
38
// between values will be attempted by calling ConvertFrom and ConvertInto as
39
// appropriate. If val cannot be converted, an error is returned.
40
//
41
// River null values will decode into a nil Go pointer or the zero value for
42
// the non-pointer type.
43
//
44
// Decode will panic if target is not a pointer.
45
func Decode(val Value, target interface{}) error {
46
rt := reflect.ValueOf(target)
47
if rt.Kind() != reflect.Pointer {
48
panic("river/value: Decode called with non-pointer value")
49
}
50
51
var d decoder
52
return d.decode(val, rt)
53
}
54
55
// DecodeCopy is like Decode but a deep copy of val is always made.
56
//
57
// Unlike Decode, DecodeCopy will always invoke Unmarshaler and
58
// text.Unmarshaler interfaces (if implemented by target).
59
func DecodeCopy(val Value, target interface{}) error {
60
rt := reflect.ValueOf(target)
61
if rt.Kind() != reflect.Pointer {
62
panic("river/value: Decode called with non-pointer value")
63
}
64
65
d := decoder{makeCopy: true}
66
return d.decode(val, rt)
67
}
68
69
type decoder struct {
70
makeCopy bool
71
}
72
73
func (d *decoder) decode(val Value, into reflect.Value) error {
74
// Store the raw value from val and try to address it so we can do underlying
75
// type match assignment.
76
rawValue := val.rv
77
if rawValue.CanAddr() {
78
rawValue = rawValue.Addr()
79
}
80
81
// Fully deference into and allocate pointers as necessary.
82
for into.Kind() == reflect.Pointer {
83
// Check for direct assignments before allocating pointers and dereferencing.
84
// This preserves pointer addresses when decoding an *int into an *int.
85
switch {
86
case into.CanSet() && val.Type() == TypeNull:
87
into.Set(reflect.Zero(into.Type()))
88
return nil
89
case into.CanSet() && d.canDirectlyAssign(rawValue.Type(), into.Type()):
90
into.Set(rawValue)
91
return nil
92
case into.CanSet() && d.canDirectlyAssign(val.rv.Type(), into.Type()):
93
into.Set(val.rv)
94
return nil
95
}
96
97
if into.IsNil() {
98
into.Set(reflect.New(into.Type().Elem()))
99
}
100
into = into.Elem()
101
}
102
103
// Ww need to preform the same switch statement as above after the loop to
104
// check for direct assignment one more time on the fully deferenced types.
105
//
106
// NOTE(rfratto): we skip the rawValue assignment check since that's meant
107
// for assigning pointers, and into is never a pointer when we reach here.
108
switch {
109
case into.CanSet() && val.Type() == TypeNull:
110
into.Set(reflect.Zero(into.Type()))
111
return nil
112
case into.CanSet() && d.canDirectlyAssign(val.rv.Type(), into.Type()):
113
into.Set(val.rv)
114
return nil
115
}
116
117
// Special decoding rules:
118
//
119
// 1. If into is an interface{}, go through decodeAny so it gets assigned
120
// predictable types.
121
// 2. If into implements a supported interface, use the interface for
122
// decoding instead.
123
if into.Type() == goAny {
124
return d.decodeAny(val, into)
125
} else if ok, err := d.decodeFromInterface(val, into); ok {
126
return err
127
}
128
129
targetType := RiverType(into.Type())
130
131
// Track a value to use for decoding. This value will be updated if
132
// conversion is necessary.
133
//
134
// NOTE(rfratto): we don't reassign to val here, since Go 1.18 thinks that
135
// means it escapes the heap. We need to create a local variable to avoid
136
// extra allocations.
137
convVal := val
138
139
// Convert the value.
140
switch {
141
case val.rv.Type() == goByteSlice && into.Type() == goString: // []byte -> string
142
into.Set(val.rv.Convert(goString))
143
return nil
144
case val.rv.Type() == goString && into.Type() == goByteSlice: // string -> []byte
145
into.Set(val.rv.Convert(goByteSlice))
146
return nil
147
case convVal.Type() != targetType:
148
converted, err := tryCapsuleConvert(convVal, into, targetType)
149
if err != nil {
150
return err
151
} else if converted {
152
return nil
153
}
154
155
convVal, err = convertValue(convVal, targetType)
156
if err != nil {
157
return err
158
}
159
}
160
161
// Slowest case: recursive decoding. Once we've reached this point, we know
162
// that convVal.rv and into are compatible Go types.
163
switch convVal.Type() {
164
case TypeNumber:
165
into.Set(convertGoNumber(convVal.Number(), into.Type()))
166
return nil
167
case TypeString:
168
// Call convVal.Text() to get the final string value, since convVal.rv
169
// might not be a string.
170
into.Set(reflect.ValueOf(convVal.Text()))
171
return nil
172
case TypeBool:
173
into.Set(reflect.ValueOf(convVal.Bool()))
174
return nil
175
case TypeArray:
176
return d.decodeArray(convVal, into)
177
case TypeObject:
178
return d.decodeObject(convVal, into)
179
case TypeFunction:
180
// The Go types for two functions must be the same.
181
//
182
// TODO(rfratto): we may want to consider being more lax here, potentially
183
// creating an adapter between the two functions.
184
if convVal.rv.Type() == into.Type() {
185
into.Set(convVal.rv)
186
return nil
187
}
188
189
return Error{
190
Value: val,
191
Inner: fmt.Errorf("expected function(%s), got function(%s)", into.Type(), convVal.rv.Type()),
192
}
193
case TypeCapsule:
194
// The Go types for the capsules must be the same or able to be converted.
195
if convVal.rv.Type() == into.Type() {
196
into.Set(convVal.rv)
197
return nil
198
}
199
200
converted, err := tryCapsuleConvert(convVal, into, targetType)
201
if err != nil {
202
return err
203
} else if converted {
204
return nil
205
}
206
207
// TODO(rfratto): return a TypeError for this instead. TypeError isn't
208
// appropriate at the moment because it would just print "capsule", which
209
// doesn't contain all the information the user would want to know (e.g., a
210
// capsule of what inner type?).
211
return Error{
212
Value: val,
213
Inner: fmt.Errorf("expected capsule(%q), got %s", into.Type(), convVal.Describe()),
214
}
215
default:
216
panic("river/value: unexpected kind " + convVal.Type().String())
217
}
218
}
219
220
// canDirectlyAssign returns true if the `from` type can be directly asssigned
221
// to the `into` type. This always returns false if the decoder is set to make
222
// copies or into contains an interface{} type anywhere in its type definition
223
// to allow for decoding interfaces{} into a set of known types.
224
func (d *decoder) canDirectlyAssign(from reflect.Type, into reflect.Type) bool {
225
if d.makeCopy {
226
return false
227
}
228
if from != into {
229
return false
230
}
231
return !containsAny(into)
232
}
233
234
// containsAny recursively traverses through into, returning true if it
235
// contains an interface{} value anywhere in its structure.
236
func containsAny(into reflect.Type) bool {
237
// TODO(rfratto): cache result of this function?
238
239
if into == goAny {
240
return true
241
}
242
243
switch into.Kind() {
244
case reflect.Array, reflect.Pointer, reflect.Slice:
245
return containsAny(into.Elem())
246
case reflect.Map:
247
if into.Key() == goString {
248
return containsAny(into.Elem())
249
}
250
return false
251
252
case reflect.Struct:
253
for i := 0; i < into.NumField(); i++ {
254
if containsAny(into.Field(i).Type) {
255
return true
256
}
257
}
258
return false
259
260
default:
261
// Other kinds are not River types where the decodeAny check applies.
262
return false
263
}
264
}
265
266
func (d *decoder) decodeFromInterface(val Value, into reflect.Value) (ok bool, err error) {
267
// into may only implement interface types for a pointer receiver, so we want
268
// to address into if possible.
269
if into.CanAddr() {
270
into = into.Addr()
271
}
272
273
switch {
274
case into.Type() == goDurationPtr:
275
var s string
276
err := d.decode(val, reflect.ValueOf(&s))
277
if err != nil {
278
return true, err
279
}
280
dur, err := time.ParseDuration(s)
281
if err != nil {
282
return true, Error{Value: val, Inner: err}
283
}
284
*into.Interface().(*time.Duration) = dur
285
return true, nil
286
287
case into.Type().Implements(goRiverDecoder):
288
err := into.Interface().(Unmarshaler).UnmarshalRiver(func(v interface{}) error {
289
return d.decode(val, reflect.ValueOf(v))
290
})
291
if err != nil {
292
// TODO(rfratto): we need to detect if error is one of the error types
293
// from this package and only wrap it in an Error if it isn't.
294
return true, Error{Value: val, Inner: err}
295
}
296
return true, nil
297
298
case into.Type().Implements(goTextUnmarshaler):
299
var s string
300
err := d.decode(val, reflect.ValueOf(&s))
301
if err != nil {
302
return true, err
303
}
304
err = into.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(s))
305
if err != nil {
306
return true, Error{Value: val, Inner: err}
307
}
308
return true, nil
309
}
310
311
return false, nil
312
}
313
314
func tryCapsuleConvert(from Value, into reflect.Value, intoType Type) (ok bool, err error) {
315
// Check to see if we can use capsule conversion.
316
if from.Type() == TypeCapsule {
317
cc, ok := from.Interface().(ConvertibleIntoCapsule)
318
if ok {
319
// It's always possible to Addr the reflect.Value below since we expect
320
// it to be a settable non-pointer value.
321
err := cc.ConvertInto(into.Addr().Interface())
322
if err == nil {
323
return true, nil
324
} else if err != nil && !errors.Is(err, ErrNoConversion) {
325
return false, Error{Value: from, Inner: err}
326
}
327
}
328
}
329
330
if intoType == TypeCapsule {
331
cc, ok := into.Addr().Interface().(ConvertibleFromCapsule)
332
if ok {
333
err := cc.ConvertFrom(from.Interface())
334
if err == nil {
335
return true, nil
336
} else if err != nil && !errors.Is(err, ErrNoConversion) {
337
return false, Error{Value: from, Inner: err}
338
}
339
}
340
}
341
342
// Last attempt: allow converting two capsules if the Go types are compatible
343
// and the into kind is an interface.
344
//
345
// TODO(rfratto): we may consider expanding this to allowing conversion to
346
// any compatible Go type in the future (not just interfaces).
347
if from.Type() == TypeCapsule && intoType == TypeCapsule && into.Kind() == reflect.Interface {
348
// We try to convert a pointer to from first to avoid making unnecessary
349
// copies.
350
if from.Reflect().CanAddr() && from.Reflect().Addr().CanConvert(into.Type()) {
351
val := from.Reflect().Addr().Convert(into.Type())
352
into.Set(val)
353
return true, nil
354
} else if from.Reflect().CanConvert(into.Type()) {
355
val := from.Reflect().Convert(into.Type())
356
into.Set(val)
357
return true, nil
358
}
359
}
360
361
return false, nil
362
}
363
364
// decodeAny is invoked by decode when into is an interface{}. We assign the
365
// interface{} a known type based on the River value being decoded:
366
//
367
// Null values: nil
368
// Number values: float64, int, or uint depending on the underlying Go type
369
// of the River value
370
// Arrays: []interface{}
371
// Objects: map[string]interface{}
372
// Bool: bool
373
// String: string
374
// Function: Passthrough of the underlying function value
375
// Capsule: Passthrough of the underlying capsule value
376
//
377
// In the cases where we do not pass through the underlying value, we create a
378
// value of that type, recursively call decode to populate that new value, and
379
// then store that value into the interface{}.
380
func (d *decoder) decodeAny(val Value, into reflect.Value) error {
381
var ptr reflect.Value
382
383
switch val.Type() {
384
case TypeNull:
385
into.Set(reflect.Zero(into.Type()))
386
return nil
387
388
case TypeNumber:
389
var v = val.Number().Float()
390
ptr = reflect.ValueOf(&v)
391
392
case TypeArray:
393
var v []interface{}
394
ptr = reflect.ValueOf(&v)
395
396
case TypeObject:
397
var v map[string]interface{}
398
ptr = reflect.ValueOf(&v)
399
400
case TypeBool:
401
var v bool
402
ptr = reflect.ValueOf(&v)
403
404
case TypeString:
405
var v string
406
ptr = reflect.ValueOf(&v)
407
408
case TypeFunction, TypeCapsule:
409
// Functions and capsules must be directly assigned since there's no
410
// "generic" representation for either.
411
//
412
// We retain the pointer if we were given a pointer.
413
414
if val.rv.CanAddr() {
415
into.Set(val.rv.Addr())
416
return nil
417
}
418
419
into.Set(val.rv)
420
return nil
421
422
default:
423
panic("river/value: unreachable")
424
}
425
426
if err := d.decode(val, ptr); err != nil {
427
return err
428
}
429
into.Set(ptr.Elem())
430
return nil
431
}
432
433
func (d *decoder) decodeArray(val Value, rt reflect.Value) error {
434
switch rt.Kind() {
435
case reflect.Slice:
436
res := reflect.MakeSlice(rt.Type(), val.Len(), val.Len())
437
for i := 0; i < val.Len(); i++ {
438
// Decode the original elements into the new elements.
439
if err := d.decode(val.Index(i), res.Index(i)); err != nil {
440
return ElementError{Value: val, Index: i, Inner: err}
441
}
442
}
443
rt.Set(res)
444
445
case reflect.Array:
446
res := reflect.New(rt.Type()).Elem()
447
448
if val.Len() != res.Len() {
449
return Error{
450
Value: val,
451
Inner: fmt.Errorf("array must have exactly %d elements, got %d", res.Len(), val.Len()),
452
}
453
}
454
455
for i := 0; i < val.Len(); i++ {
456
if err := d.decode(val.Index(i), res.Index(i)); err != nil {
457
return ElementError{Value: val, Index: i, Inner: err}
458
}
459
}
460
rt.Set(res)
461
462
default:
463
panic(fmt.Sprintf("river/value: unexpected array type %s", val.rv.Kind()))
464
}
465
466
return nil
467
}
468
469
func (d *decoder) decodeObject(val Value, rt reflect.Value) error {
470
switch rt.Kind() {
471
case reflect.Struct:
472
targetTags := getCachedTags(rt.Type())
473
return d.decodeObjectToStruct(val, rt, targetTags, false)
474
475
case reflect.Slice, reflect.Array: // Slice of labeled blocks
476
keys := val.Keys()
477
478
var res reflect.Value
479
480
if rt.Kind() == reflect.Slice {
481
res = reflect.MakeSlice(rt.Type(), len(keys), len(keys))
482
} else { // Array
483
res = reflect.New(rt.Type()).Elem()
484
485
if res.Len() != len(keys) {
486
return Error{
487
Value: val,
488
Inner: fmt.Errorf("object must have exactly %d keys, got %d", res.Len(), len(keys)),
489
}
490
}
491
}
492
493
fields := getCachedTags(rt.Type().Elem())
494
labelField, _ := fields.LabelField()
495
496
for i, key := range keys {
497
// First decode the key into the label.
498
elem := res.Index(i)
499
reflectutil.GetOrAlloc(elem, labelField).Set(reflect.ValueOf(key))
500
501
// Now decode the inner object.
502
value, _ := val.Key(key)
503
if err := d.decodeObjectToStruct(value, elem, fields, true); err != nil {
504
return FieldError{Value: val, Field: key, Inner: err}
505
}
506
}
507
rt.Set(res)
508
509
case reflect.Map:
510
if rt.Type().Key() != goString {
511
// Maps with non-string types are treated as capsules and can't be
512
// decoded from maps.
513
return TypeError{Value: val, Expected: RiverType(rt.Type())}
514
}
515
516
res := reflect.MakeMapWithSize(rt.Type(), val.Len())
517
518
// Create a shared value to decode each element into. This will be zeroed
519
// out for each key, and then copied when setting the map index.
520
into := reflect.New(rt.Type().Elem()).Elem()
521
intoZero := reflect.Zero(into.Type())
522
523
for i, key := range val.Keys() {
524
// We ignore the ok value because we know it exists.
525
value, _ := val.Key(key)
526
527
// Zero out the value if it was decoded in the previous loop.
528
if i > 0 {
529
into.Set(intoZero)
530
}
531
// Decode into our element.
532
if err := d.decode(value, into); err != nil {
533
return FieldError{Value: val, Field: key, Inner: err}
534
}
535
536
// Then set the map index.
537
res.SetMapIndex(reflect.ValueOf(key), into)
538
}
539
540
rt.Set(res)
541
542
default:
543
panic(fmt.Sprintf("river/value: unexpected target type %s", rt.Kind()))
544
}
545
546
return nil
547
}
548
549
func (d *decoder) decodeObjectToStruct(val Value, rt reflect.Value, fields *objectFields, decodedLabel bool) error {
550
// TODO(rfratto): this needs to check for required keys being set
551
552
for _, key := range val.Keys() {
553
// We ignore the ok value because we know it exists.
554
value, _ := val.Key(key)
555
556
// Struct labels should be decoded first, since objects are wrapped in
557
// labels. If we have yet to decode the label, decode it now.
558
if lf, ok := fields.LabelField(); ok && !decodedLabel {
559
// Safety check: if the inner field isn't an object, there's something
560
// wrong here. It's unclear if a user can craft an expression that hits
561
// this case, but it's left in for safety.
562
if value.Type() != TypeObject {
563
return FieldError{
564
Value: val,
565
Field: key,
566
Inner: TypeError{Value: value, Expected: TypeObject},
567
}
568
}
569
570
// Decode the key into the label.
571
reflectutil.GetOrAlloc(rt, lf).Set(reflect.ValueOf(key))
572
573
// ...and then code the rest of the object.
574
if err := d.decodeObjectToStruct(value, rt, fields, true); err != nil {
575
return err
576
}
577
continue
578
}
579
580
switch fields.Has(key) {
581
case objectKeyTypeInvalid:
582
return MissingKeyError{Value: value, Missing: key}
583
case objectKeyTypeNestedField: // Block with multiple name fragments
584
next, _ := fields.NestedField(key)
585
// Recurse the call with the inner value.
586
if err := d.decodeObjectToStruct(value, rt, next, decodedLabel); err != nil {
587
return err
588
}
589
case objectKeyTypeField: // Single-name fragment
590
targetField, _ := fields.Field(key)
591
targetValue := reflectutil.GetOrAlloc(rt, targetField)
592
593
if err := d.decode(value, targetValue); err != nil {
594
return FieldError{Value: val, Field: key, Inner: err}
595
}
596
}
597
}
598
599
return nil
600
}
601
602