mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 20:42:26 -06:00 
			
		
		
		
	
		
			
	
	
		
			453 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			453 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// Copyright The OpenTelemetry Authors
							 | 
						||
| 
								 | 
							
								// SPDX-License-Identifier: Apache-2.0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//go:generate stringer -type=ValueKind -trimprefix=ValueKind
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package telemetry
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"bytes"
							 | 
						||
| 
								 | 
							
									"cmp"
							 | 
						||
| 
								 | 
							
									"encoding/base64"
							 | 
						||
| 
								 | 
							
									"encoding/json"
							 | 
						||
| 
								 | 
							
									"errors"
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
									"io"
							 | 
						||
| 
								 | 
							
									"math"
							 | 
						||
| 
								 | 
							
									"slices"
							 | 
						||
| 
								 | 
							
									"strconv"
							 | 
						||
| 
								 | 
							
									"unsafe"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// A Value represents a structured value.
							 | 
						||
| 
								 | 
							
								// A zero value is valid and represents an empty value.
							 | 
						||
| 
								 | 
							
								type Value struct {
							 | 
						||
| 
								 | 
							
									// Ensure forward compatibility by explicitly making this not comparable.
							 | 
						||
| 
								 | 
							
									noCmp [0]func() //nolint: unused  // This is indeed used.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// num holds the value for Int64, Float64, and Bool. It holds the length
							 | 
						||
| 
								 | 
							
									// for String, Bytes, Slice, Map.
							 | 
						||
| 
								 | 
							
									num uint64
							 | 
						||
| 
								 | 
							
									// any holds either the KindBool, KindInt64, KindFloat64, stringptr,
							 | 
						||
| 
								 | 
							
									// bytesptr, sliceptr, or mapptr. If KindBool, KindInt64, or KindFloat64
							 | 
						||
| 
								 | 
							
									// then the value of Value is in num as described above. Otherwise, it
							 | 
						||
| 
								 | 
							
									// contains the value wrapped in the appropriate type.
							 | 
						||
| 
								 | 
							
									any any
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type (
							 | 
						||
| 
								 | 
							
									// sliceptr represents a value in Value.any for KindString Values.
							 | 
						||
| 
								 | 
							
									stringptr *byte
							 | 
						||
| 
								 | 
							
									// bytesptr represents a value in Value.any for KindBytes Values.
							 | 
						||
| 
								 | 
							
									bytesptr *byte
							 | 
						||
| 
								 | 
							
									// sliceptr represents a value in Value.any for KindSlice Values.
							 | 
						||
| 
								 | 
							
									sliceptr *Value
							 | 
						||
| 
								 | 
							
									// mapptr represents a value in Value.any for KindMap Values.
							 | 
						||
| 
								 | 
							
									mapptr *Attr
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ValueKind is the kind of a [Value].
							 | 
						||
| 
								 | 
							
								type ValueKind int
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ValueKind values.
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									ValueKindEmpty ValueKind = iota
							 | 
						||
| 
								 | 
							
									ValueKindBool
							 | 
						||
| 
								 | 
							
									ValueKindFloat64
							 | 
						||
| 
								 | 
							
									ValueKindInt64
							 | 
						||
| 
								 | 
							
									ValueKindString
							 | 
						||
| 
								 | 
							
									ValueKindBytes
							 | 
						||
| 
								 | 
							
									ValueKindSlice
							 | 
						||
| 
								 | 
							
									ValueKindMap
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var valueKindStrings = []string{
							 | 
						||
| 
								 | 
							
									"Empty",
							 | 
						||
| 
								 | 
							
									"Bool",
							 | 
						||
| 
								 | 
							
									"Float64",
							 | 
						||
| 
								 | 
							
									"Int64",
							 | 
						||
| 
								 | 
							
									"String",
							 | 
						||
| 
								 | 
							
									"Bytes",
							 | 
						||
| 
								 | 
							
									"Slice",
							 | 
						||
| 
								 | 
							
									"Map",
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (k ValueKind) String() string {
							 | 
						||
| 
								 | 
							
									if k >= 0 && int(k) < len(valueKindStrings) {
							 | 
						||
| 
								 | 
							
										return valueKindStrings[k]
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return "<unknown telemetry.ValueKind>"
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// StringValue returns a new [Value] for a string.
							 | 
						||
| 
								 | 
							
								func StringValue(v string) Value {
							 | 
						||
| 
								 | 
							
									return Value{
							 | 
						||
| 
								 | 
							
										num: uint64(len(v)),
							 | 
						||
| 
								 | 
							
										any: stringptr(unsafe.StringData(v)),
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// IntValue returns a [Value] for an int.
							 | 
						||
| 
								 | 
							
								func IntValue(v int) Value { return Int64Value(int64(v)) }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Int64Value returns a [Value] for an int64.
							 | 
						||
| 
								 | 
							
								func Int64Value(v int64) Value {
							 | 
						||
| 
								 | 
							
									return Value{num: uint64(v), any: ValueKindInt64}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Float64Value returns a [Value] for a float64.
							 | 
						||
| 
								 | 
							
								func Float64Value(v float64) Value {
							 | 
						||
| 
								 | 
							
									return Value{num: math.Float64bits(v), any: ValueKindFloat64}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// BoolValue returns a [Value] for a bool.
							 | 
						||
| 
								 | 
							
								func BoolValue(v bool) Value { //nolint:revive // Not a control flag.
							 | 
						||
| 
								 | 
							
									var n uint64
							 | 
						||
| 
								 | 
							
									if v {
							 | 
						||
| 
								 | 
							
										n = 1
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return Value{num: n, any: ValueKindBool}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// BytesValue returns a [Value] for a byte slice. The passed slice must not be
							 | 
						||
| 
								 | 
							
								// changed after it is passed.
							 | 
						||
| 
								 | 
							
								func BytesValue(v []byte) Value {
							 | 
						||
| 
								 | 
							
									return Value{
							 | 
						||
| 
								 | 
							
										num: uint64(len(v)),
							 | 
						||
| 
								 | 
							
										any: bytesptr(unsafe.SliceData(v)),
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// SliceValue returns a [Value] for a slice of [Value]. The passed slice must
							 | 
						||
| 
								 | 
							
								// not be changed after it is passed.
							 | 
						||
| 
								 | 
							
								func SliceValue(vs ...Value) Value {
							 | 
						||
| 
								 | 
							
									return Value{
							 | 
						||
| 
								 | 
							
										num: uint64(len(vs)),
							 | 
						||
| 
								 | 
							
										any: sliceptr(unsafe.SliceData(vs)),
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// MapValue returns a new [Value] for a slice of key-value pairs. The passed
							 | 
						||
| 
								 | 
							
								// slice must not be changed after it is passed.
							 | 
						||
| 
								 | 
							
								func MapValue(kvs ...Attr) Value {
							 | 
						||
| 
								 | 
							
									return Value{
							 | 
						||
| 
								 | 
							
										num: uint64(len(kvs)),
							 | 
						||
| 
								 | 
							
										any: mapptr(unsafe.SliceData(kvs)),
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AsString returns the value held by v as a string.
							 | 
						||
| 
								 | 
							
								func (v Value) AsString() string {
							 | 
						||
| 
								 | 
							
									if sp, ok := v.any.(stringptr); ok {
							 | 
						||
| 
								 | 
							
										return unsafe.String(sp, v.num)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// TODO: error handle
							 | 
						||
| 
								 | 
							
									return ""
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// asString returns the value held by v as a string. It will panic if the Value
							 | 
						||
| 
								 | 
							
								// is not KindString.
							 | 
						||
| 
								 | 
							
								func (v Value) asString() string {
							 | 
						||
| 
								 | 
							
									return unsafe.String(v.any.(stringptr), v.num)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AsInt64 returns the value held by v as an int64.
							 | 
						||
| 
								 | 
							
								func (v Value) AsInt64() int64 {
							 | 
						||
| 
								 | 
							
									if v.Kind() != ValueKindInt64 {
							 | 
						||
| 
								 | 
							
										// TODO: error handle
							 | 
						||
| 
								 | 
							
										return 0
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return v.asInt64()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// asInt64 returns the value held by v as an int64. If v is not of KindInt64,
							 | 
						||
| 
								 | 
							
								// this will return garbage.
							 | 
						||
| 
								 | 
							
								func (v Value) asInt64() int64 {
							 | 
						||
| 
								 | 
							
									// Assumes v.num was a valid int64 (overflow not checked).
							 | 
						||
| 
								 | 
							
									return int64(v.num) // nolint: gosec
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AsBool returns the value held by v as a bool.
							 | 
						||
| 
								 | 
							
								func (v Value) AsBool() bool {
							 | 
						||
| 
								 | 
							
									if v.Kind() != ValueKindBool {
							 | 
						||
| 
								 | 
							
										// TODO: error handle
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return v.asBool()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// asBool returns the value held by v as a bool. If v is not of KindBool, this
							 | 
						||
| 
								 | 
							
								// will return garbage.
							 | 
						||
| 
								 | 
							
								func (v Value) asBool() bool { return v.num == 1 }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AsFloat64 returns the value held by v as a float64.
							 | 
						||
| 
								 | 
							
								func (v Value) AsFloat64() float64 {
							 | 
						||
| 
								 | 
							
									if v.Kind() != ValueKindFloat64 {
							 | 
						||
| 
								 | 
							
										// TODO: error handle
							 | 
						||
| 
								 | 
							
										return 0
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return v.asFloat64()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// asFloat64 returns the value held by v as a float64. If v is not of
							 | 
						||
| 
								 | 
							
								// KindFloat64, this will return garbage.
							 | 
						||
| 
								 | 
							
								func (v Value) asFloat64() float64 { return math.Float64frombits(v.num) }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AsBytes returns the value held by v as a []byte.
							 | 
						||
| 
								 | 
							
								func (v Value) AsBytes() []byte {
							 | 
						||
| 
								 | 
							
									if sp, ok := v.any.(bytesptr); ok {
							 | 
						||
| 
								 | 
							
										return unsafe.Slice((*byte)(sp), v.num)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// TODO: error handle
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// asBytes returns the value held by v as a []byte. It will panic if the Value
							 | 
						||
| 
								 | 
							
								// is not KindBytes.
							 | 
						||
| 
								 | 
							
								func (v Value) asBytes() []byte {
							 | 
						||
| 
								 | 
							
									return unsafe.Slice((*byte)(v.any.(bytesptr)), v.num)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AsSlice returns the value held by v as a []Value.
							 | 
						||
| 
								 | 
							
								func (v Value) AsSlice() []Value {
							 | 
						||
| 
								 | 
							
									if sp, ok := v.any.(sliceptr); ok {
							 | 
						||
| 
								 | 
							
										return unsafe.Slice((*Value)(sp), v.num)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// TODO: error handle
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// asSlice returns the value held by v as a []Value. It will panic if the Value
							 | 
						||
| 
								 | 
							
								// is not KindSlice.
							 | 
						||
| 
								 | 
							
								func (v Value) asSlice() []Value {
							 | 
						||
| 
								 | 
							
									return unsafe.Slice((*Value)(v.any.(sliceptr)), v.num)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AsMap returns the value held by v as a []Attr.
							 | 
						||
| 
								 | 
							
								func (v Value) AsMap() []Attr {
							 | 
						||
| 
								 | 
							
									if sp, ok := v.any.(mapptr); ok {
							 | 
						||
| 
								 | 
							
										return unsafe.Slice((*Attr)(sp), v.num)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// TODO: error handle
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// asMap returns the value held by v as a []Attr. It will panic if the
							 | 
						||
| 
								 | 
							
								// Value is not KindMap.
							 | 
						||
| 
								 | 
							
								func (v Value) asMap() []Attr {
							 | 
						||
| 
								 | 
							
									return unsafe.Slice((*Attr)(v.any.(mapptr)), v.num)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Kind returns the Kind of v.
							 | 
						||
| 
								 | 
							
								func (v Value) Kind() ValueKind {
							 | 
						||
| 
								 | 
							
									switch x := v.any.(type) {
							 | 
						||
| 
								 | 
							
									case ValueKind:
							 | 
						||
| 
								 | 
							
										return x
							 | 
						||
| 
								 | 
							
									case stringptr:
							 | 
						||
| 
								 | 
							
										return ValueKindString
							 | 
						||
| 
								 | 
							
									case bytesptr:
							 | 
						||
| 
								 | 
							
										return ValueKindBytes
							 | 
						||
| 
								 | 
							
									case sliceptr:
							 | 
						||
| 
								 | 
							
										return ValueKindSlice
							 | 
						||
| 
								 | 
							
									case mapptr:
							 | 
						||
| 
								 | 
							
										return ValueKindMap
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										return ValueKindEmpty
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Empty returns if v does not hold any value.
							 | 
						||
| 
								 | 
							
								func (v Value) Empty() bool { return v.Kind() == ValueKindEmpty }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Equal returns if v is equal to w.
							 | 
						||
| 
								 | 
							
								func (v Value) Equal(w Value) bool {
							 | 
						||
| 
								 | 
							
									k1 := v.Kind()
							 | 
						||
| 
								 | 
							
									k2 := w.Kind()
							 | 
						||
| 
								 | 
							
									if k1 != k2 {
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									switch k1 {
							 | 
						||
| 
								 | 
							
									case ValueKindInt64, ValueKindBool:
							 | 
						||
| 
								 | 
							
										return v.num == w.num
							 | 
						||
| 
								 | 
							
									case ValueKindString:
							 | 
						||
| 
								 | 
							
										return v.asString() == w.asString()
							 | 
						||
| 
								 | 
							
									case ValueKindFloat64:
							 | 
						||
| 
								 | 
							
										return v.asFloat64() == w.asFloat64()
							 | 
						||
| 
								 | 
							
									case ValueKindSlice:
							 | 
						||
| 
								 | 
							
										return slices.EqualFunc(v.asSlice(), w.asSlice(), Value.Equal)
							 | 
						||
| 
								 | 
							
									case ValueKindMap:
							 | 
						||
| 
								 | 
							
										sv := sortMap(v.asMap())
							 | 
						||
| 
								 | 
							
										sw := sortMap(w.asMap())
							 | 
						||
| 
								 | 
							
										return slices.EqualFunc(sv, sw, Attr.Equal)
							 | 
						||
| 
								 | 
							
									case ValueKindBytes:
							 | 
						||
| 
								 | 
							
										return bytes.Equal(v.asBytes(), w.asBytes())
							 | 
						||
| 
								 | 
							
									case ValueKindEmpty:
							 | 
						||
| 
								 | 
							
										return true
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										// TODO: error handle
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func sortMap(m []Attr) []Attr {
							 | 
						||
| 
								 | 
							
									sm := make([]Attr, len(m))
							 | 
						||
| 
								 | 
							
									copy(sm, m)
							 | 
						||
| 
								 | 
							
									slices.SortFunc(sm, func(a, b Attr) int {
							 | 
						||
| 
								 | 
							
										return cmp.Compare(a.Key, b.Key)
							 | 
						||
| 
								 | 
							
									})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return sm
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// String returns Value's value as a string, formatted like [fmt.Sprint].
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The returned string is meant for debugging;
							 | 
						||
| 
								 | 
							
								// the string representation is not stable.
							 | 
						||
| 
								 | 
							
								func (v Value) String() string {
							 | 
						||
| 
								 | 
							
									switch v.Kind() {
							 | 
						||
| 
								 | 
							
									case ValueKindString:
							 | 
						||
| 
								 | 
							
										return v.asString()
							 | 
						||
| 
								 | 
							
									case ValueKindInt64:
							 | 
						||
| 
								 | 
							
										// Assumes v.num was a valid int64 (overflow not checked).
							 | 
						||
| 
								 | 
							
										return strconv.FormatInt(int64(v.num), 10) // nolint: gosec
							 | 
						||
| 
								 | 
							
									case ValueKindFloat64:
							 | 
						||
| 
								 | 
							
										return strconv.FormatFloat(v.asFloat64(), 'g', -1, 64)
							 | 
						||
| 
								 | 
							
									case ValueKindBool:
							 | 
						||
| 
								 | 
							
										return strconv.FormatBool(v.asBool())
							 | 
						||
| 
								 | 
							
									case ValueKindBytes:
							 | 
						||
| 
								 | 
							
										return fmt.Sprint(v.asBytes())
							 | 
						||
| 
								 | 
							
									case ValueKindMap:
							 | 
						||
| 
								 | 
							
										return fmt.Sprint(v.asMap())
							 | 
						||
| 
								 | 
							
									case ValueKindSlice:
							 | 
						||
| 
								 | 
							
										return fmt.Sprint(v.asSlice())
							 | 
						||
| 
								 | 
							
									case ValueKindEmpty:
							 | 
						||
| 
								 | 
							
										return "<nil>"
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										// Try to handle this as gracefully as possible.
							 | 
						||
| 
								 | 
							
										//
							 | 
						||
| 
								 | 
							
										// Don't panic here. The goal here is to have developers find this
							 | 
						||
| 
								 | 
							
										// first if a slog.Kind is is not handled. It is
							 | 
						||
| 
								 | 
							
										// preferable to have user's open issue asking why their attributes
							 | 
						||
| 
								 | 
							
										// have a "unhandled: " prefix than say that their code is panicking.
							 | 
						||
| 
								 | 
							
										return fmt.Sprintf("<unhandled telemetry.ValueKind: %s>", v.Kind())
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// MarshalJSON encodes v into OTLP formatted JSON.
							 | 
						||
| 
								 | 
							
								func (v *Value) MarshalJSON() ([]byte, error) {
							 | 
						||
| 
								 | 
							
									switch v.Kind() {
							 | 
						||
| 
								 | 
							
									case ValueKindString:
							 | 
						||
| 
								 | 
							
										return json.Marshal(struct {
							 | 
						||
| 
								 | 
							
											Value string `json:"stringValue"`
							 | 
						||
| 
								 | 
							
										}{v.asString()})
							 | 
						||
| 
								 | 
							
									case ValueKindInt64:
							 | 
						||
| 
								 | 
							
										return json.Marshal(struct {
							 | 
						||
| 
								 | 
							
											Value string `json:"intValue"`
							 | 
						||
| 
								 | 
							
										}{strconv.FormatInt(int64(v.num), 10)})
							 | 
						||
| 
								 | 
							
									case ValueKindFloat64:
							 | 
						||
| 
								 | 
							
										return json.Marshal(struct {
							 | 
						||
| 
								 | 
							
											Value float64 `json:"doubleValue"`
							 | 
						||
| 
								 | 
							
										}{v.asFloat64()})
							 | 
						||
| 
								 | 
							
									case ValueKindBool:
							 | 
						||
| 
								 | 
							
										return json.Marshal(struct {
							 | 
						||
| 
								 | 
							
											Value bool `json:"boolValue"`
							 | 
						||
| 
								 | 
							
										}{v.asBool()})
							 | 
						||
| 
								 | 
							
									case ValueKindBytes:
							 | 
						||
| 
								 | 
							
										return json.Marshal(struct {
							 | 
						||
| 
								 | 
							
											Value []byte `json:"bytesValue"`
							 | 
						||
| 
								 | 
							
										}{v.asBytes()})
							 | 
						||
| 
								 | 
							
									case ValueKindMap:
							 | 
						||
| 
								 | 
							
										return json.Marshal(struct {
							 | 
						||
| 
								 | 
							
											Value struct {
							 | 
						||
| 
								 | 
							
												Values []Attr `json:"values"`
							 | 
						||
| 
								 | 
							
											} `json:"kvlistValue"`
							 | 
						||
| 
								 | 
							
										}{struct {
							 | 
						||
| 
								 | 
							
											Values []Attr `json:"values"`
							 | 
						||
| 
								 | 
							
										}{v.asMap()}})
							 | 
						||
| 
								 | 
							
									case ValueKindSlice:
							 | 
						||
| 
								 | 
							
										return json.Marshal(struct {
							 | 
						||
| 
								 | 
							
											Value struct {
							 | 
						||
| 
								 | 
							
												Values []Value `json:"values"`
							 | 
						||
| 
								 | 
							
											} `json:"arrayValue"`
							 | 
						||
| 
								 | 
							
										}{struct {
							 | 
						||
| 
								 | 
							
											Values []Value `json:"values"`
							 | 
						||
| 
								 | 
							
										}{v.asSlice()}})
							 | 
						||
| 
								 | 
							
									case ValueKindEmpty:
							 | 
						||
| 
								 | 
							
										return nil, nil
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										return nil, fmt.Errorf("unknown Value kind: %s", v.Kind().String())
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// UnmarshalJSON decodes the OTLP formatted JSON contained in data into v.
							 | 
						||
| 
								 | 
							
								func (v *Value) UnmarshalJSON(data []byte) error {
							 | 
						||
| 
								 | 
							
									decoder := json.NewDecoder(bytes.NewReader(data))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									t, err := decoder.Token()
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if t != json.Delim('{') {
							 | 
						||
| 
								 | 
							
										return errors.New("invalid Value type")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for decoder.More() {
							 | 
						||
| 
								 | 
							
										keyIface, err := decoder.Token()
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											if errors.Is(err, io.EOF) {
							 | 
						||
| 
								 | 
							
												// Empty.
							 | 
						||
| 
								 | 
							
												return nil
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											return err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										key, ok := keyIface.(string)
							 | 
						||
| 
								 | 
							
										if !ok {
							 | 
						||
| 
								 | 
							
											return fmt.Errorf("invalid Value key: %#v", keyIface)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										switch key {
							 | 
						||
| 
								 | 
							
										case "stringValue", "string_value":
							 | 
						||
| 
								 | 
							
											var val string
							 | 
						||
| 
								 | 
							
											err = decoder.Decode(&val)
							 | 
						||
| 
								 | 
							
											*v = StringValue(val)
							 | 
						||
| 
								 | 
							
										case "boolValue", "bool_value":
							 | 
						||
| 
								 | 
							
											var val bool
							 | 
						||
| 
								 | 
							
											err = decoder.Decode(&val)
							 | 
						||
| 
								 | 
							
											*v = BoolValue(val)
							 | 
						||
| 
								 | 
							
										case "intValue", "int_value":
							 | 
						||
| 
								 | 
							
											var val protoInt64
							 | 
						||
| 
								 | 
							
											err = decoder.Decode(&val)
							 | 
						||
| 
								 | 
							
											*v = Int64Value(val.Int64())
							 | 
						||
| 
								 | 
							
										case "doubleValue", "double_value":
							 | 
						||
| 
								 | 
							
											var val float64
							 | 
						||
| 
								 | 
							
											err = decoder.Decode(&val)
							 | 
						||
| 
								 | 
							
											*v = Float64Value(val)
							 | 
						||
| 
								 | 
							
										case "bytesValue", "bytes_value":
							 | 
						||
| 
								 | 
							
											var val64 string
							 | 
						||
| 
								 | 
							
											if err := decoder.Decode(&val64); err != nil {
							 | 
						||
| 
								 | 
							
												return err
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											var val []byte
							 | 
						||
| 
								 | 
							
											val, err = base64.StdEncoding.DecodeString(val64)
							 | 
						||
| 
								 | 
							
											*v = BytesValue(val)
							 | 
						||
| 
								 | 
							
										case "arrayValue", "array_value":
							 | 
						||
| 
								 | 
							
											var val struct{ Values []Value }
							 | 
						||
| 
								 | 
							
											err = decoder.Decode(&val)
							 | 
						||
| 
								 | 
							
											*v = SliceValue(val.Values...)
							 | 
						||
| 
								 | 
							
										case "kvlistValue", "kvlist_value":
							 | 
						||
| 
								 | 
							
											var val struct{ Values []Attr }
							 | 
						||
| 
								 | 
							
											err = decoder.Decode(&val)
							 | 
						||
| 
								 | 
							
											*v = MapValue(val.Values...)
							 | 
						||
| 
								 | 
							
										default:
							 | 
						||
| 
								 | 
							
											// Skip unknown.
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										// Use first valid. Ignore the rest.
							 | 
						||
| 
								 | 
							
										return err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Only unknown fields. Return nil without unmarshaling any value.
							 | 
						||
| 
								 | 
							
									return nil
							 | 
						||
| 
								 | 
							
								}
							 |