diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e65a0750..f387a0cb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - [bridge/ot] Fall-back to TextMap carrier when it's not ot.HttpHeaders. (#3679) +### Fixed + +- Ensure `go.opentelemetry.io/otel` does not use generics. (#3723, #3725) + ## [1.13.0/0.36.0] 2023-02-07 ### Added diff --git a/attribute/value.go b/attribute/value.go index 34a4e548d..cb21dd5c0 100644 --- a/attribute/value.go +++ b/attribute/value.go @@ -68,7 +68,7 @@ func BoolValue(v bool) Value { // BoolSliceValue creates a BOOLSLICE Value. func BoolSliceValue(v []bool) Value { - return Value{vtype: BOOLSLICE, slice: attribute.SliceValue(v)} + return Value{vtype: BOOLSLICE, slice: attribute.BoolSliceValue(v)} } // IntValue creates an INT64 Value. @@ -99,7 +99,7 @@ func Int64Value(v int64) Value { // Int64SliceValue creates an INT64SLICE Value. func Int64SliceValue(v []int64) Value { - return Value{vtype: INT64SLICE, slice: attribute.SliceValue(v)} + return Value{vtype: INT64SLICE, slice: attribute.Int64SliceValue(v)} } // Float64Value creates a FLOAT64 Value. @@ -112,7 +112,7 @@ func Float64Value(v float64) Value { // Float64SliceValue creates a FLOAT64SLICE Value. func Float64SliceValue(v []float64) Value { - return Value{vtype: FLOAT64SLICE, slice: attribute.SliceValue(v)} + return Value{vtype: FLOAT64SLICE, slice: attribute.Float64SliceValue(v)} } // StringValue creates a STRING Value. @@ -125,7 +125,7 @@ func StringValue(v string) Value { // StringSliceValue creates a STRINGSLICE Value. func StringSliceValue(v []string) Value { - return Value{vtype: STRINGSLICE, slice: attribute.SliceValue(v)} + return Value{vtype: STRINGSLICE, slice: attribute.StringSliceValue(v)} } // Type returns a type of the Value. @@ -149,7 +149,7 @@ func (v Value) AsBoolSlice() []bool { } func (v Value) asBoolSlice() []bool { - return attribute.AsSlice[bool](v.slice) + return attribute.AsBoolSlice(v.slice) } // AsInt64 returns the int64 value. Make sure that the Value's type is @@ -168,7 +168,7 @@ func (v Value) AsInt64Slice() []int64 { } func (v Value) asInt64Slice() []int64 { - return attribute.AsSlice[int64](v.slice) + return attribute.AsInt64Slice(v.slice) } // AsFloat64 returns the float64 value. Make sure that the Value's @@ -187,7 +187,7 @@ func (v Value) AsFloat64Slice() []float64 { } func (v Value) asFloat64Slice() []float64 { - return attribute.AsSlice[float64](v.slice) + return attribute.AsFloat64Slice(v.slice) } // AsString returns the string value. Make sure that the Value's type @@ -206,7 +206,7 @@ func (v Value) AsStringSlice() []string { } func (v Value) asStringSlice() []string { - return attribute.AsSlice[string](v.slice) + return attribute.AsStringSlice(v.slice) } type unknownValueType struct{} diff --git a/internal/attribute/attribute.go b/internal/attribute/attribute.go index 220348944..622c3ee3f 100644 --- a/internal/attribute/attribute.go +++ b/internal/attribute/attribute.go @@ -22,24 +22,90 @@ import ( "reflect" ) -// SliceValue convert a slice into an array with same elements as slice. -func SliceValue[T bool | int64 | float64 | string](v []T) any { - var zero T +// BoolSliceValue converts a bool slice into an array with same elements as slice. +func BoolSliceValue(v []bool) interface{} { + var zero bool cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))) - copy(cp.Elem().Slice(0, len(v)).Interface().([]T), v) + copy(cp.Elem().Slice(0, len(v)).Interface().([]bool), v) return cp.Elem().Interface() } -// AsSlice convert an array into a slice into with same elements as array. -func AsSlice[T bool | int64 | float64 | string](v any) []T { +// Int64SliceValue converts an int64 slice into an array with same elements as slice. +func Int64SliceValue(v []int64) interface{} { + var zero int64 + cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))) + copy(cp.Elem().Slice(0, len(v)).Interface().([]int64), v) + return cp.Elem().Interface() +} + +// Float64SliceValue converts a float64 slice into an array with same elements as slice. +func Float64SliceValue(v []float64) interface{} { + var zero float64 + cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))) + copy(cp.Elem().Slice(0, len(v)).Interface().([]float64), v) + return cp.Elem().Interface() +} + +// StringSliceValue converts a string slice into an array with same elements as slice. +func StringSliceValue(v []string) interface{} { + var zero string + cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeOf(zero))) + copy(cp.Elem().Slice(0, len(v)).Interface().([]string), v) + return cp.Elem().Interface() +} + +// AsBoolSlice converts a bool array into a slice into with same elements as array. +func AsBoolSlice(v interface{}) []bool { rv := reflect.ValueOf(v) if rv.Type().Kind() != reflect.Array { return nil } - var zero T + var zero bool correctLen := rv.Len() correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero)) cpy := reflect.New(correctType) _ = reflect.Copy(cpy.Elem(), rv) - return cpy.Elem().Slice(0, correctLen).Interface().([]T) + return cpy.Elem().Slice(0, correctLen).Interface().([]bool) +} + +// AsInt64Slice converts an int64 array into a slice into with same elements as array. +func AsInt64Slice(v interface{}) []int64 { + rv := reflect.ValueOf(v) + if rv.Type().Kind() != reflect.Array { + return nil + } + var zero int64 + correctLen := rv.Len() + correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero)) + cpy := reflect.New(correctType) + _ = reflect.Copy(cpy.Elem(), rv) + return cpy.Elem().Slice(0, correctLen).Interface().([]int64) +} + +// AsFloat64Slice converts a float64 array into a slice into with same elements as array. +func AsFloat64Slice(v interface{}) []float64 { + rv := reflect.ValueOf(v) + if rv.Type().Kind() != reflect.Array { + return nil + } + var zero float64 + correctLen := rv.Len() + correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero)) + cpy := reflect.New(correctType) + _ = reflect.Copy(cpy.Elem(), rv) + return cpy.Elem().Slice(0, correctLen).Interface().([]float64) +} + +// AsStringSlice converts a string array into a slice into with same elements as array. +func AsStringSlice(v interface{}) []string { + rv := reflect.ValueOf(v) + if rv.Type().Kind() != reflect.Array { + return nil + } + var zero string + correctLen := rv.Len() + correctType := reflect.ArrayOf(correctLen, reflect.TypeOf(zero)) + cpy := reflect.New(correctType) + _ = reflect.Copy(cpy.Elem(), rv) + return cpy.Elem().Slice(0, correctLen).Interface().([]string) } diff --git a/internal/attribute/attribute_test.go b/internal/attribute/attribute_test.go new file mode 100644 index 000000000..3cba91173 --- /dev/null +++ b/internal/attribute/attribute_test.go @@ -0,0 +1,103 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package attribute + +import ( + "reflect" + "testing" +) + +var wrapFloat64SliceValue = func(v interface{}) interface{} { + if vi, ok := v.([]float64); ok { + return Float64SliceValue(vi) + } + return nil +} + +var wrapInt64SliceValue = func(v interface{}) interface{} { + if vi, ok := v.([]int64); ok { + return Int64SliceValue(vi) + } + return nil +} + +var wrapBoolSliceValue = func(v interface{}) interface{} { + if vi, ok := v.([]bool); ok { + return BoolSliceValue(vi) + } + return nil +} +var wrapStringSliceValue = func(v interface{}) interface{} { + if vi, ok := v.([]string); ok { + return StringSliceValue(vi) + } + return nil +} +var wrapAsBoolSlice = func(v interface{}) interface{} { return AsBoolSlice(v) } +var wrapAsInt64Slice = func(v interface{}) interface{} { return AsInt64Slice(v) } +var wrapAsFloat64Slice = func(v interface{}) interface{} { return AsFloat64Slice(v) } +var wrapAsStringSlice = func(v interface{}) interface{} { return AsStringSlice(v) } + +func TestSliceValue(t *testing.T) { + type args struct { + v interface{} + } + tests := []struct { + name string + args args + want interface{} + fn func(interface{}) interface{} + }{ + { + name: "Float64SliceValue() two items", + args: args{v: []float64{1, 2.3}}, want: [2]float64{1, 2.3}, fn: wrapFloat64SliceValue, + }, + { + name: "Int64SliceValue() two items", + args: args{[]int64{1, 2}}, want: [2]int64{1, 2}, fn: wrapInt64SliceValue, + }, + { + name: "BoolSliceValue() two items", + args: args{v: []bool{true, false}}, want: [2]bool{true, false}, fn: wrapBoolSliceValue, + }, + { + name: "StringSliceValue() two items", + args: args{[]string{"123", "2"}}, want: [2]string{"123", "2"}, fn: wrapStringSliceValue, + }, + { + name: "AsBoolSlice() two items", + args: args{[2]bool{true, false}}, want: []bool{true, false}, fn: wrapAsBoolSlice, + }, + { + name: "AsInt64Slice() two items", + args: args{[2]int64{1, 3}}, want: []int64{1, 3}, fn: wrapAsInt64Slice, + }, + { + name: "AsFloat64Slice() two items", + args: args{[2]float64{1.2, 3.1}}, want: []float64{1.2, 3.1}, fn: wrapAsFloat64Slice, + }, + { + name: "AsStringSlice() two items", + args: args{[2]string{"1234", "12"}}, want: []string{"1234", "12"}, fn: wrapAsStringSlice, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := tt.fn(tt.args.v); !reflect.DeepEqual(got, tt.want) { + t.Errorf("got %v, want %v", got, tt.want) + } + }) + } +}