xref: /aosp_15_r20/external/golang-protobuf/testing/protocmp/xform.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
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