1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsen// Package protocmp provides protobuf specific options for the 6*1c12ee1eSDan Willemsen// "github.com/google/go-cmp/cmp" package. 7*1c12ee1eSDan Willemsen// 8*1c12ee1eSDan Willemsen// The primary feature is the Transform option, which transform proto.Message 9*1c12ee1eSDan Willemsen// types into a Message map that is suitable for cmp to introspect upon. 10*1c12ee1eSDan Willemsen// All other options in this package must be used in conjunction with Transform. 11*1c12ee1eSDan Willemsenpackage protocmp 12*1c12ee1eSDan Willemsen 13*1c12ee1eSDan Willemsenimport ( 14*1c12ee1eSDan Willemsen "reflect" 15*1c12ee1eSDan Willemsen "strconv" 16*1c12ee1eSDan Willemsen 17*1c12ee1eSDan Willemsen "github.com/google/go-cmp/cmp" 18*1c12ee1eSDan Willemsen 19*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/protowire" 20*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/genid" 21*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/msgfmt" 22*1c12ee1eSDan Willemsen "google.golang.org/protobuf/proto" 23*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 24*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoregistry" 25*1c12ee1eSDan Willemsen "google.golang.org/protobuf/runtime/protoiface" 26*1c12ee1eSDan Willemsen "google.golang.org/protobuf/runtime/protoimpl" 27*1c12ee1eSDan Willemsen) 28*1c12ee1eSDan Willemsen 29*1c12ee1eSDan Willemsenvar ( 30*1c12ee1eSDan Willemsen enumV2Type = reflect.TypeOf((*protoreflect.Enum)(nil)).Elem() 31*1c12ee1eSDan Willemsen messageV1Type = reflect.TypeOf((*protoiface.MessageV1)(nil)).Elem() 32*1c12ee1eSDan Willemsen messageV2Type = reflect.TypeOf((*proto.Message)(nil)).Elem() 33*1c12ee1eSDan Willemsen) 34*1c12ee1eSDan Willemsen 35*1c12ee1eSDan Willemsen// Enum is a dynamic representation of a protocol buffer enum that is 36*1c12ee1eSDan Willemsen// suitable for cmp.Equal and cmp.Diff to compare upon. 37*1c12ee1eSDan Willemsentype Enum struct { 38*1c12ee1eSDan Willemsen num protoreflect.EnumNumber 39*1c12ee1eSDan Willemsen ed protoreflect.EnumDescriptor 40*1c12ee1eSDan Willemsen} 41*1c12ee1eSDan Willemsen 42*1c12ee1eSDan Willemsen// Descriptor returns the enum descriptor. 43*1c12ee1eSDan Willemsen// It returns nil for a zero Enum value. 44*1c12ee1eSDan Willemsenfunc (e Enum) Descriptor() protoreflect.EnumDescriptor { 45*1c12ee1eSDan Willemsen return e.ed 46*1c12ee1eSDan Willemsen} 47*1c12ee1eSDan Willemsen 48*1c12ee1eSDan Willemsen// Number returns the enum value as an integer. 49*1c12ee1eSDan Willemsenfunc (e Enum) Number() protoreflect.EnumNumber { 50*1c12ee1eSDan Willemsen return e.num 51*1c12ee1eSDan Willemsen} 52*1c12ee1eSDan Willemsen 53*1c12ee1eSDan Willemsen// Equal reports whether e1 and e2 represent the same enum value. 54*1c12ee1eSDan Willemsenfunc (e1 Enum) Equal(e2 Enum) bool { 55*1c12ee1eSDan Willemsen if e1.ed.FullName() != e2.ed.FullName() { 56*1c12ee1eSDan Willemsen return false 57*1c12ee1eSDan Willemsen } 58*1c12ee1eSDan Willemsen return e1.num == e2.num 59*1c12ee1eSDan Willemsen} 60*1c12ee1eSDan Willemsen 61*1c12ee1eSDan Willemsen// String returns the name of the enum value if known (e.g., "ENUM_VALUE"), 62*1c12ee1eSDan Willemsen// otherwise it returns the formatted decimal enum number (e.g., "14"). 63*1c12ee1eSDan Willemsenfunc (e Enum) String() string { 64*1c12ee1eSDan Willemsen if ev := e.ed.Values().ByNumber(e.num); ev != nil { 65*1c12ee1eSDan Willemsen return string(ev.Name()) 66*1c12ee1eSDan Willemsen } 67*1c12ee1eSDan Willemsen return strconv.Itoa(int(e.num)) 68*1c12ee1eSDan Willemsen} 69*1c12ee1eSDan Willemsen 70*1c12ee1eSDan Willemsenconst ( 71*1c12ee1eSDan Willemsen // messageTypeKey indicates the protobuf message type. 72*1c12ee1eSDan Willemsen // The value type is always messageMeta. 73*1c12ee1eSDan Willemsen // From the public API, it presents itself as only the type, but the 74*1c12ee1eSDan Willemsen // underlying data structure holds arbitrary metadata about the message. 75*1c12ee1eSDan Willemsen messageTypeKey = "@type" 76*1c12ee1eSDan Willemsen 77*1c12ee1eSDan Willemsen // messageInvalidKey indicates that the message is invalid. 78*1c12ee1eSDan Willemsen // The value is always the boolean "true". 79*1c12ee1eSDan Willemsen messageInvalidKey = "@invalid" 80*1c12ee1eSDan Willemsen) 81*1c12ee1eSDan Willemsen 82*1c12ee1eSDan Willemsentype messageMeta struct { 83*1c12ee1eSDan Willemsen m proto.Message 84*1c12ee1eSDan Willemsen md protoreflect.MessageDescriptor 85*1c12ee1eSDan Willemsen xds map[string]protoreflect.ExtensionDescriptor 86*1c12ee1eSDan Willemsen} 87*1c12ee1eSDan Willemsen 88*1c12ee1eSDan Willemsenfunc (t messageMeta) String() string { 89*1c12ee1eSDan Willemsen return string(t.md.FullName()) 90*1c12ee1eSDan Willemsen} 91*1c12ee1eSDan Willemsen 92*1c12ee1eSDan Willemsenfunc (t1 messageMeta) Equal(t2 messageMeta) bool { 93*1c12ee1eSDan Willemsen return t1.md.FullName() == t2.md.FullName() 94*1c12ee1eSDan Willemsen} 95*1c12ee1eSDan Willemsen 96*1c12ee1eSDan Willemsen// Message is a dynamic representation of a protocol buffer message that is 97*1c12ee1eSDan Willemsen// suitable for cmp.Equal and cmp.Diff to directly operate upon. 98*1c12ee1eSDan Willemsen// 99*1c12ee1eSDan Willemsen// Every populated known field (excluding extension fields) is stored in the map 100*1c12ee1eSDan Willemsen// with the key being the short name of the field (e.g., "field_name") and 101*1c12ee1eSDan Willemsen// the value determined by the kind and cardinality of the field. 102*1c12ee1eSDan Willemsen// 103*1c12ee1eSDan Willemsen// Singular scalars are represented by the same Go type as protoreflect.Value, 104*1c12ee1eSDan Willemsen// singular messages are represented by the Message type, 105*1c12ee1eSDan Willemsen// singular enums are represented by the Enum type, 106*1c12ee1eSDan Willemsen// list fields are represented as a Go slice, and 107*1c12ee1eSDan Willemsen// map fields are represented as a Go map. 108*1c12ee1eSDan Willemsen// 109*1c12ee1eSDan Willemsen// Every populated extension field is stored in the map with the key being the 110*1c12ee1eSDan Willemsen// full name of the field surrounded by brackets (e.g., "[extension.full.name]") 111*1c12ee1eSDan Willemsen// and the value determined according to the same rules as known fields. 112*1c12ee1eSDan Willemsen// 113*1c12ee1eSDan Willemsen// Every unknown field is stored in the map with the key being the field number 114*1c12ee1eSDan Willemsen// encoded as a decimal string (e.g., "132") and the value being the raw bytes 115*1c12ee1eSDan Willemsen// of the encoded field (as the protoreflect.RawFields type). 116*1c12ee1eSDan Willemsen// 117*1c12ee1eSDan Willemsen// Message values must not be created by or mutated by users. 118*1c12ee1eSDan Willemsentype Message map[string]interface{} 119*1c12ee1eSDan Willemsen 120*1c12ee1eSDan Willemsen// Unwrap returns the original message value. 121*1c12ee1eSDan Willemsen// It returns nil if this Message was not constructed from another message. 122*1c12ee1eSDan Willemsenfunc (m Message) Unwrap() proto.Message { 123*1c12ee1eSDan Willemsen mm, _ := m[messageTypeKey].(messageMeta) 124*1c12ee1eSDan Willemsen return mm.m 125*1c12ee1eSDan Willemsen} 126*1c12ee1eSDan Willemsen 127*1c12ee1eSDan Willemsen// Descriptor return the message descriptor. 128*1c12ee1eSDan Willemsen// It returns nil for a zero Message value. 129*1c12ee1eSDan Willemsenfunc (m Message) Descriptor() protoreflect.MessageDescriptor { 130*1c12ee1eSDan Willemsen mm, _ := m[messageTypeKey].(messageMeta) 131*1c12ee1eSDan Willemsen return mm.md 132*1c12ee1eSDan Willemsen} 133*1c12ee1eSDan Willemsen 134*1c12ee1eSDan Willemsen// ProtoReflect returns a reflective view of m. 135*1c12ee1eSDan Willemsen// It only implements the read-only operations of protoreflect.Message. 136*1c12ee1eSDan Willemsen// Calling any mutating operations on m panics. 137*1c12ee1eSDan Willemsenfunc (m Message) ProtoReflect() protoreflect.Message { 138*1c12ee1eSDan Willemsen return (reflectMessage)(m) 139*1c12ee1eSDan Willemsen} 140*1c12ee1eSDan Willemsen 141*1c12ee1eSDan Willemsen// ProtoMessage is a marker method from the legacy message interface. 142*1c12ee1eSDan Willemsenfunc (m Message) ProtoMessage() {} 143*1c12ee1eSDan Willemsen 144*1c12ee1eSDan Willemsen// Reset is the required Reset method from the legacy message interface. 145*1c12ee1eSDan Willemsenfunc (m Message) Reset() { 146*1c12ee1eSDan Willemsen panic("invalid mutation of a read-only message") 147*1c12ee1eSDan Willemsen} 148*1c12ee1eSDan Willemsen 149*1c12ee1eSDan Willemsen// String returns a formatted string for the message. 150*1c12ee1eSDan Willemsen// It is intended for human debugging and has no guarantees about its 151*1c12ee1eSDan Willemsen// exact format or the stability of its output. 152*1c12ee1eSDan Willemsenfunc (m Message) String() string { 153*1c12ee1eSDan Willemsen switch { 154*1c12ee1eSDan Willemsen case m == nil: 155*1c12ee1eSDan Willemsen return "<nil>" 156*1c12ee1eSDan Willemsen case !m.ProtoReflect().IsValid(): 157*1c12ee1eSDan Willemsen return "<invalid>" 158*1c12ee1eSDan Willemsen default: 159*1c12ee1eSDan Willemsen return msgfmt.Format(m) 160*1c12ee1eSDan Willemsen } 161*1c12ee1eSDan Willemsen} 162*1c12ee1eSDan Willemsen 163*1c12ee1eSDan Willemsentype option struct{} 164*1c12ee1eSDan Willemsen 165*1c12ee1eSDan Willemsen// Transform returns a cmp.Option that converts each proto.Message to a Message. 166*1c12ee1eSDan Willemsen// The transformation does not mutate nor alias any converted messages. 167*1c12ee1eSDan Willemsen// 168*1c12ee1eSDan Willemsen// The google.protobuf.Any message is automatically unmarshaled such that the 169*1c12ee1eSDan Willemsen// "value" field is a Message representing the underlying message value 170*1c12ee1eSDan Willemsen// assuming it could be resolved and properly unmarshaled. 171*1c12ee1eSDan Willemsen// 172*1c12ee1eSDan Willemsen// This does not directly transform higher-order composite Go types. 173*1c12ee1eSDan Willemsen// For example, []*foopb.Message is not transformed into []Message, 174*1c12ee1eSDan Willemsen// but rather the individual message elements of the slice are transformed. 175*1c12ee1eSDan Willemsen// 176*1c12ee1eSDan Willemsen// Note that there are currently no custom options for Transform, 177*1c12ee1eSDan Willemsen// but the use of an unexported type keeps the future open. 178*1c12ee1eSDan Willemsenfunc Transform(...option) cmp.Option { 179*1c12ee1eSDan Willemsen // addrType returns a pointer to t if t isn't a pointer or interface. 180*1c12ee1eSDan Willemsen addrType := func(t reflect.Type) reflect.Type { 181*1c12ee1eSDan Willemsen if k := t.Kind(); k == reflect.Interface || k == reflect.Ptr { 182*1c12ee1eSDan Willemsen return t 183*1c12ee1eSDan Willemsen } 184*1c12ee1eSDan Willemsen return reflect.PtrTo(t) 185*1c12ee1eSDan Willemsen } 186*1c12ee1eSDan Willemsen 187*1c12ee1eSDan Willemsen // TODO: Should this transform protoreflect.Enum types to Enum as well? 188*1c12ee1eSDan Willemsen return cmp.FilterPath(func(p cmp.Path) bool { 189*1c12ee1eSDan Willemsen ps := p.Last() 190*1c12ee1eSDan Willemsen if isMessageType(addrType(ps.Type())) { 191*1c12ee1eSDan Willemsen return true 192*1c12ee1eSDan Willemsen } 193*1c12ee1eSDan Willemsen 194*1c12ee1eSDan Willemsen // Check whether the concrete values of an interface both satisfy 195*1c12ee1eSDan Willemsen // the Message interface. 196*1c12ee1eSDan Willemsen if ps.Type().Kind() == reflect.Interface { 197*1c12ee1eSDan Willemsen vx, vy := ps.Values() 198*1c12ee1eSDan Willemsen if !vx.IsValid() || vx.IsNil() || !vy.IsValid() || vy.IsNil() { 199*1c12ee1eSDan Willemsen return false 200*1c12ee1eSDan Willemsen } 201*1c12ee1eSDan Willemsen return isMessageType(addrType(vx.Elem().Type())) && isMessageType(addrType(vy.Elem().Type())) 202*1c12ee1eSDan Willemsen } 203*1c12ee1eSDan Willemsen 204*1c12ee1eSDan Willemsen return false 205*1c12ee1eSDan Willemsen }, cmp.Transformer("protocmp.Transform", func(v interface{}) Message { 206*1c12ee1eSDan Willemsen // For user convenience, shallow copy the message value if necessary 207*1c12ee1eSDan Willemsen // in order for it to implement the message interface. 208*1c12ee1eSDan Willemsen if rv := reflect.ValueOf(v); rv.IsValid() && rv.Kind() != reflect.Ptr && !isMessageType(rv.Type()) { 209*1c12ee1eSDan Willemsen pv := reflect.New(rv.Type()) 210*1c12ee1eSDan Willemsen pv.Elem().Set(rv) 211*1c12ee1eSDan Willemsen v = pv.Interface() 212*1c12ee1eSDan Willemsen } 213*1c12ee1eSDan Willemsen 214*1c12ee1eSDan Willemsen m := protoimpl.X.MessageOf(v) 215*1c12ee1eSDan Willemsen switch { 216*1c12ee1eSDan Willemsen case m == nil: 217*1c12ee1eSDan Willemsen return nil 218*1c12ee1eSDan Willemsen case !m.IsValid(): 219*1c12ee1eSDan Willemsen return Message{messageTypeKey: messageMeta{m: m.Interface(), md: m.Descriptor()}, messageInvalidKey: true} 220*1c12ee1eSDan Willemsen default: 221*1c12ee1eSDan Willemsen return transformMessage(m) 222*1c12ee1eSDan Willemsen } 223*1c12ee1eSDan Willemsen })) 224*1c12ee1eSDan Willemsen} 225*1c12ee1eSDan Willemsen 226*1c12ee1eSDan Willemsenfunc isMessageType(t reflect.Type) bool { 227*1c12ee1eSDan Willemsen // Avoid transforming the Message itself. 228*1c12ee1eSDan Willemsen if t == reflect.TypeOf(Message(nil)) || t == reflect.TypeOf((*Message)(nil)) { 229*1c12ee1eSDan Willemsen return false 230*1c12ee1eSDan Willemsen } 231*1c12ee1eSDan Willemsen return t.Implements(messageV1Type) || t.Implements(messageV2Type) 232*1c12ee1eSDan Willemsen} 233*1c12ee1eSDan Willemsen 234*1c12ee1eSDan Willemsenfunc transformMessage(m protoreflect.Message) Message { 235*1c12ee1eSDan Willemsen mx := Message{} 236*1c12ee1eSDan Willemsen mt := messageMeta{m: m.Interface(), md: m.Descriptor(), xds: make(map[string]protoreflect.FieldDescriptor)} 237*1c12ee1eSDan Willemsen 238*1c12ee1eSDan Willemsen // Handle known and extension fields. 239*1c12ee1eSDan Willemsen m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { 240*1c12ee1eSDan Willemsen s := fd.TextName() 241*1c12ee1eSDan Willemsen if fd.IsExtension() { 242*1c12ee1eSDan Willemsen mt.xds[s] = fd 243*1c12ee1eSDan Willemsen } 244*1c12ee1eSDan Willemsen switch { 245*1c12ee1eSDan Willemsen case fd.IsList(): 246*1c12ee1eSDan Willemsen mx[s] = transformList(fd, v.List()) 247*1c12ee1eSDan Willemsen case fd.IsMap(): 248*1c12ee1eSDan Willemsen mx[s] = transformMap(fd, v.Map()) 249*1c12ee1eSDan Willemsen default: 250*1c12ee1eSDan Willemsen mx[s] = transformSingular(fd, v) 251*1c12ee1eSDan Willemsen } 252*1c12ee1eSDan Willemsen return true 253*1c12ee1eSDan Willemsen }) 254*1c12ee1eSDan Willemsen 255*1c12ee1eSDan Willemsen // Handle unknown fields. 256*1c12ee1eSDan Willemsen for b := m.GetUnknown(); len(b) > 0; { 257*1c12ee1eSDan Willemsen num, _, n := protowire.ConsumeField(b) 258*1c12ee1eSDan Willemsen s := strconv.Itoa(int(num)) 259*1c12ee1eSDan Willemsen b2, _ := mx[s].(protoreflect.RawFields) 260*1c12ee1eSDan Willemsen mx[s] = append(b2, b[:n]...) 261*1c12ee1eSDan Willemsen b = b[n:] 262*1c12ee1eSDan Willemsen } 263*1c12ee1eSDan Willemsen 264*1c12ee1eSDan Willemsen // Expand Any messages. 265*1c12ee1eSDan Willemsen if mt.md.FullName() == genid.Any_message_fullname { 266*1c12ee1eSDan Willemsen // TODO: Expose Transform option to specify a custom resolver? 267*1c12ee1eSDan Willemsen s, _ := mx[string(genid.Any_TypeUrl_field_name)].(string) 268*1c12ee1eSDan Willemsen b, _ := mx[string(genid.Any_Value_field_name)].([]byte) 269*1c12ee1eSDan Willemsen mt, err := protoregistry.GlobalTypes.FindMessageByURL(s) 270*1c12ee1eSDan Willemsen if mt != nil && err == nil { 271*1c12ee1eSDan Willemsen m2 := mt.New() 272*1c12ee1eSDan Willemsen err := proto.UnmarshalOptions{AllowPartial: true}.Unmarshal(b, m2.Interface()) 273*1c12ee1eSDan Willemsen if err == nil { 274*1c12ee1eSDan Willemsen mx[string(genid.Any_Value_field_name)] = transformMessage(m2) 275*1c12ee1eSDan Willemsen } 276*1c12ee1eSDan Willemsen } 277*1c12ee1eSDan Willemsen } 278*1c12ee1eSDan Willemsen 279*1c12ee1eSDan Willemsen mx[messageTypeKey] = mt 280*1c12ee1eSDan Willemsen return mx 281*1c12ee1eSDan Willemsen} 282*1c12ee1eSDan Willemsen 283*1c12ee1eSDan Willemsenfunc transformList(fd protoreflect.FieldDescriptor, lv protoreflect.List) interface{} { 284*1c12ee1eSDan Willemsen t := protoKindToGoType(fd.Kind()) 285*1c12ee1eSDan Willemsen rv := reflect.MakeSlice(reflect.SliceOf(t), lv.Len(), lv.Len()) 286*1c12ee1eSDan Willemsen for i := 0; i < lv.Len(); i++ { 287*1c12ee1eSDan Willemsen v := reflect.ValueOf(transformSingular(fd, lv.Get(i))) 288*1c12ee1eSDan Willemsen rv.Index(i).Set(v) 289*1c12ee1eSDan Willemsen } 290*1c12ee1eSDan Willemsen return rv.Interface() 291*1c12ee1eSDan Willemsen} 292*1c12ee1eSDan Willemsen 293*1c12ee1eSDan Willemsenfunc transformMap(fd protoreflect.FieldDescriptor, mv protoreflect.Map) interface{} { 294*1c12ee1eSDan Willemsen kfd := fd.MapKey() 295*1c12ee1eSDan Willemsen vfd := fd.MapValue() 296*1c12ee1eSDan Willemsen kt := protoKindToGoType(kfd.Kind()) 297*1c12ee1eSDan Willemsen vt := protoKindToGoType(vfd.Kind()) 298*1c12ee1eSDan Willemsen rv := reflect.MakeMapWithSize(reflect.MapOf(kt, vt), mv.Len()) 299*1c12ee1eSDan Willemsen mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { 300*1c12ee1eSDan Willemsen kv := reflect.ValueOf(transformSingular(kfd, k.Value())) 301*1c12ee1eSDan Willemsen vv := reflect.ValueOf(transformSingular(vfd, v)) 302*1c12ee1eSDan Willemsen rv.SetMapIndex(kv, vv) 303*1c12ee1eSDan Willemsen return true 304*1c12ee1eSDan Willemsen }) 305*1c12ee1eSDan Willemsen return rv.Interface() 306*1c12ee1eSDan Willemsen} 307*1c12ee1eSDan Willemsen 308*1c12ee1eSDan Willemsenfunc transformSingular(fd protoreflect.FieldDescriptor, v protoreflect.Value) interface{} { 309*1c12ee1eSDan Willemsen switch fd.Kind() { 310*1c12ee1eSDan Willemsen case protoreflect.EnumKind: 311*1c12ee1eSDan Willemsen return Enum{num: v.Enum(), ed: fd.Enum()} 312*1c12ee1eSDan Willemsen case protoreflect.MessageKind, protoreflect.GroupKind: 313*1c12ee1eSDan Willemsen return transformMessage(v.Message()) 314*1c12ee1eSDan Willemsen case protoreflect.BytesKind: 315*1c12ee1eSDan Willemsen // The protoreflect API does not specify whether an empty bytes is 316*1c12ee1eSDan Willemsen // guaranteed to be nil or not. Always return non-nil bytes to avoid 317*1c12ee1eSDan Willemsen // leaking information about the concrete proto.Message implementation. 318*1c12ee1eSDan Willemsen if len(v.Bytes()) == 0 { 319*1c12ee1eSDan Willemsen return []byte{} 320*1c12ee1eSDan Willemsen } 321*1c12ee1eSDan Willemsen return v.Bytes() 322*1c12ee1eSDan Willemsen default: 323*1c12ee1eSDan Willemsen return v.Interface() 324*1c12ee1eSDan Willemsen } 325*1c12ee1eSDan Willemsen} 326*1c12ee1eSDan Willemsen 327*1c12ee1eSDan Willemsenfunc protoKindToGoType(k protoreflect.Kind) reflect.Type { 328*1c12ee1eSDan Willemsen switch k { 329*1c12ee1eSDan Willemsen case protoreflect.BoolKind: 330*1c12ee1eSDan Willemsen return reflect.TypeOf(bool(false)) 331*1c12ee1eSDan Willemsen case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: 332*1c12ee1eSDan Willemsen return reflect.TypeOf(int32(0)) 333*1c12ee1eSDan Willemsen case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: 334*1c12ee1eSDan Willemsen return reflect.TypeOf(int64(0)) 335*1c12ee1eSDan Willemsen case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: 336*1c12ee1eSDan Willemsen return reflect.TypeOf(uint32(0)) 337*1c12ee1eSDan Willemsen case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: 338*1c12ee1eSDan Willemsen return reflect.TypeOf(uint64(0)) 339*1c12ee1eSDan Willemsen case protoreflect.FloatKind: 340*1c12ee1eSDan Willemsen return reflect.TypeOf(float32(0)) 341*1c12ee1eSDan Willemsen case protoreflect.DoubleKind: 342*1c12ee1eSDan Willemsen return reflect.TypeOf(float64(0)) 343*1c12ee1eSDan Willemsen case protoreflect.StringKind: 344*1c12ee1eSDan Willemsen return reflect.TypeOf(string("")) 345*1c12ee1eSDan Willemsen case protoreflect.BytesKind: 346*1c12ee1eSDan Willemsen return reflect.TypeOf([]byte(nil)) 347*1c12ee1eSDan Willemsen case protoreflect.EnumKind: 348*1c12ee1eSDan Willemsen return reflect.TypeOf(Enum{}) 349*1c12ee1eSDan Willemsen case protoreflect.MessageKind, protoreflect.GroupKind: 350*1c12ee1eSDan Willemsen return reflect.TypeOf(Message{}) 351*1c12ee1eSDan Willemsen default: 352*1c12ee1eSDan Willemsen panic("invalid kind") 353*1c12ee1eSDan Willemsen } 354*1c12ee1eSDan Willemsen} 355