// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package attribute // import "go.opentelemetry.io/otel/attribute"

import (
	
	

	
)

// Type identifiers. These identifiers are hashed before the value of the
// corresponding type. This is done to distinguish values that are hashed with
// the same value representation (e.g. `int64(1)` and `true`, []int64{0} and
// int64(0)).
//
// These are all 8 byte length strings converted to a uint64 representation. A
// uint64 is used instead of the string directly as an optimization, it avoids
// the for loop in [xxhash] which adds minor overhead.
const (
	boolID         uint64 = 7953749933313450591 // "_boolean" (little endian)
	int64ID        uint64 = 7592915492740740150 // "64_bit_i" (little endian)
	float64ID      uint64 = 7376742710626956342 // "64_bit_f" (little endian)
	stringID       uint64 = 6874584755375207263 // "_string_" (little endian)
	boolSliceID    uint64 = 6875993255270243167 // "_[]bool_" (little endian)
	int64SliceID   uint64 = 3762322556277578591 // "_[]int64" (little endian)
	float64SliceID uint64 = 7308324551835016539 // "[]double" (little endian)
	stringSliceID  uint64 = 7453010373645655387 // "[]string" (little endian)
	byteSliceID    uint64 = 6874028470941080415 // "_[]byte_" (little endian)
	sliceID        uint64 = 7883494272577650031 // "__slice_" (little endian)
	emptyID        uint64 = 7305809155345288421 // "__empty_" (little endian)
)

// hashKVs returns a new xxHash64 hash of kvs.
func ( []KeyValue) uint64 {
	 := xxhash.New()
	for ,  := range  {
		 = hashKV(, )
	}
	return .Sum64()
}

// hashKV returns the xxHash64 hash of kv with h as the base.
func ( xxhash.Hash,  KeyValue) xxhash.Hash {
	 = .String(string(.Key))
	return hashValue(, .Value)
}

func ( xxhash.Hash,  Value) xxhash.Hash {
	switch .Type() {
	case BOOL:
		 = .Uint64(boolID)
		 = .Uint64(.numeric)
	case INT64:
		 = .Uint64(int64ID)
		 = .Uint64(.numeric)
	case FLOAT64:
		 = .Uint64(float64ID)
		// Assumes numeric stored with math.Float64bits.
		 = .Uint64(.numeric)
	case STRING:
		 = .Uint64(stringID)
		 = .String(.stringly)
	case BOOLSLICE:
		 = .Uint64(boolSliceID)
		 := reflect.ValueOf(.slice)
		for  := 0;  < .Len(); ++ {
			 = .Bool(.Index().Bool())
		}
	case INT64SLICE:
		 = .Uint64(int64SliceID)
		 := reflect.ValueOf(.slice)
		for  := 0;  < .Len(); ++ {
			 = .Int64(.Index().Int())
		}
	case FLOAT64SLICE:
		 = .Uint64(float64SliceID)
		 := reflect.ValueOf(.slice)
		for  := 0;  < .Len(); ++ {
			 = .Float64(.Index().Float())
		}
	case STRINGSLICE:
		 = .Uint64(stringSliceID)
		 := reflect.ValueOf(.slice)
		for  := 0;  < .Len(); ++ {
			 = .String(.Index().String())
		}
	case BYTESLICE:
		 = .Uint64(byteSliceID)
		 = .String(.stringly)
	case SLICE:
		 = .Uint64(sliceID)
		switch vals := .slice.(type) {
		case [0]Value:
			// No values to hash, but the type identifier is still hashed above.
		case [1]Value:
			 = hashValueSlice(, [:])
		case [2]Value:
			 = hashValueSlice(, [:])
		case [3]Value:
			 = hashValueSlice(, [:])
		case [4]Value:
			 = hashValueSlice(, [:])
		case [5]Value:
			 = hashValueSlice(, [:])
		default:
			 := reflect.ValueOf(.slice)
			for  := 0;  < .Len(); ++ {
				 = (, .Index().Interface().(Value))
			}
		}
	case EMPTY:
		 = .Uint64(emptyID)
	default:
		// Logging is an alternative, but using the internal logger here
		// causes an import cycle so it is not done.
		 := .AsInterface()
		 := fmt.Sprintf("unknown value type: %[1]v (%[1]T)", )
		panic()
	}
	return 
}

func ( xxhash.Hash,  []Value) xxhash.Hash {
	for ,  := range  {
		 = hashValue(, )
	}
	return 
}