xref: /aosp_15_r20/external/golang-protobuf/internal/impl/legacy_message.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1*1c12ee1eSDan Willemsen// Copyright 2018 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 Willemsenpackage impl
6*1c12ee1eSDan Willemsen
7*1c12ee1eSDan Willemsenimport (
8*1c12ee1eSDan Willemsen	"fmt"
9*1c12ee1eSDan Willemsen	"reflect"
10*1c12ee1eSDan Willemsen	"strings"
11*1c12ee1eSDan Willemsen	"sync"
12*1c12ee1eSDan Willemsen
13*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/descopts"
14*1c12ee1eSDan Willemsen	ptag "google.golang.org/protobuf/internal/encoding/tag"
15*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/errors"
16*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/filedesc"
17*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/strs"
18*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoreflect"
19*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/runtime/protoiface"
20*1c12ee1eSDan Willemsen)
21*1c12ee1eSDan Willemsen
22*1c12ee1eSDan Willemsen// legacyWrapMessage wraps v as a protoreflect.Message,
23*1c12ee1eSDan Willemsen// where v must be a *struct kind and not implement the v2 API already.
24*1c12ee1eSDan Willemsenfunc legacyWrapMessage(v reflect.Value) protoreflect.Message {
25*1c12ee1eSDan Willemsen	t := v.Type()
26*1c12ee1eSDan Willemsen	if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
27*1c12ee1eSDan Willemsen		return aberrantMessage{v: v}
28*1c12ee1eSDan Willemsen	}
29*1c12ee1eSDan Willemsen	mt := legacyLoadMessageInfo(t, "")
30*1c12ee1eSDan Willemsen	return mt.MessageOf(v.Interface())
31*1c12ee1eSDan Willemsen}
32*1c12ee1eSDan Willemsen
33*1c12ee1eSDan Willemsen// legacyLoadMessageType dynamically loads a protoreflect.Type for t,
34*1c12ee1eSDan Willemsen// where t must be not implement the v2 API already.
35*1c12ee1eSDan Willemsen// The provided name is used if it cannot be determined from the message.
36*1c12ee1eSDan Willemsenfunc legacyLoadMessageType(t reflect.Type, name protoreflect.FullName) protoreflect.MessageType {
37*1c12ee1eSDan Willemsen	if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
38*1c12ee1eSDan Willemsen		return aberrantMessageType{t}
39*1c12ee1eSDan Willemsen	}
40*1c12ee1eSDan Willemsen	return legacyLoadMessageInfo(t, name)
41*1c12ee1eSDan Willemsen}
42*1c12ee1eSDan Willemsen
43*1c12ee1eSDan Willemsenvar legacyMessageTypeCache sync.Map // map[reflect.Type]*MessageInfo
44*1c12ee1eSDan Willemsen
45*1c12ee1eSDan Willemsen// legacyLoadMessageInfo dynamically loads a *MessageInfo for t,
46*1c12ee1eSDan Willemsen// where t must be a *struct kind and not implement the v2 API already.
47*1c12ee1eSDan Willemsen// The provided name is used if it cannot be determined from the message.
48*1c12ee1eSDan Willemsenfunc legacyLoadMessageInfo(t reflect.Type, name protoreflect.FullName) *MessageInfo {
49*1c12ee1eSDan Willemsen	// Fast-path: check if a MessageInfo is cached for this concrete type.
50*1c12ee1eSDan Willemsen	if mt, ok := legacyMessageTypeCache.Load(t); ok {
51*1c12ee1eSDan Willemsen		return mt.(*MessageInfo)
52*1c12ee1eSDan Willemsen	}
53*1c12ee1eSDan Willemsen
54*1c12ee1eSDan Willemsen	// Slow-path: derive message descriptor and initialize MessageInfo.
55*1c12ee1eSDan Willemsen	mi := &MessageInfo{
56*1c12ee1eSDan Willemsen		Desc:          legacyLoadMessageDesc(t, name),
57*1c12ee1eSDan Willemsen		GoReflectType: t,
58*1c12ee1eSDan Willemsen	}
59*1c12ee1eSDan Willemsen
60*1c12ee1eSDan Willemsen	var hasMarshal, hasUnmarshal bool
61*1c12ee1eSDan Willemsen	v := reflect.Zero(t).Interface()
62*1c12ee1eSDan Willemsen	if _, hasMarshal = v.(legacyMarshaler); hasMarshal {
63*1c12ee1eSDan Willemsen		mi.methods.Marshal = legacyMarshal
64*1c12ee1eSDan Willemsen
65*1c12ee1eSDan Willemsen		// We have no way to tell whether the type's Marshal method
66*1c12ee1eSDan Willemsen		// supports deterministic serialization or not, but this
67*1c12ee1eSDan Willemsen		// preserves the v1 implementation's behavior of always
68*1c12ee1eSDan Willemsen		// calling Marshal methods when present.
69*1c12ee1eSDan Willemsen		mi.methods.Flags |= protoiface.SupportMarshalDeterministic
70*1c12ee1eSDan Willemsen	}
71*1c12ee1eSDan Willemsen	if _, hasUnmarshal = v.(legacyUnmarshaler); hasUnmarshal {
72*1c12ee1eSDan Willemsen		mi.methods.Unmarshal = legacyUnmarshal
73*1c12ee1eSDan Willemsen	}
74*1c12ee1eSDan Willemsen	if _, hasMerge := v.(legacyMerger); hasMerge || (hasMarshal && hasUnmarshal) {
75*1c12ee1eSDan Willemsen		mi.methods.Merge = legacyMerge
76*1c12ee1eSDan Willemsen	}
77*1c12ee1eSDan Willemsen
78*1c12ee1eSDan Willemsen	if mi, ok := legacyMessageTypeCache.LoadOrStore(t, mi); ok {
79*1c12ee1eSDan Willemsen		return mi.(*MessageInfo)
80*1c12ee1eSDan Willemsen	}
81*1c12ee1eSDan Willemsen	return mi
82*1c12ee1eSDan Willemsen}
83*1c12ee1eSDan Willemsen
84*1c12ee1eSDan Willemsenvar legacyMessageDescCache sync.Map // map[reflect.Type]protoreflect.MessageDescriptor
85*1c12ee1eSDan Willemsen
86*1c12ee1eSDan Willemsen// LegacyLoadMessageDesc returns an MessageDescriptor derived from the Go type,
87*1c12ee1eSDan Willemsen// which should be a *struct kind and must not implement the v2 API already.
88*1c12ee1eSDan Willemsen//
89*1c12ee1eSDan Willemsen// This is exported for testing purposes.
90*1c12ee1eSDan Willemsenfunc LegacyLoadMessageDesc(t reflect.Type) protoreflect.MessageDescriptor {
91*1c12ee1eSDan Willemsen	return legacyLoadMessageDesc(t, "")
92*1c12ee1eSDan Willemsen}
93*1c12ee1eSDan Willemsenfunc legacyLoadMessageDesc(t reflect.Type, name protoreflect.FullName) protoreflect.MessageDescriptor {
94*1c12ee1eSDan Willemsen	// Fast-path: check if a MessageDescriptor is cached for this concrete type.
95*1c12ee1eSDan Willemsen	if mi, ok := legacyMessageDescCache.Load(t); ok {
96*1c12ee1eSDan Willemsen		return mi.(protoreflect.MessageDescriptor)
97*1c12ee1eSDan Willemsen	}
98*1c12ee1eSDan Willemsen
99*1c12ee1eSDan Willemsen	// Slow-path: initialize MessageDescriptor from the raw descriptor.
100*1c12ee1eSDan Willemsen	mv := reflect.Zero(t).Interface()
101*1c12ee1eSDan Willemsen	if _, ok := mv.(protoreflect.ProtoMessage); ok {
102*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("%v already implements proto.Message", t))
103*1c12ee1eSDan Willemsen	}
104*1c12ee1eSDan Willemsen	mdV1, ok := mv.(messageV1)
105*1c12ee1eSDan Willemsen	if !ok {
106*1c12ee1eSDan Willemsen		return aberrantLoadMessageDesc(t, name)
107*1c12ee1eSDan Willemsen	}
108*1c12ee1eSDan Willemsen
109*1c12ee1eSDan Willemsen	// If this is a dynamic message type where there isn't a 1-1 mapping between
110*1c12ee1eSDan Willemsen	// Go and protobuf types, calling the Descriptor method on the zero value of
111*1c12ee1eSDan Willemsen	// the message type isn't likely to work. If it panics, swallow the panic and
112*1c12ee1eSDan Willemsen	// continue as if the Descriptor method wasn't present.
113*1c12ee1eSDan Willemsen	b, idxs := func() ([]byte, []int) {
114*1c12ee1eSDan Willemsen		defer func() {
115*1c12ee1eSDan Willemsen			recover()
116*1c12ee1eSDan Willemsen		}()
117*1c12ee1eSDan Willemsen		return mdV1.Descriptor()
118*1c12ee1eSDan Willemsen	}()
119*1c12ee1eSDan Willemsen	if b == nil {
120*1c12ee1eSDan Willemsen		return aberrantLoadMessageDesc(t, name)
121*1c12ee1eSDan Willemsen	}
122*1c12ee1eSDan Willemsen
123*1c12ee1eSDan Willemsen	// If the Go type has no fields, then this might be a proto3 empty message
124*1c12ee1eSDan Willemsen	// from before the size cache was added. If there are any fields, check to
125*1c12ee1eSDan Willemsen	// see that at least one of them looks like something we generated.
126*1c12ee1eSDan Willemsen	if t.Elem().Kind() == reflect.Struct {
127*1c12ee1eSDan Willemsen		if nfield := t.Elem().NumField(); nfield > 0 {
128*1c12ee1eSDan Willemsen			hasProtoField := false
129*1c12ee1eSDan Willemsen			for i := 0; i < nfield; i++ {
130*1c12ee1eSDan Willemsen				f := t.Elem().Field(i)
131*1c12ee1eSDan Willemsen				if f.Tag.Get("protobuf") != "" || f.Tag.Get("protobuf_oneof") != "" || strings.HasPrefix(f.Name, "XXX_") {
132*1c12ee1eSDan Willemsen					hasProtoField = true
133*1c12ee1eSDan Willemsen					break
134*1c12ee1eSDan Willemsen				}
135*1c12ee1eSDan Willemsen			}
136*1c12ee1eSDan Willemsen			if !hasProtoField {
137*1c12ee1eSDan Willemsen				return aberrantLoadMessageDesc(t, name)
138*1c12ee1eSDan Willemsen			}
139*1c12ee1eSDan Willemsen		}
140*1c12ee1eSDan Willemsen	}
141*1c12ee1eSDan Willemsen
142*1c12ee1eSDan Willemsen	md := legacyLoadFileDesc(b).Messages().Get(idxs[0])
143*1c12ee1eSDan Willemsen	for _, i := range idxs[1:] {
144*1c12ee1eSDan Willemsen		md = md.Messages().Get(i)
145*1c12ee1eSDan Willemsen	}
146*1c12ee1eSDan Willemsen	if name != "" && md.FullName() != name {
147*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("mismatching message name: got %v, want %v", md.FullName(), name))
148*1c12ee1eSDan Willemsen	}
149*1c12ee1eSDan Willemsen	if md, ok := legacyMessageDescCache.LoadOrStore(t, md); ok {
150*1c12ee1eSDan Willemsen		return md.(protoreflect.MessageDescriptor)
151*1c12ee1eSDan Willemsen	}
152*1c12ee1eSDan Willemsen	return md
153*1c12ee1eSDan Willemsen}
154*1c12ee1eSDan Willemsen
155*1c12ee1eSDan Willemsenvar (
156*1c12ee1eSDan Willemsen	aberrantMessageDescLock  sync.Mutex
157*1c12ee1eSDan Willemsen	aberrantMessageDescCache map[reflect.Type]protoreflect.MessageDescriptor
158*1c12ee1eSDan Willemsen)
159*1c12ee1eSDan Willemsen
160*1c12ee1eSDan Willemsen// aberrantLoadMessageDesc returns an MessageDescriptor derived from the Go type,
161*1c12ee1eSDan Willemsen// which must not implement protoreflect.ProtoMessage or messageV1.
162*1c12ee1eSDan Willemsen//
163*1c12ee1eSDan Willemsen// This is a best-effort derivation of the message descriptor using the protobuf
164*1c12ee1eSDan Willemsen// tags on the struct fields.
165*1c12ee1eSDan Willemsenfunc aberrantLoadMessageDesc(t reflect.Type, name protoreflect.FullName) protoreflect.MessageDescriptor {
166*1c12ee1eSDan Willemsen	aberrantMessageDescLock.Lock()
167*1c12ee1eSDan Willemsen	defer aberrantMessageDescLock.Unlock()
168*1c12ee1eSDan Willemsen	if aberrantMessageDescCache == nil {
169*1c12ee1eSDan Willemsen		aberrantMessageDescCache = make(map[reflect.Type]protoreflect.MessageDescriptor)
170*1c12ee1eSDan Willemsen	}
171*1c12ee1eSDan Willemsen	return aberrantLoadMessageDescReentrant(t, name)
172*1c12ee1eSDan Willemsen}
173*1c12ee1eSDan Willemsenfunc aberrantLoadMessageDescReentrant(t reflect.Type, name protoreflect.FullName) protoreflect.MessageDescriptor {
174*1c12ee1eSDan Willemsen	// Fast-path: check if an MessageDescriptor is cached for this concrete type.
175*1c12ee1eSDan Willemsen	if md, ok := aberrantMessageDescCache[t]; ok {
176*1c12ee1eSDan Willemsen		return md
177*1c12ee1eSDan Willemsen	}
178*1c12ee1eSDan Willemsen
179*1c12ee1eSDan Willemsen	// Slow-path: construct a descriptor from the Go struct type (best-effort).
180*1c12ee1eSDan Willemsen	// Cache the MessageDescriptor early on so that we can resolve internal
181*1c12ee1eSDan Willemsen	// cyclic references.
182*1c12ee1eSDan Willemsen	md := &filedesc.Message{L2: new(filedesc.MessageL2)}
183*1c12ee1eSDan Willemsen	md.L0.FullName = aberrantDeriveMessageName(t, name)
184*1c12ee1eSDan Willemsen	md.L0.ParentFile = filedesc.SurrogateProto2
185*1c12ee1eSDan Willemsen	aberrantMessageDescCache[t] = md
186*1c12ee1eSDan Willemsen
187*1c12ee1eSDan Willemsen	if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct {
188*1c12ee1eSDan Willemsen		return md
189*1c12ee1eSDan Willemsen	}
190*1c12ee1eSDan Willemsen
191*1c12ee1eSDan Willemsen	// Try to determine if the message is using proto3 by checking scalars.
192*1c12ee1eSDan Willemsen	for i := 0; i < t.Elem().NumField(); i++ {
193*1c12ee1eSDan Willemsen		f := t.Elem().Field(i)
194*1c12ee1eSDan Willemsen		if tag := f.Tag.Get("protobuf"); tag != "" {
195*1c12ee1eSDan Willemsen			switch f.Type.Kind() {
196*1c12ee1eSDan Willemsen			case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
197*1c12ee1eSDan Willemsen				md.L0.ParentFile = filedesc.SurrogateProto3
198*1c12ee1eSDan Willemsen			}
199*1c12ee1eSDan Willemsen			for _, s := range strings.Split(tag, ",") {
200*1c12ee1eSDan Willemsen				if s == "proto3" {
201*1c12ee1eSDan Willemsen					md.L0.ParentFile = filedesc.SurrogateProto3
202*1c12ee1eSDan Willemsen				}
203*1c12ee1eSDan Willemsen			}
204*1c12ee1eSDan Willemsen		}
205*1c12ee1eSDan Willemsen	}
206*1c12ee1eSDan Willemsen
207*1c12ee1eSDan Willemsen	// Obtain a list of oneof wrapper types.
208*1c12ee1eSDan Willemsen	var oneofWrappers []reflect.Type
209*1c12ee1eSDan Willemsen	for _, method := range []string{"XXX_OneofFuncs", "XXX_OneofWrappers"} {
210*1c12ee1eSDan Willemsen		if fn, ok := t.MethodByName(method); ok {
211*1c12ee1eSDan Willemsen			for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) {
212*1c12ee1eSDan Willemsen				if vs, ok := v.Interface().([]interface{}); ok {
213*1c12ee1eSDan Willemsen					for _, v := range vs {
214*1c12ee1eSDan Willemsen						oneofWrappers = append(oneofWrappers, reflect.TypeOf(v))
215*1c12ee1eSDan Willemsen					}
216*1c12ee1eSDan Willemsen				}
217*1c12ee1eSDan Willemsen			}
218*1c12ee1eSDan Willemsen		}
219*1c12ee1eSDan Willemsen	}
220*1c12ee1eSDan Willemsen
221*1c12ee1eSDan Willemsen	// Obtain a list of the extension ranges.
222*1c12ee1eSDan Willemsen	if fn, ok := t.MethodByName("ExtensionRangeArray"); ok {
223*1c12ee1eSDan Willemsen		vs := fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0]
224*1c12ee1eSDan Willemsen		for i := 0; i < vs.Len(); i++ {
225*1c12ee1eSDan Willemsen			v := vs.Index(i)
226*1c12ee1eSDan Willemsen			md.L2.ExtensionRanges.List = append(md.L2.ExtensionRanges.List, [2]protoreflect.FieldNumber{
227*1c12ee1eSDan Willemsen				protoreflect.FieldNumber(v.FieldByName("Start").Int()),
228*1c12ee1eSDan Willemsen				protoreflect.FieldNumber(v.FieldByName("End").Int() + 1),
229*1c12ee1eSDan Willemsen			})
230*1c12ee1eSDan Willemsen			md.L2.ExtensionRangeOptions = append(md.L2.ExtensionRangeOptions, nil)
231*1c12ee1eSDan Willemsen		}
232*1c12ee1eSDan Willemsen	}
233*1c12ee1eSDan Willemsen
234*1c12ee1eSDan Willemsen	// Derive the message fields by inspecting the struct fields.
235*1c12ee1eSDan Willemsen	for i := 0; i < t.Elem().NumField(); i++ {
236*1c12ee1eSDan Willemsen		f := t.Elem().Field(i)
237*1c12ee1eSDan Willemsen		if tag := f.Tag.Get("protobuf"); tag != "" {
238*1c12ee1eSDan Willemsen			tagKey := f.Tag.Get("protobuf_key")
239*1c12ee1eSDan Willemsen			tagVal := f.Tag.Get("protobuf_val")
240*1c12ee1eSDan Willemsen			aberrantAppendField(md, f.Type, tag, tagKey, tagVal)
241*1c12ee1eSDan Willemsen		}
242*1c12ee1eSDan Willemsen		if tag := f.Tag.Get("protobuf_oneof"); tag != "" {
243*1c12ee1eSDan Willemsen			n := len(md.L2.Oneofs.List)
244*1c12ee1eSDan Willemsen			md.L2.Oneofs.List = append(md.L2.Oneofs.List, filedesc.Oneof{})
245*1c12ee1eSDan Willemsen			od := &md.L2.Oneofs.List[n]
246*1c12ee1eSDan Willemsen			od.L0.FullName = md.FullName().Append(protoreflect.Name(tag))
247*1c12ee1eSDan Willemsen			od.L0.ParentFile = md.L0.ParentFile
248*1c12ee1eSDan Willemsen			od.L0.Parent = md
249*1c12ee1eSDan Willemsen			od.L0.Index = n
250*1c12ee1eSDan Willemsen
251*1c12ee1eSDan Willemsen			for _, t := range oneofWrappers {
252*1c12ee1eSDan Willemsen				if t.Implements(f.Type) {
253*1c12ee1eSDan Willemsen					f := t.Elem().Field(0)
254*1c12ee1eSDan Willemsen					if tag := f.Tag.Get("protobuf"); tag != "" {
255*1c12ee1eSDan Willemsen						aberrantAppendField(md, f.Type, tag, "", "")
256*1c12ee1eSDan Willemsen						fd := &md.L2.Fields.List[len(md.L2.Fields.List)-1]
257*1c12ee1eSDan Willemsen						fd.L1.ContainingOneof = od
258*1c12ee1eSDan Willemsen						od.L1.Fields.List = append(od.L1.Fields.List, fd)
259*1c12ee1eSDan Willemsen					}
260*1c12ee1eSDan Willemsen				}
261*1c12ee1eSDan Willemsen			}
262*1c12ee1eSDan Willemsen		}
263*1c12ee1eSDan Willemsen	}
264*1c12ee1eSDan Willemsen
265*1c12ee1eSDan Willemsen	return md
266*1c12ee1eSDan Willemsen}
267*1c12ee1eSDan Willemsen
268*1c12ee1eSDan Willemsenfunc aberrantDeriveMessageName(t reflect.Type, name protoreflect.FullName) protoreflect.FullName {
269*1c12ee1eSDan Willemsen	if name.IsValid() {
270*1c12ee1eSDan Willemsen		return name
271*1c12ee1eSDan Willemsen	}
272*1c12ee1eSDan Willemsen	func() {
273*1c12ee1eSDan Willemsen		defer func() { recover() }() // swallow possible nil panics
274*1c12ee1eSDan Willemsen		if m, ok := reflect.Zero(t).Interface().(interface{ XXX_MessageName() string }); ok {
275*1c12ee1eSDan Willemsen			name = protoreflect.FullName(m.XXX_MessageName())
276*1c12ee1eSDan Willemsen		}
277*1c12ee1eSDan Willemsen	}()
278*1c12ee1eSDan Willemsen	if name.IsValid() {
279*1c12ee1eSDan Willemsen		return name
280*1c12ee1eSDan Willemsen	}
281*1c12ee1eSDan Willemsen	if t.Kind() == reflect.Ptr {
282*1c12ee1eSDan Willemsen		t = t.Elem()
283*1c12ee1eSDan Willemsen	}
284*1c12ee1eSDan Willemsen	return AberrantDeriveFullName(t)
285*1c12ee1eSDan Willemsen}
286*1c12ee1eSDan Willemsen
287*1c12ee1eSDan Willemsenfunc aberrantAppendField(md *filedesc.Message, goType reflect.Type, tag, tagKey, tagVal string) {
288*1c12ee1eSDan Willemsen	t := goType
289*1c12ee1eSDan Willemsen	isOptional := t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct
290*1c12ee1eSDan Willemsen	isRepeated := t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
291*1c12ee1eSDan Willemsen	if isOptional || isRepeated {
292*1c12ee1eSDan Willemsen		t = t.Elem()
293*1c12ee1eSDan Willemsen	}
294*1c12ee1eSDan Willemsen	fd := ptag.Unmarshal(tag, t, placeholderEnumValues{}).(*filedesc.Field)
295*1c12ee1eSDan Willemsen
296*1c12ee1eSDan Willemsen	// Append field descriptor to the message.
297*1c12ee1eSDan Willemsen	n := len(md.L2.Fields.List)
298*1c12ee1eSDan Willemsen	md.L2.Fields.List = append(md.L2.Fields.List, *fd)
299*1c12ee1eSDan Willemsen	fd = &md.L2.Fields.List[n]
300*1c12ee1eSDan Willemsen	fd.L0.FullName = md.FullName().Append(fd.Name())
301*1c12ee1eSDan Willemsen	fd.L0.ParentFile = md.L0.ParentFile
302*1c12ee1eSDan Willemsen	fd.L0.Parent = md
303*1c12ee1eSDan Willemsen	fd.L0.Index = n
304*1c12ee1eSDan Willemsen
305*1c12ee1eSDan Willemsen	if fd.L1.IsWeak || fd.L1.HasPacked {
306*1c12ee1eSDan Willemsen		fd.L1.Options = func() protoreflect.ProtoMessage {
307*1c12ee1eSDan Willemsen			opts := descopts.Field.ProtoReflect().New()
308*1c12ee1eSDan Willemsen			if fd.L1.IsWeak {
309*1c12ee1eSDan Willemsen				opts.Set(opts.Descriptor().Fields().ByName("weak"), protoreflect.ValueOfBool(true))
310*1c12ee1eSDan Willemsen			}
311*1c12ee1eSDan Willemsen			if fd.L1.HasPacked {
312*1c12ee1eSDan Willemsen				opts.Set(opts.Descriptor().Fields().ByName("packed"), protoreflect.ValueOfBool(fd.L1.IsPacked))
313*1c12ee1eSDan Willemsen			}
314*1c12ee1eSDan Willemsen			return opts.Interface()
315*1c12ee1eSDan Willemsen		}
316*1c12ee1eSDan Willemsen	}
317*1c12ee1eSDan Willemsen
318*1c12ee1eSDan Willemsen	// Populate Enum and Message.
319*1c12ee1eSDan Willemsen	if fd.Enum() == nil && fd.Kind() == protoreflect.EnumKind {
320*1c12ee1eSDan Willemsen		switch v := reflect.Zero(t).Interface().(type) {
321*1c12ee1eSDan Willemsen		case protoreflect.Enum:
322*1c12ee1eSDan Willemsen			fd.L1.Enum = v.Descriptor()
323*1c12ee1eSDan Willemsen		default:
324*1c12ee1eSDan Willemsen			fd.L1.Enum = LegacyLoadEnumDesc(t)
325*1c12ee1eSDan Willemsen		}
326*1c12ee1eSDan Willemsen	}
327*1c12ee1eSDan Willemsen	if fd.Message() == nil && (fd.Kind() == protoreflect.MessageKind || fd.Kind() == protoreflect.GroupKind) {
328*1c12ee1eSDan Willemsen		switch v := reflect.Zero(t).Interface().(type) {
329*1c12ee1eSDan Willemsen		case protoreflect.ProtoMessage:
330*1c12ee1eSDan Willemsen			fd.L1.Message = v.ProtoReflect().Descriptor()
331*1c12ee1eSDan Willemsen		case messageV1:
332*1c12ee1eSDan Willemsen			fd.L1.Message = LegacyLoadMessageDesc(t)
333*1c12ee1eSDan Willemsen		default:
334*1c12ee1eSDan Willemsen			if t.Kind() == reflect.Map {
335*1c12ee1eSDan Willemsen				n := len(md.L1.Messages.List)
336*1c12ee1eSDan Willemsen				md.L1.Messages.List = append(md.L1.Messages.List, filedesc.Message{L2: new(filedesc.MessageL2)})
337*1c12ee1eSDan Willemsen				md2 := &md.L1.Messages.List[n]
338*1c12ee1eSDan Willemsen				md2.L0.FullName = md.FullName().Append(protoreflect.Name(strs.MapEntryName(string(fd.Name()))))
339*1c12ee1eSDan Willemsen				md2.L0.ParentFile = md.L0.ParentFile
340*1c12ee1eSDan Willemsen				md2.L0.Parent = md
341*1c12ee1eSDan Willemsen				md2.L0.Index = n
342*1c12ee1eSDan Willemsen
343*1c12ee1eSDan Willemsen				md2.L1.IsMapEntry = true
344*1c12ee1eSDan Willemsen				md2.L2.Options = func() protoreflect.ProtoMessage {
345*1c12ee1eSDan Willemsen					opts := descopts.Message.ProtoReflect().New()
346*1c12ee1eSDan Willemsen					opts.Set(opts.Descriptor().Fields().ByName("map_entry"), protoreflect.ValueOfBool(true))
347*1c12ee1eSDan Willemsen					return opts.Interface()
348*1c12ee1eSDan Willemsen				}
349*1c12ee1eSDan Willemsen
350*1c12ee1eSDan Willemsen				aberrantAppendField(md2, t.Key(), tagKey, "", "")
351*1c12ee1eSDan Willemsen				aberrantAppendField(md2, t.Elem(), tagVal, "", "")
352*1c12ee1eSDan Willemsen
353*1c12ee1eSDan Willemsen				fd.L1.Message = md2
354*1c12ee1eSDan Willemsen				break
355*1c12ee1eSDan Willemsen			}
356*1c12ee1eSDan Willemsen			fd.L1.Message = aberrantLoadMessageDescReentrant(t, "")
357*1c12ee1eSDan Willemsen		}
358*1c12ee1eSDan Willemsen	}
359*1c12ee1eSDan Willemsen}
360*1c12ee1eSDan Willemsen
361*1c12ee1eSDan Willemsentype placeholderEnumValues struct {
362*1c12ee1eSDan Willemsen	protoreflect.EnumValueDescriptors
363*1c12ee1eSDan Willemsen}
364*1c12ee1eSDan Willemsen
365*1c12ee1eSDan Willemsenfunc (placeholderEnumValues) ByNumber(n protoreflect.EnumNumber) protoreflect.EnumValueDescriptor {
366*1c12ee1eSDan Willemsen	return filedesc.PlaceholderEnumValue(protoreflect.FullName(fmt.Sprintf("UNKNOWN_%d", n)))
367*1c12ee1eSDan Willemsen}
368*1c12ee1eSDan Willemsen
369*1c12ee1eSDan Willemsen// legacyMarshaler is the proto.Marshaler interface superseded by protoiface.Methoder.
370*1c12ee1eSDan Willemsentype legacyMarshaler interface {
371*1c12ee1eSDan Willemsen	Marshal() ([]byte, error)
372*1c12ee1eSDan Willemsen}
373*1c12ee1eSDan Willemsen
374*1c12ee1eSDan Willemsen// legacyUnmarshaler is the proto.Unmarshaler interface superseded by protoiface.Methoder.
375*1c12ee1eSDan Willemsentype legacyUnmarshaler interface {
376*1c12ee1eSDan Willemsen	Unmarshal([]byte) error
377*1c12ee1eSDan Willemsen}
378*1c12ee1eSDan Willemsen
379*1c12ee1eSDan Willemsen// legacyMerger is the proto.Merger interface superseded by protoiface.Methoder.
380*1c12ee1eSDan Willemsentype legacyMerger interface {
381*1c12ee1eSDan Willemsen	Merge(protoiface.MessageV1)
382*1c12ee1eSDan Willemsen}
383*1c12ee1eSDan Willemsen
384*1c12ee1eSDan Willemsenvar aberrantProtoMethods = &protoiface.Methods{
385*1c12ee1eSDan Willemsen	Marshal:   legacyMarshal,
386*1c12ee1eSDan Willemsen	Unmarshal: legacyUnmarshal,
387*1c12ee1eSDan Willemsen	Merge:     legacyMerge,
388*1c12ee1eSDan Willemsen
389*1c12ee1eSDan Willemsen	// We have no way to tell whether the type's Marshal method
390*1c12ee1eSDan Willemsen	// supports deterministic serialization or not, but this
391*1c12ee1eSDan Willemsen	// preserves the v1 implementation's behavior of always
392*1c12ee1eSDan Willemsen	// calling Marshal methods when present.
393*1c12ee1eSDan Willemsen	Flags: protoiface.SupportMarshalDeterministic,
394*1c12ee1eSDan Willemsen}
395*1c12ee1eSDan Willemsen
396*1c12ee1eSDan Willemsenfunc legacyMarshal(in protoiface.MarshalInput) (protoiface.MarshalOutput, error) {
397*1c12ee1eSDan Willemsen	v := in.Message.(unwrapper).protoUnwrap()
398*1c12ee1eSDan Willemsen	marshaler, ok := v.(legacyMarshaler)
399*1c12ee1eSDan Willemsen	if !ok {
400*1c12ee1eSDan Willemsen		return protoiface.MarshalOutput{}, errors.New("%T does not implement Marshal", v)
401*1c12ee1eSDan Willemsen	}
402*1c12ee1eSDan Willemsen	out, err := marshaler.Marshal()
403*1c12ee1eSDan Willemsen	if in.Buf != nil {
404*1c12ee1eSDan Willemsen		out = append(in.Buf, out...)
405*1c12ee1eSDan Willemsen	}
406*1c12ee1eSDan Willemsen	return protoiface.MarshalOutput{
407*1c12ee1eSDan Willemsen		Buf: out,
408*1c12ee1eSDan Willemsen	}, err
409*1c12ee1eSDan Willemsen}
410*1c12ee1eSDan Willemsen
411*1c12ee1eSDan Willemsenfunc legacyUnmarshal(in protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) {
412*1c12ee1eSDan Willemsen	v := in.Message.(unwrapper).protoUnwrap()
413*1c12ee1eSDan Willemsen	unmarshaler, ok := v.(legacyUnmarshaler)
414*1c12ee1eSDan Willemsen	if !ok {
415*1c12ee1eSDan Willemsen		return protoiface.UnmarshalOutput{}, errors.New("%T does not implement Unmarshal", v)
416*1c12ee1eSDan Willemsen	}
417*1c12ee1eSDan Willemsen	return protoiface.UnmarshalOutput{}, unmarshaler.Unmarshal(in.Buf)
418*1c12ee1eSDan Willemsen}
419*1c12ee1eSDan Willemsen
420*1c12ee1eSDan Willemsenfunc legacyMerge(in protoiface.MergeInput) protoiface.MergeOutput {
421*1c12ee1eSDan Willemsen	// Check whether this supports the legacy merger.
422*1c12ee1eSDan Willemsen	dstv := in.Destination.(unwrapper).protoUnwrap()
423*1c12ee1eSDan Willemsen	merger, ok := dstv.(legacyMerger)
424*1c12ee1eSDan Willemsen	if ok {
425*1c12ee1eSDan Willemsen		merger.Merge(Export{}.ProtoMessageV1Of(in.Source))
426*1c12ee1eSDan Willemsen		return protoiface.MergeOutput{Flags: protoiface.MergeComplete}
427*1c12ee1eSDan Willemsen	}
428*1c12ee1eSDan Willemsen
429*1c12ee1eSDan Willemsen	// If legacy merger is unavailable, implement merge in terms of
430*1c12ee1eSDan Willemsen	// a marshal and unmarshal operation.
431*1c12ee1eSDan Willemsen	srcv := in.Source.(unwrapper).protoUnwrap()
432*1c12ee1eSDan Willemsen	marshaler, ok := srcv.(legacyMarshaler)
433*1c12ee1eSDan Willemsen	if !ok {
434*1c12ee1eSDan Willemsen		return protoiface.MergeOutput{}
435*1c12ee1eSDan Willemsen	}
436*1c12ee1eSDan Willemsen	dstv = in.Destination.(unwrapper).protoUnwrap()
437*1c12ee1eSDan Willemsen	unmarshaler, ok := dstv.(legacyUnmarshaler)
438*1c12ee1eSDan Willemsen	if !ok {
439*1c12ee1eSDan Willemsen		return protoiface.MergeOutput{}
440*1c12ee1eSDan Willemsen	}
441*1c12ee1eSDan Willemsen	if !in.Source.IsValid() {
442*1c12ee1eSDan Willemsen		// Legacy Marshal methods may not function on nil messages.
443*1c12ee1eSDan Willemsen		// Check for a typed nil source only after we confirm that
444*1c12ee1eSDan Willemsen		// legacy Marshal/Unmarshal methods are present, for
445*1c12ee1eSDan Willemsen		// consistency.
446*1c12ee1eSDan Willemsen		return protoiface.MergeOutput{Flags: protoiface.MergeComplete}
447*1c12ee1eSDan Willemsen	}
448*1c12ee1eSDan Willemsen	b, err := marshaler.Marshal()
449*1c12ee1eSDan Willemsen	if err != nil {
450*1c12ee1eSDan Willemsen		return protoiface.MergeOutput{}
451*1c12ee1eSDan Willemsen	}
452*1c12ee1eSDan Willemsen	err = unmarshaler.Unmarshal(b)
453*1c12ee1eSDan Willemsen	if err != nil {
454*1c12ee1eSDan Willemsen		return protoiface.MergeOutput{}
455*1c12ee1eSDan Willemsen	}
456*1c12ee1eSDan Willemsen	return protoiface.MergeOutput{Flags: protoiface.MergeComplete}
457*1c12ee1eSDan Willemsen}
458*1c12ee1eSDan Willemsen
459*1c12ee1eSDan Willemsen// aberrantMessageType implements MessageType for all types other than pointer-to-struct.
460*1c12ee1eSDan Willemsentype aberrantMessageType struct {
461*1c12ee1eSDan Willemsen	t reflect.Type
462*1c12ee1eSDan Willemsen}
463*1c12ee1eSDan Willemsen
464*1c12ee1eSDan Willemsenfunc (mt aberrantMessageType) New() protoreflect.Message {
465*1c12ee1eSDan Willemsen	if mt.t.Kind() == reflect.Ptr {
466*1c12ee1eSDan Willemsen		return aberrantMessage{reflect.New(mt.t.Elem())}
467*1c12ee1eSDan Willemsen	}
468*1c12ee1eSDan Willemsen	return aberrantMessage{reflect.Zero(mt.t)}
469*1c12ee1eSDan Willemsen}
470*1c12ee1eSDan Willemsenfunc (mt aberrantMessageType) Zero() protoreflect.Message {
471*1c12ee1eSDan Willemsen	return aberrantMessage{reflect.Zero(mt.t)}
472*1c12ee1eSDan Willemsen}
473*1c12ee1eSDan Willemsenfunc (mt aberrantMessageType) GoType() reflect.Type {
474*1c12ee1eSDan Willemsen	return mt.t
475*1c12ee1eSDan Willemsen}
476*1c12ee1eSDan Willemsenfunc (mt aberrantMessageType) Descriptor() protoreflect.MessageDescriptor {
477*1c12ee1eSDan Willemsen	return LegacyLoadMessageDesc(mt.t)
478*1c12ee1eSDan Willemsen}
479*1c12ee1eSDan Willemsen
480*1c12ee1eSDan Willemsen// aberrantMessage implements Message for all types other than pointer-to-struct.
481*1c12ee1eSDan Willemsen//
482*1c12ee1eSDan Willemsen// When the underlying type implements legacyMarshaler or legacyUnmarshaler,
483*1c12ee1eSDan Willemsen// the aberrant Message can be marshaled or unmarshaled. Otherwise, there is
484*1c12ee1eSDan Willemsen// not much that can be done with values of this type.
485*1c12ee1eSDan Willemsentype aberrantMessage struct {
486*1c12ee1eSDan Willemsen	v reflect.Value
487*1c12ee1eSDan Willemsen}
488*1c12ee1eSDan Willemsen
489*1c12ee1eSDan Willemsen// Reset implements the v1 proto.Message.Reset method.
490*1c12ee1eSDan Willemsenfunc (m aberrantMessage) Reset() {
491*1c12ee1eSDan Willemsen	if mr, ok := m.v.Interface().(interface{ Reset() }); ok {
492*1c12ee1eSDan Willemsen		mr.Reset()
493*1c12ee1eSDan Willemsen		return
494*1c12ee1eSDan Willemsen	}
495*1c12ee1eSDan Willemsen	if m.v.Kind() == reflect.Ptr && !m.v.IsNil() {
496*1c12ee1eSDan Willemsen		m.v.Elem().Set(reflect.Zero(m.v.Type().Elem()))
497*1c12ee1eSDan Willemsen	}
498*1c12ee1eSDan Willemsen}
499*1c12ee1eSDan Willemsen
500*1c12ee1eSDan Willemsenfunc (m aberrantMessage) ProtoReflect() protoreflect.Message {
501*1c12ee1eSDan Willemsen	return m
502*1c12ee1eSDan Willemsen}
503*1c12ee1eSDan Willemsen
504*1c12ee1eSDan Willemsenfunc (m aberrantMessage) Descriptor() protoreflect.MessageDescriptor {
505*1c12ee1eSDan Willemsen	return LegacyLoadMessageDesc(m.v.Type())
506*1c12ee1eSDan Willemsen}
507*1c12ee1eSDan Willemsenfunc (m aberrantMessage) Type() protoreflect.MessageType {
508*1c12ee1eSDan Willemsen	return aberrantMessageType{m.v.Type()}
509*1c12ee1eSDan Willemsen}
510*1c12ee1eSDan Willemsenfunc (m aberrantMessage) New() protoreflect.Message {
511*1c12ee1eSDan Willemsen	if m.v.Type().Kind() == reflect.Ptr {
512*1c12ee1eSDan Willemsen		return aberrantMessage{reflect.New(m.v.Type().Elem())}
513*1c12ee1eSDan Willemsen	}
514*1c12ee1eSDan Willemsen	return aberrantMessage{reflect.Zero(m.v.Type())}
515*1c12ee1eSDan Willemsen}
516*1c12ee1eSDan Willemsenfunc (m aberrantMessage) Interface() protoreflect.ProtoMessage {
517*1c12ee1eSDan Willemsen	return m
518*1c12ee1eSDan Willemsen}
519*1c12ee1eSDan Willemsenfunc (m aberrantMessage) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
520*1c12ee1eSDan Willemsen	return
521*1c12ee1eSDan Willemsen}
522*1c12ee1eSDan Willemsenfunc (m aberrantMessage) Has(protoreflect.FieldDescriptor) bool {
523*1c12ee1eSDan Willemsen	return false
524*1c12ee1eSDan Willemsen}
525*1c12ee1eSDan Willemsenfunc (m aberrantMessage) Clear(protoreflect.FieldDescriptor) {
526*1c12ee1eSDan Willemsen	panic("invalid Message.Clear on " + string(m.Descriptor().FullName()))
527*1c12ee1eSDan Willemsen}
528*1c12ee1eSDan Willemsenfunc (m aberrantMessage) Get(fd protoreflect.FieldDescriptor) protoreflect.Value {
529*1c12ee1eSDan Willemsen	if fd.Default().IsValid() {
530*1c12ee1eSDan Willemsen		return fd.Default()
531*1c12ee1eSDan Willemsen	}
532*1c12ee1eSDan Willemsen	panic("invalid Message.Get on " + string(m.Descriptor().FullName()))
533*1c12ee1eSDan Willemsen}
534*1c12ee1eSDan Willemsenfunc (m aberrantMessage) Set(protoreflect.FieldDescriptor, protoreflect.Value) {
535*1c12ee1eSDan Willemsen	panic("invalid Message.Set on " + string(m.Descriptor().FullName()))
536*1c12ee1eSDan Willemsen}
537*1c12ee1eSDan Willemsenfunc (m aberrantMessage) Mutable(protoreflect.FieldDescriptor) protoreflect.Value {
538*1c12ee1eSDan Willemsen	panic("invalid Message.Mutable on " + string(m.Descriptor().FullName()))
539*1c12ee1eSDan Willemsen}
540*1c12ee1eSDan Willemsenfunc (m aberrantMessage) NewField(protoreflect.FieldDescriptor) protoreflect.Value {
541*1c12ee1eSDan Willemsen	panic("invalid Message.NewField on " + string(m.Descriptor().FullName()))
542*1c12ee1eSDan Willemsen}
543*1c12ee1eSDan Willemsenfunc (m aberrantMessage) WhichOneof(protoreflect.OneofDescriptor) protoreflect.FieldDescriptor {
544*1c12ee1eSDan Willemsen	panic("invalid Message.WhichOneof descriptor on " + string(m.Descriptor().FullName()))
545*1c12ee1eSDan Willemsen}
546*1c12ee1eSDan Willemsenfunc (m aberrantMessage) GetUnknown() protoreflect.RawFields {
547*1c12ee1eSDan Willemsen	return nil
548*1c12ee1eSDan Willemsen}
549*1c12ee1eSDan Willemsenfunc (m aberrantMessage) SetUnknown(protoreflect.RawFields) {
550*1c12ee1eSDan Willemsen	// SetUnknown discards its input on messages which don't support unknown field storage.
551*1c12ee1eSDan Willemsen}
552*1c12ee1eSDan Willemsenfunc (m aberrantMessage) IsValid() bool {
553*1c12ee1eSDan Willemsen	if m.v.Kind() == reflect.Ptr {
554*1c12ee1eSDan Willemsen		return !m.v.IsNil()
555*1c12ee1eSDan Willemsen	}
556*1c12ee1eSDan Willemsen	return false
557*1c12ee1eSDan Willemsen}
558*1c12ee1eSDan Willemsenfunc (m aberrantMessage) ProtoMethods() *protoiface.Methods {
559*1c12ee1eSDan Willemsen	return aberrantProtoMethods
560*1c12ee1eSDan Willemsen}
561*1c12ee1eSDan Willemsenfunc (m aberrantMessage) protoUnwrap() interface{} {
562*1c12ee1eSDan Willemsen	return m.v.Interface()
563*1c12ee1eSDan Willemsen}
564