Copyright 2017, OpenCensus Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

package tag

import (
	
	
	
	
)
Tag is a key value pair that can be propagated on wire.
type Tag struct {
	Key   Key
	Value string
}

type tagContent struct {
	value string
	m     metadatas
}
Map is a map of tags. Use New to create a context containing a new Map.
type Map struct {
	m map[Key]tagContent
}
Value returns the value for the key if a value for the key exists.
func ( *Map) ( Key) (string, bool) {
	if  == nil {
		return "", false
	}
	,  := .m[]
	return .value, 
}

func ( *Map) () string {
	if  == nil {
		return "nil"
	}
	 := make([]Key, 0, len(.m))
	for  := range .m {
		 = append(, )
	}
	sort.Slice(, func(,  int) bool { return [].Name() < [].Name() })

	var  bytes.Buffer
	.WriteString("{ ")
	for ,  := range  {
		.WriteString(fmt.Sprintf("{%v %v}", .name, .m[]))
	}
	.WriteString(" }")
	return .String()
}

func ( *Map) ( Key,  string,  metadatas) {
	if ,  := .m[];  {
		return
	}
	.m[] = tagContent{value: , m: }
}

func ( *Map) ( Key,  string,  metadatas) {
	if ,  := .m[];  {
		.m[] = tagContent{value: , m: }
	}
}

func ( *Map) ( Key,  string,  metadatas) {
	.m[] = tagContent{value: , m: }
}

func ( *Map) ( Key) {
	delete(.m, )
}

func () *Map {
	return &Map{m: make(map[Key]tagContent)}
}
Mutator modifies a tag map.
type Mutator interface {
	Mutate(t *Map) (*Map, error)
}
Insert returns a mutator that inserts a value associated with k. If k already exists in the tag map, mutator doesn't update the value. Metadata applies metadata to the tag. It is optional. Metadatas are applied in the order in which it is provided. If more than one metadata updates the same attribute then the update from the last metadata prevails.
func ( Key,  string,  ...Metadata) Mutator {
	return &mutator{
		fn: func( *Map) (*Map, error) {
			if !checkValue() {
				return nil, errInvalidValue
			}
			.insert(, , createMetadatas(...))
			return , nil
		},
	}
}
Update returns a mutator that updates the value of the tag associated with k with v. If k doesn't exists in the tag map, the mutator doesn't insert the value. Metadata applies metadata to the tag. It is optional. Metadatas are applied in the order in which it is provided. If more than one metadata updates the same attribute then the update from the last metadata prevails.
func ( Key,  string,  ...Metadata) Mutator {
	return &mutator{
		fn: func( *Map) (*Map, error) {
			if !checkValue() {
				return nil, errInvalidValue
			}
			.update(, , createMetadatas(...))
			return , nil
		},
	}
}
Upsert returns a mutator that upserts the value of the tag associated with k with v. It inserts the value if k doesn't exist already. It mutates the value if k already exists. Metadata applies metadata to the tag. It is optional. Metadatas are applied in the order in which it is provided. If more than one metadata updates the same attribute then the update from the last metadata prevails.
func ( Key,  string,  ...Metadata) Mutator {
	return &mutator{
		fn: func( *Map) (*Map, error) {
			if !checkValue() {
				return nil, errInvalidValue
			}
			.upsert(, , createMetadatas(...))
			return , nil
		},
	}
}

func ( ...Metadata) metadatas {
	var  metadatas
	if len() > 0 {
		for ,  := range  {
			if  != nil {
				(&)
			}
		}
	} else {
		WithTTL(TTLUnlimitedPropagation)(&)
	}
	return 

}
Delete returns a mutator that deletes the value associated with k.
func ( Key) Mutator {
	return &mutator{
		fn: func( *Map) (*Map, error) {
			.delete()
			return , nil
		},
	}
}
New returns a new context that contains a tag map originated from the incoming context and modified with the provided mutators.
func ( context.Context,  ...Mutator) (context.Context, error) {
	 := newMap()
	 := FromContext()
	if  != nil {
		for ,  := range .m {
			if !checkKeyName(.Name()) {
				return , fmt.Errorf("key:%q: %v", , errInvalidKeyName)
			}
			if !checkValue(.value) {
				return , fmt.Errorf("key:%q value:%q: %v", .Name(), , errInvalidValue)
			}
			.insert(, .value, .m)
		}
	}
	var  error
	for ,  := range  {
		,  = .Mutate()
		if  != nil {
			return , 
		}
	}
	return NewContext(, ), nil
}
Do is similar to pprof.Do: a convenience for installing the tags from the context as Go profiler labels. This allows you to correlated runtime profiling with stats. It converts the key/values from the given map to Go profiler labels and calls pprof.Do. Do is going to do nothing if your Go version is below 1.9.
func ( context.Context,  func( context.Context)) {
	do(, )
}

type mutator struct {
	fn func(t *Map) (*Map, error)
}

func ( *mutator) ( *Map) (*Map, error) {
	return .fn()