func UnwrapInt64(tv *TypedValue) (int64, error) {
	i, err := Unwrap(tv)
	if err != nil {
		return 0, err
	}
	switch t := i.(type) {
	case int64:
		return int64(t), nil
	case int32:
		return int64(t), nil
	case uint32:
		return int64(t), nil
	case uint64:
		return int64(t), nil
	case float32:
		return int64(t), nil
	case float64:
		return int64(t), nil
	default:
		return 0, errors.Wrapf(ErrIllegalTypeAssertion, "failed to unwrap %s to int64", tv.ValueType())
	}
}
TODO reduce verbosity of these numberic implementations
package typedvalues
import (
	"fmt"
	"regexp"
	"strings"
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/ptypes"
	"github.com/golang/protobuf/ptypes/any"
	"github.com/golang/protobuf/ptypes/wrappers"
	"github.com/pkg/errors"
)
const (
	TypeUrlPrefix = "types.fission.io/"
)
var (
	expressionRe            = regexp.MustCompile("^\\{(.*)\\}$")
	ErrIllegalTypeAssertion = errors.New("illegal type assertion")
	ErrUnsupportedType      = errors.New("unsupported type")
)
func (m *TypedValue) ValueType() string {
	if m == nil || m.Value == nil {
		return ""
	}
	typeUrl := m.Value.TypeUrl
	pos := strings.Index(typeUrl, TypeUrlPrefix)
	if pos == 0 {
		return typeUrl[len(TypeUrlPrefix):]
	}
	return typeUrl
}
func (m *TypedValue) Interface() interface{} {
	if m == nil || m.Value == nil {
		return nil
	}
	return MustUnwrap(m)
}
func (m *TypedValue) Float64() float64 {
	val := m.Interface()
	switch t := val.(type) {
	case int32:
		return float64(t)
	case int64:
		return float64(t)
	case uint32:
		return float64(t)
	case uint64:
		return float64(t)
	case float32:
		return float64(t)
	case float64:
		return float64(t)
	default:
		panic("TypedValue: not a number")
	}
}
func (m *TypedValue) Short() string {
	if m == nil {
		return ""
	}
	return fmt.Sprintf("<Type=\"%s\", Val=\"%v\">", m.ValueType(), len(m.GetValue().GetValue()))
}
func (m *TypedValue) SetMetadata(k string, v string) *TypedValue {
	if m == nil {
		return m
	}
	if m.Metadata == nil {
		m.Metadata = map[string]string{}
	}
	m.Metadata[k] = v
	return m
}
func (m *TypedValue) GetMetadataValue(k string) (string, bool) {
	if m == nil {
		return "", false
	}
	if m.Metadata == nil {
		m.Metadata = map[string]string{}
	}
	v, ok := m.Metadata[k]
	return v, ok
}
func (m *TypedValue) Equals(other *TypedValue) bool {
	return proto.Equal(m, other)
}
func Unwrap(tv *TypedValue) (interface{}, error) {
	if tv == nil {
		return nil, nil
	}
	msg, err := UnwrapProto(tv)
	if err != nil {
		return nil, err
	}
	var i interface{}
	switch t := msg.(type) {
	case *MapValue:
		mapValue := make(map[string]interface{}, len(t.Value))
		for k, v := range t.Value {
			entry, err := Unwrap(v)
			if err != nil {
				return TypedValue{}, errors.Wrapf(err, "failed to format map[%s]", k)
			}
			mapValue[k] = entry
		}
		i = mapValue
	case *ArrayValue:
		arrayValue := make([]interface{}, len(t.Value))
		for k, v := range t.Value {
			entry, err := Unwrap(v)
			if err != nil {
				return TypedValue{}, errors.Wrapf(err, "failed to format array[%d]", k)
			}
			arrayValue[k] = entry
		}
		i = arrayValue
	case *Expression:
		i = t.Value
	case *wrappers.BoolValue:
		i = t.Value
	case *wrappers.FloatValue:
		i = t.Value
	case *wrappers.DoubleValue:
		i = t.Value
	case *wrappers.Int32Value:
		i = t.Value
	case *wrappers.Int64Value:
		i = t.Value
	case *wrappers.UInt64Value:
		i = t.Value
	case *wrappers.UInt32Value:
		i = t.Value
	case *wrappers.StringValue:
		i = t.Value
	case *wrappers.BytesValue:
		i = t.Value
	case *NilValue:
		i = nil
	default:
		i = t
	}
	return i, nil
}
func Wrap(val interface{}) (*TypedValue, error) {
	var msg proto.Message
	switch t := val.(type) {
	case *TypedValue:
		return t, nil
	case []*TypedValue:
		msg = &ArrayValue{Value: t}
	case map[string]*TypedValue:
		msg = &MapValue{Value: t}
	case map[string]interface{}:
		values := make(map[string]*TypedValue, len(t))
		for k, v := range t {
			tv, err := Wrap(v)
			if err != nil {
				return nil, errors.Wrapf(err, "failed to parse map[%s]", k)
			}
			values[k] = tv
		}
		msg = &MapValue{Value: values}
	case []interface{}:
		values := make([]*TypedValue, len(t))
		for i, v := range t {
			tv, err := Wrap(v)
			if err != nil {
				return nil, errors.Wrapf(err, "failed to parse array[%d]", i)
			}
			values[i] = tv
		}
		msg = &ArrayValue{Value: values}
	case proto.Message:
		msg = t
	case string:
		if expressionRe.MatchString(t) {
			msg = &Expression{Value: t}
		} else {
			msg = &wrappers.StringValue{Value: t}
		}
	case bool:
		msg = &wrappers.BoolValue{Value: t}
	case float32:
		msg = &wrappers.FloatValue{Value: t}
	case float64:
		msg = &wrappers.DoubleValue{Value: t}
	case int64:
		msg = &wrappers.Int64Value{Value: t}
	case int:
		msg = &wrappers.Int32Value{Value: int32(t)}
	case int32:
		msg = &wrappers.Int32Value{Value: t}
	case uint32:
		msg = &wrappers.UInt32Value{Value: t}
	case uint64:
		msg = &wrappers.UInt64Value{Value: t}
	case []byte:
		msg = &wrappers.BytesValue{Value: t}
	case nil:
		msg = &NilValue{}
	default:
		return nil, errors.Wrapf(ErrUnsupportedType, "parse %T", t)
	}
	marshaled, err := marshalAny(msg)
	if err != nil {
		return nil, err
	}
	return &TypedValue{
		Value: marshaled,
	}, nil
}
func MustWrap(val interface{}) *TypedValue {
	tv, err := Wrap(val)
	if err != nil {
		panic(err)
	}
	return tv
}
func MustUnwrap(tv *TypedValue) interface{} {
	i, err := Unwrap(tv)
	if err != nil {
		panic(err)
	}
	return i
}
func UnwrapString(tv *TypedValue) (string, error) {
	i, err := Unwrap(tv)
	if err != nil {
		return "", err
	}
	if s, ok := i.(string); ok {
		return s, nil
	}
	if bs, ok := i.([]byte); ok {
		return string(bs), nil
	}
	return "", errors.Wrapf(ErrIllegalTypeAssertion, "failed to unwrap %s to string", tv.ValueType())
}
func UnwrapProto(tv *TypedValue) (proto.Message, error) {
	var dynamic ptypes.DynamicAny
	err := ptypes.UnmarshalAny(tv.Value, &dynamic)
	if err != nil {
		return nil, errors.WithStack(err)
	}
	return dynamic.Message, nil
}
func UnwrapBytes(tv *TypedValue) ([]byte, error) {
	i, err := Unwrap(tv)
	if err != nil {
		return nil, err
	}
	if d, ok := i.([]byte); ok {
		return d, nil
	}
	if s, ok := i.(string); ok {
		return []byte(s), nil
	}
	return nil, errors.Wrapf(ErrIllegalTypeAssertion, "failed to unwrap %s to bytes", tv.ValueType())
}
func UnwrapBool(tv *TypedValue) (bool, error) {
	i, err := Unwrap(tv)
	if err != nil {
		return false, err
	}
	s, ok := i.(bool)
	if !ok {
		return false, errors.Wrapf(ErrIllegalTypeAssertion, "failed to unwrap %s to bool", tv.ValueType())
	}
	return s, nil
}
func UnwrapArray(tv *TypedValue) ([]interface{}, error) {
	i, err := Unwrap(tv)
	if err != nil {
		return nil, err
	}
	s, ok := i.([]interface{})
	if !ok {
		return nil, errors.Wrapf(ErrIllegalTypeAssertion, "failed to unwrap %s to array", tv.ValueType())
	}
	return s, nil
}
func UnwrapTypedValueArray(tv *TypedValue) ([]*TypedValue, error) {
	arrayWrapper := &ArrayValue{}
	err := ptypes.UnmarshalAny(tv.Value, arrayWrapper)
	if err != nil {
		return nil, errors.Wrapf(ErrIllegalTypeAssertion, "failed to unwrap %s to TypedValue-array", tv.ValueType())
	}
	arrayValue := make([]*TypedValue, len(arrayWrapper.Value))
	for k, v := range arrayWrapper.Value {
		arrayValue[k] = v
	}
	return arrayValue, nil
}
func UnwrapTypedValueMap(tv *TypedValue) (map[string]*TypedValue, error) {
	mapWrapper := &MapValue{}
	err := ptypes.UnmarshalAny(tv.Value, mapWrapper)
	if err != nil {
		return nil, errors.Wrapf(ErrIllegalTypeAssertion, "failed to unwrap %s to TypedValue-map", tv.ValueType())
	}
	mapValue := make(map[string]*TypedValue, len(mapWrapper.Value))
	for k, v := range mapWrapper.Value {
		mapValue[k] = v
	}
	return mapValue, nil
}
func UnwrapMapTypedValue(tvs map[string]*TypedValue) (map[string]interface{}, error) {
	tv, err := Wrap(tvs)
	if err != nil {
		return nil, err
	}
	return UnwrapMap(tv)
}
func WrapMapTypedValue(tvs map[string]interface{}) (map[string]*TypedValue, error) {
	entries := make(map[string]*TypedValue, len(tvs))
	for k, v := range tvs {
		e, err := Wrap(v)
		if err != nil {
			return nil, err
		}
		entries[k] = e
	}
	return entries, nil
}
func MustWrapMapTypedValue(tvs map[string]interface{}) map[string]*TypedValue {
	tv, err := WrapMapTypedValue(tvs)
	if err != nil {
		panic(err)
	}
	return tv
}
func UnwrapMap(tv *TypedValue) (map[string]interface{}, error) {
	i, err := Unwrap(tv)
	if err != nil {
		return nil, err
	}
	s, ok := i.(map[string]interface{})
	if !ok {
		return nil, errors.Wrapf(ErrIllegalTypeAssertion, "failed to unwrap %s to map", tv.ValueType())
	}
	return s, nil
}