github.com/jd-ly/tools@v0.5.7/internal/event/label/label.go (about)

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package label
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"reflect"
    11  	"unsafe"
    12  )
    13  
    14  // Key is used as the identity of a Label.
    15  // Keys are intended to be compared by pointer only, the name should be unique
    16  // for communicating with external systems, but it is not required or enforced.
    17  type Key interface {
    18  	// Name returns the key name.
    19  	Name() string
    20  	// Description returns a string that can be used to describe the value.
    21  	Description() string
    22  
    23  	// Format is used in formatting to append the value of the label to the
    24  	// supplied buffer.
    25  	// The formatter may use the supplied buf as a scratch area to avoid
    26  	// allocations.
    27  	Format(w io.Writer, buf []byte, l Label)
    28  }
    29  
    30  // Label holds a key and value pair.
    31  // It is normally used when passing around lists of labels.
    32  type Label struct {
    33  	key     Key
    34  	packed  uint64
    35  	untyped interface{}
    36  }
    37  
    38  // Map is the interface to a collection of Labels indexed by key.
    39  type Map interface {
    40  	// Find returns the label that matches the supplied key.
    41  	Find(key Key) Label
    42  }
    43  
    44  // List is the interface to something that provides an iterable
    45  // list of labels.
    46  // Iteration should start from 0 and continue until Valid returns false.
    47  type List interface {
    48  	// Valid returns true if the index is within range for the list.
    49  	// It does not imply the label at that index will itself be valid.
    50  	Valid(index int) bool
    51  	// Label returns the label at the given index.
    52  	Label(index int) Label
    53  }
    54  
    55  // list implements LabelList for a list of Labels.
    56  type list struct {
    57  	labels []Label
    58  }
    59  
    60  // filter wraps a LabelList filtering out specific labels.
    61  type filter struct {
    62  	keys       []Key
    63  	underlying List
    64  }
    65  
    66  // listMap implements LabelMap for a simple list of labels.
    67  type listMap struct {
    68  	labels []Label
    69  }
    70  
    71  // mapChain implements LabelMap for a list of underlying LabelMap.
    72  type mapChain struct {
    73  	maps []Map
    74  }
    75  
    76  // OfValue creates a new label from the key and value.
    77  // This method is for implementing new key types, label creation should
    78  // normally be done with the Of method of the key.
    79  func OfValue(k Key, value interface{}) Label { return Label{key: k, untyped: value} }
    80  
    81  // UnpackValue assumes the label was built using LabelOfValue and returns the value
    82  // that was passed to that constructor.
    83  // This method is for implementing new key types, for type safety normal
    84  // access should be done with the From method of the key.
    85  func (t Label) UnpackValue() interface{} { return t.untyped }
    86  
    87  // Of64 creates a new label from a key and a uint64. This is often
    88  // used for non uint64 values that can be packed into a uint64.
    89  // This method is for implementing new key types, label creation should
    90  // normally be done with the Of method of the key.
    91  func Of64(k Key, v uint64) Label { return Label{key: k, packed: v} }
    92  
    93  // Unpack64 assumes the label was built using LabelOf64 and returns the value that
    94  // was passed to that constructor.
    95  // This method is for implementing new key types, for type safety normal
    96  // access should be done with the From method of the key.
    97  func (t Label) Unpack64() uint64 { return t.packed }
    98  
    99  // OfString creates a new label from a key and a string.
   100  // This method is for implementing new key types, label creation should
   101  // normally be done with the Of method of the key.
   102  func OfString(k Key, v string) Label {
   103  	hdr := (*reflect.StringHeader)(unsafe.Pointer(&v))
   104  	return Label{
   105  		key:     k,
   106  		packed:  uint64(hdr.Len),
   107  		untyped: unsafe.Pointer(hdr.Data),
   108  	}
   109  }
   110  
   111  // UnpackString assumes the label was built using LabelOfString and returns the
   112  // value that was passed to that constructor.
   113  // This method is for implementing new key types, for type safety normal
   114  // access should be done with the From method of the key.
   115  func (t Label) UnpackString() string {
   116  	var v string
   117  	hdr := (*reflect.StringHeader)(unsafe.Pointer(&v))
   118  	hdr.Data = uintptr(t.untyped.(unsafe.Pointer))
   119  	hdr.Len = int(t.packed)
   120  	return *(*string)(unsafe.Pointer(hdr))
   121  }
   122  
   123  // Valid returns true if the Label is a valid one (it has a key).
   124  func (t Label) Valid() bool { return t.key != nil }
   125  
   126  // Key returns the key of this Label.
   127  func (t Label) Key() Key { return t.key }
   128  
   129  // Format is used for debug printing of labels.
   130  func (t Label) Format(f fmt.State, r rune) {
   131  	if !t.Valid() {
   132  		io.WriteString(f, `nil`)
   133  		return
   134  	}
   135  	io.WriteString(f, t.Key().Name())
   136  	io.WriteString(f, "=")
   137  	var buf [128]byte
   138  	t.Key().Format(f, buf[:0], t)
   139  }
   140  
   141  func (l *list) Valid(index int) bool {
   142  	return index >= 0 && index < len(l.labels)
   143  }
   144  
   145  func (l *list) Label(index int) Label {
   146  	return l.labels[index]
   147  }
   148  
   149  func (f *filter) Valid(index int) bool {
   150  	return f.underlying.Valid(index)
   151  }
   152  
   153  func (f *filter) Label(index int) Label {
   154  	l := f.underlying.Label(index)
   155  	for _, f := range f.keys {
   156  		if l.Key() == f {
   157  			return Label{}
   158  		}
   159  	}
   160  	return l
   161  }
   162  
   163  func (lm listMap) Find(key Key) Label {
   164  	for _, l := range lm.labels {
   165  		if l.Key() == key {
   166  			return l
   167  		}
   168  	}
   169  	return Label{}
   170  }
   171  
   172  func (c mapChain) Find(key Key) Label {
   173  	for _, src := range c.maps {
   174  		l := src.Find(key)
   175  		if l.Valid() {
   176  			return l
   177  		}
   178  	}
   179  	return Label{}
   180  }
   181  
   182  var emptyList = &list{}
   183  
   184  func NewList(labels ...Label) List {
   185  	if len(labels) == 0 {
   186  		return emptyList
   187  	}
   188  	return &list{labels: labels}
   189  }
   190  
   191  func Filter(l List, keys ...Key) List {
   192  	if len(keys) == 0 {
   193  		return l
   194  	}
   195  	return &filter{keys: keys, underlying: l}
   196  }
   197  
   198  func NewMap(labels ...Label) Map {
   199  	return listMap{labels: labels}
   200  }
   201  
   202  func MergeMaps(srcs ...Map) Map {
   203  	var nonNil []Map
   204  	for _, src := range srcs {
   205  		if src != nil {
   206  			nonNil = append(nonNil, src)
   207  		}
   208  	}
   209  	if len(nonNil) == 1 {
   210  		return nonNil[0]
   211  	}
   212  	return mapChain{maps: nonNil}
   213  }