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

//go:generate stringer -type=Kind -trimprefix=Kind

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

import (
	
	
	
	
	
	
	
	

	
	
)

// errKind is logged when a Value is decoded to an incompatible type.
var errKind = errors.New("invalid Kind")

// Kind is the kind of a [Value].
type Kind int

// Kind values.
const (
	KindEmpty Kind = iota
	KindBool
	KindFloat64
	KindInt64
	KindString
	KindBytes
	KindSlice
	KindMap
)

// A Value represents a structured log 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 *KeyValue
)

// StringValue returns a new [Value] for a string.
func ( string) Value {
	return Value{
		num: uint64(len()),
		any: stringptr(unsafe.StringData()),
	}
}

// IntValue returns a [Value] for an int.
func ( int) Value { return Int64Value(int64()) }

// Int64Value returns a [Value] for an int64.
func ( int64) Value {
	// This can be later converted back to int64 (overflow not checked).
	return Value{num: uint64(), any: KindInt64} // nolint:gosec
}

// Float64Value returns a [Value] for a float64.
func ( float64) Value {
	return Value{num: math.Float64bits(), any: KindFloat64}
}

// BoolValue returns a [Value] for a bool.
func ( bool) Value { //nolint:revive // Not a control flag.
	var  uint64
	if  {
		 = 1
	}
	return Value{num: , any: KindBool}
}

// BytesValue returns a [Value] for a byte slice. The passed slice must not be
// changed after it is passed.
func ( []byte) Value {
	return Value{
		num: uint64(len()),
		any: bytesptr(unsafe.SliceData()),
	}
}

// SliceValue returns a [Value] for a slice of [Value]. The passed slice must
// not be changed after it is passed.
func ( ...Value) Value {
	return Value{
		num: uint64(len()),
		any: sliceptr(unsafe.SliceData()),
	}
}

// MapValue returns a new [Value] for a slice of key-value pairs. The passed
// slice must not be changed after it is passed.
func ( ...KeyValue) Value {
	return Value{
		num: uint64(len()),
		any: mapptr(unsafe.SliceData()),
	}
}

// AsString returns the value held by v as a string.
func ( Value) () string {
	if ,  := .any.(stringptr);  {
		return unsafe.String(, .num)
	}
	global.Error(errKind, "AsString", "Kind", .Kind())
	return ""
}

// asString returns the value held by v as a string. It will panic if the Value
// is not KindString.
func ( Value) () string {
	return unsafe.String(.any.(stringptr), .num)
}

// AsInt64 returns the value held by v as an int64.
func ( Value) () int64 {
	if .Kind() != KindInt64 {
		global.Error(errKind, "AsInt64", "Kind", .Kind())
		return 0
	}
	return .asInt64()
}

// asInt64 returns the value held by v as an int64. If v is not of KindInt64,
// this will return garbage.
func ( Value) () int64 {
	// Assumes v.num was a valid int64 (overflow not checked).
	return int64(.num) // nolint: gosec
}

// AsBool returns the value held by v as a bool.
func ( Value) () bool {
	if .Kind() != KindBool {
		global.Error(errKind, "AsBool", "Kind", .Kind())
		return false
	}
	return .asBool()
}

// asBool returns the value held by v as a bool. If v is not of KindBool, this
// will return garbage.
func ( Value) () bool { return .num == 1 }

// AsFloat64 returns the value held by v as a float64.
func ( Value) () float64 {
	if .Kind() != KindFloat64 {
		global.Error(errKind, "AsFloat64", "Kind", .Kind())
		return 0
	}
	return .asFloat64()
}

// asFloat64 returns the value held by v as a float64. If v is not of
// KindFloat64, this will return garbage.
func ( Value) () float64 { return math.Float64frombits(.num) }

// AsBytes returns the value held by v as a []byte.
func ( Value) () []byte {
	if ,  := .any.(bytesptr);  {
		return unsafe.Slice((*byte)(), .num)
	}
	global.Error(errKind, "AsBytes", "Kind", .Kind())
	return nil
}

// asBytes returns the value held by v as a []byte. It will panic if the Value
// is not KindBytes.
func ( Value) () []byte {
	return unsafe.Slice((*byte)(.any.(bytesptr)), .num)
}

// AsSlice returns the value held by v as a []Value.
func ( Value) () []Value {
	if ,  := .any.(sliceptr);  {
		return unsafe.Slice((*Value)(), .num)
	}
	global.Error(errKind, "AsSlice", "Kind", .Kind())
	return nil
}

// asSlice returns the value held by v as a []Value. It will panic if the Value
// is not KindSlice.
func ( Value) () []Value {
	return unsafe.Slice((*Value)(.any.(sliceptr)), .num)
}

// AsMap returns the value held by v as a []KeyValue.
func ( Value) () []KeyValue {
	if ,  := .any.(mapptr);  {
		return unsafe.Slice((*KeyValue)(), .num)
	}
	global.Error(errKind, "AsMap", "Kind", .Kind())
	return nil
}

// asMap returns the value held by v as a []KeyValue. It will panic if the
// Value is not KindMap.
func ( Value) () []KeyValue {
	return unsafe.Slice((*KeyValue)(.any.(mapptr)), .num)
}

// Kind returns the Kind of v.
func ( Value) () Kind {
	switch x := .any.(type) {
	case Kind:
		return 
	case stringptr:
		return KindString
	case bytesptr:
		return KindBytes
	case sliceptr:
		return KindSlice
	case mapptr:
		return KindMap
	default:
		return KindEmpty
	}
}

