attribute.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. /*
  4. Package attribute provide several helper functions for some commonly used
  5. logic of processing attributes.
  6. */
  7. package attribute // import "go.opentelemetry.io/otel/attribute/internal"
  8. import (
  9. "reflect"
  10. )
  11. // sliceElem is the exact set of element types stored in attribute slice values.
  12. // Using a closed set prevents accidental instantiations for unsupported types.
  13. type sliceElem interface {
  14. bool | int64 | float64 | string
  15. }
  16. // SliceValue converts a slice into an array with the same elements.
  17. func SliceValue[T sliceElem](v []T) any {
  18. // Keep only the common tiny-slice cases out of reflection. Extending this
  19. // much further increases code size for diminishing benefit while larger
  20. // slices still need the generic reflective path to preserve comparability.
  21. // This matches the short lengths that show up most often in local
  22. // benchmarks and semantic convention examples while leaving larger, less
  23. // predictable slices on the generic reflective path.
  24. switch len(v) {
  25. case 0:
  26. return [0]T{}
  27. case 1:
  28. return [1]T{v[0]}
  29. case 2:
  30. return [2]T{v[0], v[1]}
  31. case 3:
  32. return [3]T{v[0], v[1], v[2]}
  33. }
  34. return sliceValueReflect(v)
  35. }
  36. // AsSlice converts an array into a slice with the same elements.
  37. func AsSlice[T sliceElem](v any) []T {
  38. // Mirror the small fixed-array fast path used by SliceValue.
  39. switch a := v.(type) {
  40. case [0]T:
  41. return []T{}
  42. case [1]T:
  43. return []T{a[0]}
  44. case [2]T:
  45. return []T{a[0], a[1]}
  46. case [3]T:
  47. return []T{a[0], a[1], a[2]}
  48. }
  49. return asSliceReflect[T](v)
  50. }
  51. func sliceValueReflect[T sliceElem](v []T) any {
  52. cp := reflect.New(reflect.ArrayOf(len(v), reflect.TypeFor[T]())).Elem()
  53. reflect.Copy(cp, reflect.ValueOf(v))
  54. return cp.Interface()
  55. }
  56. func asSliceReflect[T sliceElem](v any) []T {
  57. rv := reflect.ValueOf(v)
  58. if !rv.IsValid() || rv.Kind() != reflect.Array || rv.Type().Elem() != reflect.TypeFor[T]() {
  59. return nil
  60. }
  61. cpy := make([]T, rv.Len())
  62. if len(cpy) > 0 {
  63. _ = reflect.Copy(reflect.ValueOf(cpy), rv)
  64. }
  65. return cpy
  66. }