|  | // Copyright 2019 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package label | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "io" | 
|  | "reflect" | 
|  | "unsafe" | 
|  | ) | 
|  |  | 
|  | // Key is used as the identity of a Label. | 
|  | // Keys are intended to be compared by pointer only, the name should be unique | 
|  | // for communicating with external systems, but it is not required or enforced. | 
|  | type Key interface { | 
|  | // Name returns the key name. | 
|  | Name() string | 
|  | // Description returns a string that can be used to describe the value. | 
|  | Description() string | 
|  |  | 
|  | // Format is used in formatting to append the value of the label to the | 
|  | // supplied buffer. | 
|  | // The formatter may use the supplied buf as a scratch area to avoid | 
|  | // allocations. | 
|  | Format(w io.Writer, buf []byte, l Label) | 
|  | } | 
|  |  | 
|  | // Label holds a key and value pair. | 
|  | // It is normally used when passing around lists of labels. | 
|  | type Label struct { | 
|  | key     Key | 
|  | packed  uint64 | 
|  | untyped interface{} | 
|  | } | 
|  |  | 
|  | // Map is the interface to a collection of Labels indexed by key. | 
|  | type Map interface { | 
|  | // Find returns the label that matches the supplied key. | 
|  | Find(key Key) Label | 
|  | } | 
|  |  | 
|  | // List is the interface to something that provides an iterable | 
|  | // list of labels. | 
|  | // Iteration should start from 0 and continue until Valid returns false. | 
|  | type List interface { | 
|  | // Valid returns true if the index is within range for the list. | 
|  | // It does not imply the label at that index will itself be valid. | 
|  | Valid(index int) bool | 
|  | // Label returns the label at the given index. | 
|  | Label(index int) Label | 
|  | } | 
|  |  | 
|  | // list implements LabelList for a list of Labels. | 
|  | type list struct { | 
|  | labels []Label | 
|  | } | 
|  |  | 
|  | // filter wraps a LabelList filtering out specific labels. | 
|  | type filter struct { | 
|  | keys       []Key | 
|  | underlying List | 
|  | } | 
|  |  | 
|  | // listMap implements LabelMap for a simple list of labels. | 
|  | type listMap struct { | 
|  | labels []Label | 
|  | } | 
|  |  | 
|  | // mapChain implements LabelMap for a list of underlying LabelMap. | 
|  | type mapChain struct { | 
|  | maps []Map | 
|  | } | 
|  |  | 
|  | // OfValue creates a new label from the key and value. | 
|  | // This method is for implementing new key types, label creation should | 
|  | // normally be done with the Of method of the key. | 
|  | func OfValue(k Key, value interface{}) Label { return Label{key: k, untyped: value} } | 
|  |  | 
|  | // UnpackValue assumes the label was built using LabelOfValue and returns the value | 
|  | // that was passed to that constructor. | 
|  | // This method is for implementing new key types, for type safety normal | 
|  | // access should be done with the From method of the key. | 
|  | func (t Label) UnpackValue() interface{} { return t.untyped } | 
|  |  | 
|  | // Of64 creates a new label from a key and a uint64. This is often | 
|  | // used for non uint64 values that can be packed into a uint64. | 
|  | // This method is for implementing new key types, label creation should | 
|  | // normally be done with the Of method of the key. | 
|  | func Of64(k Key, v uint64) Label { return Label{key: k, packed: v} } | 
|  |  | 
|  | // Unpack64 assumes the label was built using LabelOf64 and returns the value that | 
|  | // was passed to that constructor. | 
|  | // This method is for implementing new key types, for type safety normal | 
|  | // access should be done with the From method of the key. | 
|  | func (t Label) Unpack64() uint64 { return t.packed } | 
|  |  | 
|  | type stringptr unsafe.Pointer | 
|  |  | 
|  | // OfString creates a new label from a key and a string. | 
|  | // This method is for implementing new key types, label creation should | 
|  | // normally be done with the Of method of the key. | 
|  | func OfString(k Key, v string) Label { | 
|  | hdr := (*reflect.StringHeader)(unsafe.Pointer(&v)) | 
|  | return Label{ | 
|  | key:     k, | 
|  | packed:  uint64(hdr.Len), | 
|  | untyped: stringptr(hdr.Data), | 
|  | } | 
|  | } | 
|  |  | 
|  | // UnpackString assumes the label was built using LabelOfString and returns the | 
|  | // value that was passed to that constructor. | 
|  | // This method is for implementing new key types, for type safety normal | 
|  | // access should be done with the From method of the key. | 
|  | func (t Label) UnpackString() string { | 
|  | var v string | 
|  | hdr := (*reflect.StringHeader)(unsafe.Pointer(&v)) | 
|  | hdr.Data = uintptr(t.untyped.(stringptr)) | 
|  | hdr.Len = int(t.packed) | 
|  | return v | 
|  | } | 
|  |  | 
|  | // Valid returns true if the Label is a valid one (it has a key). | 
|  | func (t Label) Valid() bool { return t.key != nil } | 
|  |  | 
|  | // Key returns the key of this Label. | 
|  | func (t Label) Key() Key { return t.key } | 
|  |  | 
|  | // Format is used for debug printing of labels. | 
|  | func (t Label) Format(f fmt.State, r rune) { | 
|  | if !t.Valid() { | 
|  | io.WriteString(f, `nil`) | 
|  | return | 
|  | } | 
|  | io.WriteString(f, t.Key().Name()) | 
|  | io.WriteString(f, "=") | 
|  | var buf [128]byte | 
|  | t.Key().Format(f, buf[:0], t) | 
|  | } | 
|  |  | 
|  | func (l *list) Valid(index int) bool { | 
|  | return index >= 0 && index < len(l.labels) | 
|  | } | 
|  |  | 
|  | func (l *list) Label(index int) Label { | 
|  | return l.labels[index] | 
|  | } | 
|  |  | 
|  | func (f *filter) Valid(index int) bool { | 
|  | return f.underlying.Valid(index) | 
|  | } | 
|  |  | 
|  | func (f *filter) Label(index int) Label { | 
|  | l := f.underlying.Label(index) | 
|  | for _, f := range f.keys { | 
|  | if l.Key() == f { | 
|  | return Label{} | 
|  | } | 
|  | } | 
|  | return l | 
|  | } | 
|  |  | 
|  | func (lm listMap) Find(key Key) Label { | 
|  | for _, l := range lm.labels { | 
|  | if l.Key() == key { | 
|  | return l | 
|  | } | 
|  | } | 
|  | return Label{} | 
|  | } | 
|  |  | 
|  | func (c mapChain) Find(key Key) Label { | 
|  | for _, src := range c.maps { | 
|  | l := src.Find(key) | 
|  | if l.Valid() { | 
|  | return l | 
|  | } | 
|  | } | 
|  | return Label{} | 
|  | } | 
|  |  | 
|  | var emptyList = &list{} | 
|  |  | 
|  | func NewList(labels ...Label) List { | 
|  | if len(labels) == 0 { | 
|  | return emptyList | 
|  | } | 
|  | return &list{labels: labels} | 
|  | } | 
|  |  | 
|  | func Filter(l List, keys ...Key) List { | 
|  | if len(keys) == 0 { | 
|  | return l | 
|  | } | 
|  | return &filter{keys: keys, underlying: l} | 
|  | } | 
|  |  | 
|  | func NewMap(labels ...Label) Map { | 
|  | return listMap{labels: labels} | 
|  | } | 
|  |  | 
|  | func MergeMaps(srcs ...Map) Map { | 
|  | var nonNil []Map | 
|  | for _, src := range srcs { | 
|  | if src != nil { | 
|  | nonNil = append(nonNil, src) | 
|  | } | 
|  | } | 
|  | if len(nonNil) == 1 { | 
|  | return nonNil[0] | 
|  | } | 
|  | return mapChain{maps: nonNil} | 
|  | } |