// Empty reports whether v does not hold any value.
func ( Value) () bool { return .Kind() == KindEmpty }

// Equal reports whether v is equal to w.
func ( Value) ( Value) bool {
	 := .Kind()
	 := .Kind()
	if  !=  {
		return false
	}
	switch  {
	case KindInt64, KindBool:
		return .num == .num
	case KindString:
		return .asString() == .asString()
	case KindFloat64:
		return .asFloat64() == .asFloat64()
	case KindSlice:
		return slices.EqualFunc(.asSlice(), .asSlice(), Value.)
	case KindMap:
		 := sortMap(.asMap())
		 := sortMap(.asMap())
		return slices.EqualFunc(, , KeyValue.Equal)
	case KindBytes:
		return bytes.Equal(.asBytes(), .asBytes())
	case KindEmpty:
		return true
	default:
		global.Error(errKind, "Equal", "Kind", )
		return false
	}
}

func sortMap( []KeyValue) []KeyValue {
	 := make([]KeyValue, len())
	copy(, )
	slices.SortFunc(, func(,  KeyValue) int {
		return cmp.Compare(.Key, .Key)
	})

	return 
}

// 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 ( Value) () string {
	switch .Kind() {
	case KindString:
		return .asString()
	case KindInt64:
		// Assumes v.num was a valid int64 (overflow not checked).
		return strconv.FormatInt(int64(.num), 10) // nolint: gosec
	case KindFloat64:
		return strconv.FormatFloat(.asFloat64(), 'g', -1, 64)
	case KindBool:
		return strconv.FormatBool(.asBool())
	case KindBytes:
		return fmt.Sprint(.asBytes()) // nolint:staticcheck  // Use fmt.Sprint to encode as slice.
	case KindMap:
		return fmt.Sprint(.asMap())
	case KindSlice:
		return fmt.Sprint(.asSlice())
	case KindEmpty:
		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 log.Kind: %s>", .Kind())
	}
}

// A KeyValue is a key-value pair used to represent a log attribute (a
// superset of [go.opentelemetry.io/otel/attribute.KeyValue]) and map item.
type KeyValue struct {
	Key   string
	Value Value
}

// Equal reports whether a is equal to b.
func ( KeyValue) ( KeyValue) bool {
	return .Key == .Key && .Value.Equal(.Value)
}

// String returns a KeyValue for a string value.
func (,  string) KeyValue {
	return KeyValue{, StringValue()}
}

// Int64 returns a KeyValue for an int64 value.
func ( string,  int64) KeyValue {
	return KeyValue{, Int64Value()}
}

// Int returns a KeyValue for an int value.
func ( string,  int) KeyValue {
	return KeyValue{, IntValue()}
}

// Float64 returns a KeyValue for a float64 value.
func ( string,  float64) KeyValue {
	return KeyValue{, Float64Value()}
}

// Bool returns a KeyValue for a bool value.
func ( string,  bool) KeyValue {
	return KeyValue{, BoolValue()}
}

// Bytes returns a KeyValue for a []byte value.
// The passed slice must not be changed after it is passed.
func ( string,  []byte) KeyValue {
	return KeyValue{, BytesValue()}
}

// Slice returns a KeyValue for a []Value value.
// The passed slice must not be changed after it is passed.
func ( string,  ...Value) KeyValue {
	return KeyValue{, SliceValue(...)}
}

// Map returns a KeyValue for a map value.
// The passed slice must not be changed after it is passed.
func ( string,  ...KeyValue) KeyValue {
	return KeyValue{, MapValue(...)}
}

// Empty returns a KeyValue with an empty value.
func ( string) KeyValue {
	return KeyValue{, Value{}}
}

// String returns key-value pair as a string, formatted like "key:value".
//
// The returned string is meant for debugging;
// the string representation is not stable.
func ( KeyValue) () string {
	return fmt.Sprintf("%s:%s", .Key, .Value)
}

// ValueFromAttribute converts [attribute.Value] to [Value].
func ( attribute.Value) Value {
	switch .Type() {
	case attribute.INVALID:
		return Value{}
	case attribute.BOOL:
		return BoolValue(.AsBool())
	case attribute.BOOLSLICE:
		 := .AsBoolSlice()
		 := make([]Value, 0, len())
		for ,  := range  {
			 = append(, BoolValue())
		}
		return SliceValue(...)
	case attribute.INT64:
		return Int64Value(.AsInt64())
	case attribute.INT64SLICE:
		 := .AsInt64Slice()
		 := make([]Value, 0, len())
		for ,  := range  {
			 = append(, Int64Value())
		}
		return SliceValue(...)
	case attribute.FLOAT64:
		return Float64Value(.AsFloat64())
	case attribute.FLOAT64SLICE:
		 := .AsFloat64Slice()
		 := make([]Value, 0, len())
		for ,  := range  {
			 = append(, Float64Value())
		}
		return SliceValue(...)
	case attribute.STRING:
		return StringValue(.AsString())
	case attribute.STRINGSLICE:
		 := .AsStringSlice()
		 := make([]Value, 0, len())
		for ,  := range  {
			 = append(, StringValue())
		}
		return SliceValue(...)
	}
	// This code should never be reached
	// as log attributes are a superset of standard attributes.
	panic("unknown attribute type")
}

// KeyValueFromAttribute converts [attribute.KeyValue] to [KeyValue].
func ( attribute.KeyValue) KeyValue {
	return KeyValue{
		Key:   string(.Key),
		Value: ValueFromAttribute(.Value),
	}
}