package context

import 

// valueOnlyContext provides a utility to preserve only the values of a
// Context. Suppressing any cancellation or deadline on that context being
// propagated downstream of this value.
//
// If preserveExpiredValues is false (default), and the valueCtx is canceled,
// calls to lookup values with the Values method, will always return nil. Setting
// preserveExpiredValues to true, will allow the valueOnlyContext to lookup
// values in valueCtx even if valueCtx is canceled.
//
// Based on the Go standard libraries net/lookup.go onlyValuesCtx utility.
// https://github.com/golang/go/blob/da2773fe3e2f6106634673a38dc3a6eb875fe7d8/src/net/lookup.go
type valueOnlyContext struct {
	context.Context

	preserveExpiredValues bool
	valuesCtx             context.Context
}

var _ context.Context = (*valueOnlyContext)(nil)

// Value looks up the key, returning its value. If configured to not preserve
// values of expired context, and the wrapping context is canceled, nil will be
// returned.
func ( *valueOnlyContext) ( interface{}) interface{} {
	if !.preserveExpiredValues {
		select {
		case <-.valuesCtx.Done():
			return nil
		default:
		}
	}

	return .valuesCtx.Value()
}

// WithSuppressCancel wraps the Context value, suppressing its deadline and
// cancellation events being propagated downstream to consumer of the returned
// context.
//
// By default the wrapped Context's Values are available downstream until the
// wrapped Context is canceled. Once the wrapped Context is canceled, Values
// method called on the context return will no longer lookup any key. As they
// are now considered expired.
//
// To override this behavior, use WithPreserveExpiredValues on the Context
// before it is wrapped by WithSuppressCancel. This will make the Context
// returned by WithSuppressCancel allow lookup of expired values.
func ( context.Context) context.Context {
	return &valueOnlyContext{
		Context:   context.Background(),
		valuesCtx: ,

		preserveExpiredValues: GetPreserveExpiredValues(),
	}
}

type preserveExpiredValuesKey struct{}

// WithPreserveExpiredValues adds a Value to the Context if expired values
// should be preserved, and looked up by a Context wrapped by
// WithSuppressCancel.
//
// WithPreserveExpiredValues must be added as a value to a Context, before that
// Context is wrapped by WithSuppressCancel
func ( context.Context,  bool) context.Context {
	return context.WithValue(, preserveExpiredValuesKey{}, )
}

// GetPreserveExpiredValues looks up, and returns the PreserveExpressValues
// value in the context. Returning true if enabled, false otherwise.
func ( context.Context) bool {
	 := .Value(preserveExpiredValuesKey{})
	if  != nil {
		return .(bool)
	}
	return false
}