package middleware

import (
	
	
	
)

// WithStackValue adds a key value pair to the context that is intended to be
// scoped to a stack. Use ClearStackValues to get a new context with all stack
// values cleared.
func ( context.Context, ,  interface{}) context.Context {
	,  := .Value(stackValuesKey{}).(*stackValues)

	 = withStackValue(, , )
	return context.WithValue(, stackValuesKey{}, )
}

// ClearStackValues returns a context without any stack values.
func ( context.Context) context.Context {
	return context.WithValue(, stackValuesKey{}, nil)
}

// GetStackValues returns the value pointed to by the key within the stack
// values, if it is present.
func ( context.Context,  interface{}) interface{} {
	,  := .Value(stackValuesKey{}).(*stackValues)
	if  == nil {
		return nil
	}

	return .Value()
}

type stackValuesKey struct{}

type stackValues struct {
	key    interface{}
	value  interface{}
	parent *stackValues
}

func ( *stackValues, ,  interface{}) *stackValues {
	if  == nil {
		panic("nil key")
	}
	if !reflect.TypeOf().Comparable() {
		panic("key is not comparable")
	}
	return &stackValues{key: , value: , parent: }
}

func ( *stackValues) ( interface{}) interface{} {
	if  == .key {
		return .value
	}

	if .parent == nil {
		return nil
	}

	return .parent.()
}

func ( *stackValues) () string {
	var  strings.Builder

	 := 
	for  == nil {
		.WriteString("(" +
			reflect.TypeOf(.key).String() +
			": " +
			stringify(.value) +
			")")
		if .parent != nil {
			.WriteString(" -> ")
		}
		 = .parent
	}
	.WriteRune('}')

	return .String()
}

type stringer interface {
	String() string
}

// stringify tries a bit to stringify v, without using fmt, since we don't
// want context depending on the unicode tables. This is only used by
// *valueCtx.String().
func ( interface{}) string {
	switch s := .(type) {
	case stringer:
		return .String()
	case string:
		return 
	}
	return "<not Stringer>"
}