| // 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 event |
| |
| import ( |
| "reflect" |
| "unsafe" |
| ) |
| |
| // ValueHandler is used to safely unpack unknown labels. |
| type ValueHandler interface { |
| String(v string) |
| Quote(v string) |
| Int(v int64) |
| Uint(v uint64) |
| Float(v float64) |
| Value(v interface{}) |
| } |
| |
| // LabelDispatcher is used as the identity of a Label. |
| type LabelDispatcher func(h ValueHandler, l Label) |
| |
| // Label holds a key and value pair. |
| // It is normally used when passing around lists of labels. |
| type Label struct { |
| key string |
| dispatch LabelDispatcher |
| packed uint64 |
| untyped interface{} |
| } |
| |
| // 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 string, d LabelDispatcher, value interface{}) Label { |
| return Label{key: k, dispatch: d, 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 (l Label) UnpackValue() interface{} { return l.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 string, d LabelDispatcher, v uint64) Label { |
| return Label{key: k, dispatch: d, 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 (l Label) Unpack64() uint64 { return l.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 string, d LabelDispatcher, v string) Label { |
| hdr := (*reflect.StringHeader)(unsafe.Pointer(&v)) |
| return Label{ |
| key: k, |
| dispatch: d, |
| 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 (l Label) UnpackString() string { |
| var v string |
| hdr := (*reflect.StringHeader)(unsafe.Pointer(&v)) |
| hdr.Data = uintptr(l.untyped.(stringptr)) |
| hdr.Len = int(l.packed) |
| return v |
| } |
| |
| // Valid returns true if the Label is a valid one (it has a key). |
| func (l Label) Valid() bool { return l.key != "" } |
| |
| // Key returns the key of this Label. |
| func (l Label) Key() string { return l.key } |