event: add Label.Apply

Expose the dispatch functionality via an exported method.

Change-Id: If01385a9357790d713a9256c61e2bbfdd1766f16
Reviewed-on: https://go-review.googlesource.com/c/exp/+/311454
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
diff --git a/event/label.go b/event/label.go
index b1cb46e..d867dd4 100644
--- a/event/label.go
+++ b/event/label.go
@@ -5,7 +5,9 @@
 package event
 
 import (
+	"fmt"
 	"reflect"
+	"strconv"
 	"unsafe"
 )
 
@@ -90,3 +92,49 @@
 
 // Key returns the key of this Label.
 func (l Label) Key() string { return l.key }
+
+// Apply calls the appropriate method of h on the label's value.
+func (l Label) Apply(h ValueHandler) {
+	if l.dispatch != nil {
+		l.dispatch(h, l)
+	}
+}
+
+//////////////////////////////////////////////////////////////////////
+
+// These are more demos of what Apply can do, rather than things we'd
+// necessarily want here.
+
+// Value is an expensive but general way to get a label's value.
+func (l Label) Value() interface{} {
+	var v interface{}
+	l.Apply(vhandler{&v})
+	return v
+}
+
+type vhandler struct {
+	pv *interface{}
+}
+
+func (h vhandler) String(v string)     { *h.pv = v }
+func (h vhandler) Quote(v string)      { *h.pv = strconv.Quote(v) }
+func (h vhandler) Int(v int64)         { *h.pv = v }
+func (h vhandler) Uint(v uint64)       { *h.pv = v }
+func (h vhandler) Float(v float64)     { *h.pv = v }
+func (h vhandler) Value(v interface{}) { *h.pv = v }
+
+// AppendValue appends the value of l to *dst as text.
+func (l Label) AppendValue(dst *[]byte) {
+	l.Apply(ahandler{dst})
+}
+
+type ahandler struct {
+	b *[]byte
+}
+
+func (h ahandler) String(v string)     { *h.b = append(*h.b, v...) }
+func (h ahandler) Quote(v string)      { *h.b = strconv.AppendQuote(*h.b, v) }
+func (h ahandler) Int(v int64)         { *h.b = strconv.AppendInt(*h.b, v, 10) }
+func (h ahandler) Uint(v uint64)       { *h.b = strconv.AppendUint(*h.b, v, 10) }
+func (h ahandler) Float(v float64)     { *h.b = strconv.AppendFloat(*h.b, v, 'E', -1, 32) }
+func (h ahandler) Value(v interface{}) { *h.b = append(*h.b, fmt.Sprint(v)...) }