1// Copyright The OpenTelemetry Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package label // import "go.opentelemetry.io/otel/label"
16
17import (
18	"encoding/json"
19	"fmt"
20	"reflect"
21	"strconv"
22	"unsafe"
23
24	"go.opentelemetry.io/otel/internal"
25)
26
27//go:generate stringer -type=Type
28
29// Type describes the type of the data Value holds.
30type Type int
31
32// Value represents the value part in key-value pairs.
33type Value struct {
34	vtype    Type
35	numeric  uint64
36	stringly string
37	// TODO Lazy value type?
38
39	array interface{}
40}
41
42const (
43	// INVALID is used for a Value with no value set.
44	INVALID Type = iota
45	// BOOL is a boolean Type Value.
46	BOOL
47	// INT32 is a 32-bit signed integral Type Value.
48	INT32
49	// INT64 is a 64-bit signed integral Type Value.
50	INT64
51	// UINT32 is a 32-bit unsigned integral Type Value.
52	UINT32
53	// UINT64 is a 64-bit unsigned integral Type Value.
54	UINT64
55	// FLOAT32 is a 32-bit floating point Type Value.
56	FLOAT32
57	// FLOAT64 is a 64-bit floating point Type Value.
58	FLOAT64
59	// STRING is a string Type Value.
60	STRING
61	// ARRAY is an array Type Value used to store 1-dimensional slices or
62	// arrays of bool, int, int32, int64, uint, uint32, uint64, float,
63	// float32, float64, or string types.
64	ARRAY
65)
66
67// BoolValue creates a BOOL Value.
68func BoolValue(v bool) Value {
69	return Value{
70		vtype:   BOOL,
71		numeric: internal.BoolToRaw(v),
72	}
73}
74
75// Int64Value creates an INT64 Value.
76func Int64Value(v int64) Value {
77	return Value{
78		vtype:   INT64,
79		numeric: internal.Int64ToRaw(v),
80	}
81}
82
83// Uint64Value creates a UINT64 Value.
84func Uint64Value(v uint64) Value {
85	return Value{
86		vtype:   UINT64,
87		numeric: internal.Uint64ToRaw(v),
88	}
89}
90
91// Float64Value creates a FLOAT64 Value.
92func Float64Value(v float64) Value {
93	return Value{
94		vtype:   FLOAT64,
95		numeric: internal.Float64ToRaw(v),
96	}
97}
98
99// Int32Value creates an INT32 Value.
100func Int32Value(v int32) Value {
101	return Value{
102		vtype:   INT32,
103		numeric: internal.Int32ToRaw(v),
104	}
105}
106
107// Uint32Value creates a UINT32 Value.
108func Uint32Value(v uint32) Value {
109	return Value{
110		vtype:   UINT32,
111		numeric: internal.Uint32ToRaw(v),
112	}
113}
114
115// Float32Value creates a FLOAT32 Value.
116func Float32Value(v float32) Value {
117	return Value{
118		vtype:   FLOAT32,
119		numeric: internal.Float32ToRaw(v),
120	}
121}
122
123// StringValue creates a STRING Value.
124func StringValue(v string) Value {
125	return Value{
126		vtype:    STRING,
127		stringly: v,
128	}
129}
130
131// IntValue creates either an INT32 or an INT64 Value, depending on whether
132// the int type is 32 or 64 bits wide.
133func IntValue(v int) Value {
134	if unsafe.Sizeof(v) == 4 {
135		return Int32Value(int32(v))
136	}
137	return Int64Value(int64(v))
138}
139
140// UintValue creates either a UINT32 or a UINT64 Value, depending on whether
141// the uint type is 32 or 64 bits wide.
142func UintValue(v uint) Value {
143	if unsafe.Sizeof(v) == 4 {
144		return Uint32Value(uint32(v))
145	}
146	return Uint64Value(uint64(v))
147}
148
149// ArrayValue creates an ARRAY value from an array or slice.
150// Only arrays or slices of bool, int, int32, int64, uint, uint32, uint64,
151// float, float32, float64, or string types are allowed. Specifically, arrays
152// and slices can not contain other arrays, slices, structs, or non-standard
153// types. If the passed value is not an array or slice of these types an
154// INVALID value is returned.
155func ArrayValue(v interface{}) Value {
156	switch reflect.TypeOf(v).Kind() {
157	case reflect.Array, reflect.Slice:
158		// get array type regardless of dimensions
159		typ := reflect.TypeOf(v).Elem()
160		kind := typ.Kind()
161		switch kind {
162		case reflect.Bool, reflect.Int, reflect.Int32, reflect.Int64,
163			reflect.Float32, reflect.Float64, reflect.String,
164			reflect.Uint, reflect.Uint32, reflect.Uint64:
165			val := reflect.ValueOf(v)
166			length := val.Len()
167			frozen := reflect.Indirect(reflect.New(reflect.ArrayOf(length, typ)))
168			reflect.Copy(frozen, val)
169			return Value{
170				vtype: ARRAY,
171				array: frozen.Interface(),
172			}
173		default:
174			return Value{vtype: INVALID}
175		}
176	}
177	return Value{vtype: INVALID}
178}
179
180// Type returns a type of the Value.
181func (v Value) Type() Type {
182	return v.vtype
183}
184
185// AsBool returns the bool value. Make sure that the Value's type is
186// BOOL.
187func (v Value) AsBool() bool {
188	return internal.RawToBool(v.numeric)
189}
190
191// AsInt32 returns the int32 value. Make sure that the Value's type is
192// INT32.
193func (v Value) AsInt32() int32 {
194	return internal.RawToInt32(v.numeric)
195}
196
197// AsInt64 returns the int64 value. Make sure that the Value's type is
198// INT64.
199func (v Value) AsInt64() int64 {
200	return internal.RawToInt64(v.numeric)
201}
202
203// AsUint32 returns the uint32 value. Make sure that the Value's type
204// is UINT32.
205func (v Value) AsUint32() uint32 {
206	return internal.RawToUint32(v.numeric)
207}
208
209// AsUint64 returns the uint64 value. Make sure that the Value's type is
210// UINT64.
211func (v Value) AsUint64() uint64 {
212	return internal.RawToUint64(v.numeric)
213}
214
215// AsFloat32 returns the float32 value. Make sure that the Value's
216// type is FLOAT32.
217func (v Value) AsFloat32() float32 {
218	return internal.RawToFloat32(v.numeric)
219}
220
221// AsFloat64 returns the float64 value. Make sure that the Value's
222// type is FLOAT64.
223func (v Value) AsFloat64() float64 {
224	return internal.RawToFloat64(v.numeric)
225}
226
227// AsString returns the string value. Make sure that the Value's type
228// is STRING.
229func (v Value) AsString() string {
230	return v.stringly
231}
232
233// AsArray returns the array Value as an interface{}.
234func (v Value) AsArray() interface{} {
235	return v.array
236}
237
238type unknownValueType struct{}
239
240// AsInterface returns Value's data as interface{}.
241func (v Value) AsInterface() interface{} {
242	switch v.Type() {
243	case ARRAY:
244		return v.AsArray()
245	case BOOL:
246		return v.AsBool()
247	case INT32:
248		return v.AsInt32()
249	case INT64:
250		return v.AsInt64()
251	case UINT32:
252		return v.AsUint32()
253	case UINT64:
254		return v.AsUint64()
255	case FLOAT32:
256		return v.AsFloat32()
257	case FLOAT64:
258		return v.AsFloat64()
259	case STRING:
260		return v.stringly
261	}
262	return unknownValueType{}
263}
264
265// Emit returns a string representation of Value's data.
266func (v Value) Emit() string {
267	switch v.Type() {
268	case ARRAY:
269		return fmt.Sprint(v.array)
270	case BOOL:
271		return strconv.FormatBool(v.AsBool())
272	case INT32:
273		return strconv.FormatInt(int64(v.AsInt32()), 10)
274	case INT64:
275		return strconv.FormatInt(v.AsInt64(), 10)
276	case UINT32:
277		return strconv.FormatUint(uint64(v.AsUint32()), 10)
278	case UINT64:
279		return strconv.FormatUint(v.AsUint64(), 10)
280	case FLOAT32:
281		return fmt.Sprint(v.AsFloat32())
282	case FLOAT64:
283		return fmt.Sprint(v.AsFloat64())
284	case STRING:
285		return v.stringly
286	default:
287		return "unknown"
288	}
289}
290
291// MarshalJSON returns the JSON encoding of the Value.
292func (v Value) MarshalJSON() ([]byte, error) {
293	var jsonVal struct {
294		Type  string
295		Value interface{}
296	}
297	jsonVal.Type = v.Type().String()
298	jsonVal.Value = v.AsInterface()
299	return json.Marshal(jsonVal)
300}
301