xref: /aosp_15_r20/external/golang-protobuf/internal/impl/message_reflect.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 Willemsenpackage impl
6*1c12ee1eSDan Willemsen
7*1c12ee1eSDan Willemsenimport (
8*1c12ee1eSDan Willemsen	"fmt"
9*1c12ee1eSDan Willemsen	"reflect"
10*1c12ee1eSDan Willemsen
11*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/detrand"
12*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/pragma"
13*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoreflect"
14*1c12ee1eSDan Willemsen)
15*1c12ee1eSDan Willemsen
16*1c12ee1eSDan Willemsentype reflectMessageInfo struct {
17*1c12ee1eSDan Willemsen	fields map[protoreflect.FieldNumber]*fieldInfo
18*1c12ee1eSDan Willemsen	oneofs map[protoreflect.Name]*oneofInfo
19*1c12ee1eSDan Willemsen
20*1c12ee1eSDan Willemsen	// fieldTypes contains the zero value of an enum or message field.
21*1c12ee1eSDan Willemsen	// For lists, it contains the element type.
22*1c12ee1eSDan Willemsen	// For maps, it contains the entry value type.
23*1c12ee1eSDan Willemsen	fieldTypes map[protoreflect.FieldNumber]interface{}
24*1c12ee1eSDan Willemsen
25*1c12ee1eSDan Willemsen	// denseFields is a subset of fields where:
26*1c12ee1eSDan Willemsen	//	0 < fieldDesc.Number() < len(denseFields)
27*1c12ee1eSDan Willemsen	// It provides faster access to the fieldInfo, but may be incomplete.
28*1c12ee1eSDan Willemsen	denseFields []*fieldInfo
29*1c12ee1eSDan Willemsen
30*1c12ee1eSDan Willemsen	// rangeInfos is a list of all fields (not belonging to a oneof) and oneofs.
31*1c12ee1eSDan Willemsen	rangeInfos []interface{} // either *fieldInfo or *oneofInfo
32*1c12ee1eSDan Willemsen
33*1c12ee1eSDan Willemsen	getUnknown   func(pointer) protoreflect.RawFields
34*1c12ee1eSDan Willemsen	setUnknown   func(pointer, protoreflect.RawFields)
35*1c12ee1eSDan Willemsen	extensionMap func(pointer) *extensionMap
36*1c12ee1eSDan Willemsen
37*1c12ee1eSDan Willemsen	nilMessage atomicNilMessage
38*1c12ee1eSDan Willemsen}
39*1c12ee1eSDan Willemsen
40*1c12ee1eSDan Willemsen// makeReflectFuncs generates the set of functions to support reflection.
41*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) makeReflectFuncs(t reflect.Type, si structInfo) {
42*1c12ee1eSDan Willemsen	mi.makeKnownFieldsFunc(si)
43*1c12ee1eSDan Willemsen	mi.makeUnknownFieldsFunc(t, si)
44*1c12ee1eSDan Willemsen	mi.makeExtensionFieldsFunc(t, si)
45*1c12ee1eSDan Willemsen	mi.makeFieldTypes(si)
46*1c12ee1eSDan Willemsen}
47*1c12ee1eSDan Willemsen
48*1c12ee1eSDan Willemsen// makeKnownFieldsFunc generates functions for operations that can be performed
49*1c12ee1eSDan Willemsen// on each protobuf message field. It takes in a reflect.Type representing the
50*1c12ee1eSDan Willemsen// Go struct and matches message fields with struct fields.
51*1c12ee1eSDan Willemsen//
52*1c12ee1eSDan Willemsen// This code assumes that the struct is well-formed and panics if there are
53*1c12ee1eSDan Willemsen// any discrepancies.
54*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) makeKnownFieldsFunc(si structInfo) {
55*1c12ee1eSDan Willemsen	mi.fields = map[protoreflect.FieldNumber]*fieldInfo{}
56*1c12ee1eSDan Willemsen	md := mi.Desc
57*1c12ee1eSDan Willemsen	fds := md.Fields()
58*1c12ee1eSDan Willemsen	for i := 0; i < fds.Len(); i++ {
59*1c12ee1eSDan Willemsen		fd := fds.Get(i)
60*1c12ee1eSDan Willemsen		fs := si.fieldsByNumber[fd.Number()]
61*1c12ee1eSDan Willemsen		isOneof := fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic()
62*1c12ee1eSDan Willemsen		if isOneof {
63*1c12ee1eSDan Willemsen			fs = si.oneofsByName[fd.ContainingOneof().Name()]
64*1c12ee1eSDan Willemsen		}
65*1c12ee1eSDan Willemsen		var fi fieldInfo
66*1c12ee1eSDan Willemsen		switch {
67*1c12ee1eSDan Willemsen		case fs.Type == nil:
68*1c12ee1eSDan Willemsen			fi = fieldInfoForMissing(fd) // never occurs for officially generated message types
69*1c12ee1eSDan Willemsen		case isOneof:
70*1c12ee1eSDan Willemsen			fi = fieldInfoForOneof(fd, fs, mi.Exporter, si.oneofWrappersByNumber[fd.Number()])
71*1c12ee1eSDan Willemsen		case fd.IsMap():
72*1c12ee1eSDan Willemsen			fi = fieldInfoForMap(fd, fs, mi.Exporter)
73*1c12ee1eSDan Willemsen		case fd.IsList():
74*1c12ee1eSDan Willemsen			fi = fieldInfoForList(fd, fs, mi.Exporter)
75*1c12ee1eSDan Willemsen		case fd.IsWeak():
76*1c12ee1eSDan Willemsen			fi = fieldInfoForWeakMessage(fd, si.weakOffset)
77*1c12ee1eSDan Willemsen		case fd.Message() != nil:
78*1c12ee1eSDan Willemsen			fi = fieldInfoForMessage(fd, fs, mi.Exporter)
79*1c12ee1eSDan Willemsen		default:
80*1c12ee1eSDan Willemsen			fi = fieldInfoForScalar(fd, fs, mi.Exporter)
81*1c12ee1eSDan Willemsen		}
82*1c12ee1eSDan Willemsen		mi.fields[fd.Number()] = &fi
83*1c12ee1eSDan Willemsen	}
84*1c12ee1eSDan Willemsen
85*1c12ee1eSDan Willemsen	mi.oneofs = map[protoreflect.Name]*oneofInfo{}
86*1c12ee1eSDan Willemsen	for i := 0; i < md.Oneofs().Len(); i++ {
87*1c12ee1eSDan Willemsen		od := md.Oneofs().Get(i)
88*1c12ee1eSDan Willemsen		mi.oneofs[od.Name()] = makeOneofInfo(od, si, mi.Exporter)
89*1c12ee1eSDan Willemsen	}
90*1c12ee1eSDan Willemsen
91*1c12ee1eSDan Willemsen	mi.denseFields = make([]*fieldInfo, fds.Len()*2)
92*1c12ee1eSDan Willemsen	for i := 0; i < fds.Len(); i++ {
93*1c12ee1eSDan Willemsen		if fd := fds.Get(i); int(fd.Number()) < len(mi.denseFields) {
94*1c12ee1eSDan Willemsen			mi.denseFields[fd.Number()] = mi.fields[fd.Number()]
95*1c12ee1eSDan Willemsen		}
96*1c12ee1eSDan Willemsen	}
97*1c12ee1eSDan Willemsen
98*1c12ee1eSDan Willemsen	for i := 0; i < fds.Len(); {
99*1c12ee1eSDan Willemsen		fd := fds.Get(i)
100*1c12ee1eSDan Willemsen		if od := fd.ContainingOneof(); od != nil && !od.IsSynthetic() {
101*1c12ee1eSDan Willemsen			mi.rangeInfos = append(mi.rangeInfos, mi.oneofs[od.Name()])
102*1c12ee1eSDan Willemsen			i += od.Fields().Len()
103*1c12ee1eSDan Willemsen		} else {
104*1c12ee1eSDan Willemsen			mi.rangeInfos = append(mi.rangeInfos, mi.fields[fd.Number()])
105*1c12ee1eSDan Willemsen			i++
106*1c12ee1eSDan Willemsen		}
107*1c12ee1eSDan Willemsen	}
108*1c12ee1eSDan Willemsen
109*1c12ee1eSDan Willemsen	// Introduce instability to iteration order, but keep it deterministic.
110*1c12ee1eSDan Willemsen	if len(mi.rangeInfos) > 1 && detrand.Bool() {
111*1c12ee1eSDan Willemsen		i := detrand.Intn(len(mi.rangeInfos) - 1)
112*1c12ee1eSDan Willemsen		mi.rangeInfos[i], mi.rangeInfos[i+1] = mi.rangeInfos[i+1], mi.rangeInfos[i]
113*1c12ee1eSDan Willemsen	}
114*1c12ee1eSDan Willemsen}
115*1c12ee1eSDan Willemsen
116*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) makeUnknownFieldsFunc(t reflect.Type, si structInfo) {
117*1c12ee1eSDan Willemsen	switch {
118*1c12ee1eSDan Willemsen	case si.unknownOffset.IsValid() && si.unknownType == unknownFieldsAType:
119*1c12ee1eSDan Willemsen		// Handle as []byte.
120*1c12ee1eSDan Willemsen		mi.getUnknown = func(p pointer) protoreflect.RawFields {
121*1c12ee1eSDan Willemsen			if p.IsNil() {
122*1c12ee1eSDan Willemsen				return nil
123*1c12ee1eSDan Willemsen			}
124*1c12ee1eSDan Willemsen			return *p.Apply(mi.unknownOffset).Bytes()
125*1c12ee1eSDan Willemsen		}
126*1c12ee1eSDan Willemsen		mi.setUnknown = func(p pointer, b protoreflect.RawFields) {
127*1c12ee1eSDan Willemsen			if p.IsNil() {
128*1c12ee1eSDan Willemsen				panic("invalid SetUnknown on nil Message")
129*1c12ee1eSDan Willemsen			}
130*1c12ee1eSDan Willemsen			*p.Apply(mi.unknownOffset).Bytes() = b
131*1c12ee1eSDan Willemsen		}
132*1c12ee1eSDan Willemsen	case si.unknownOffset.IsValid() && si.unknownType == unknownFieldsBType:
133*1c12ee1eSDan Willemsen		// Handle as *[]byte.
134*1c12ee1eSDan Willemsen		mi.getUnknown = func(p pointer) protoreflect.RawFields {
135*1c12ee1eSDan Willemsen			if p.IsNil() {
136*1c12ee1eSDan Willemsen				return nil
137*1c12ee1eSDan Willemsen			}
138*1c12ee1eSDan Willemsen			bp := p.Apply(mi.unknownOffset).BytesPtr()
139*1c12ee1eSDan Willemsen			if *bp == nil {
140*1c12ee1eSDan Willemsen				return nil
141*1c12ee1eSDan Willemsen			}
142*1c12ee1eSDan Willemsen			return **bp
143*1c12ee1eSDan Willemsen		}
144*1c12ee1eSDan Willemsen		mi.setUnknown = func(p pointer, b protoreflect.RawFields) {
145*1c12ee1eSDan Willemsen			if p.IsNil() {
146*1c12ee1eSDan Willemsen				panic("invalid SetUnknown on nil Message")
147*1c12ee1eSDan Willemsen			}
148*1c12ee1eSDan Willemsen			bp := p.Apply(mi.unknownOffset).BytesPtr()
149*1c12ee1eSDan Willemsen			if *bp == nil {
150*1c12ee1eSDan Willemsen				*bp = new([]byte)
151*1c12ee1eSDan Willemsen			}
152*1c12ee1eSDan Willemsen			**bp = b
153*1c12ee1eSDan Willemsen		}
154*1c12ee1eSDan Willemsen	default:
155*1c12ee1eSDan Willemsen		mi.getUnknown = func(pointer) protoreflect.RawFields {
156*1c12ee1eSDan Willemsen			return nil
157*1c12ee1eSDan Willemsen		}
158*1c12ee1eSDan Willemsen		mi.setUnknown = func(p pointer, _ protoreflect.RawFields) {
159*1c12ee1eSDan Willemsen			if p.IsNil() {
160*1c12ee1eSDan Willemsen				panic("invalid SetUnknown on nil Message")
161*1c12ee1eSDan Willemsen			}
162*1c12ee1eSDan Willemsen		}
163*1c12ee1eSDan Willemsen	}
164*1c12ee1eSDan Willemsen}
165*1c12ee1eSDan Willemsen
166*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) makeExtensionFieldsFunc(t reflect.Type, si structInfo) {
167*1c12ee1eSDan Willemsen	if si.extensionOffset.IsValid() {
168*1c12ee1eSDan Willemsen		mi.extensionMap = func(p pointer) *extensionMap {
169*1c12ee1eSDan Willemsen			if p.IsNil() {
170*1c12ee1eSDan Willemsen				return (*extensionMap)(nil)
171*1c12ee1eSDan Willemsen			}
172*1c12ee1eSDan Willemsen			v := p.Apply(si.extensionOffset).AsValueOf(extensionFieldsType)
173*1c12ee1eSDan Willemsen			return (*extensionMap)(v.Interface().(*map[int32]ExtensionField))
174*1c12ee1eSDan Willemsen		}
175*1c12ee1eSDan Willemsen	} else {
176*1c12ee1eSDan Willemsen		mi.extensionMap = func(pointer) *extensionMap {
177*1c12ee1eSDan Willemsen			return (*extensionMap)(nil)
178*1c12ee1eSDan Willemsen		}
179*1c12ee1eSDan Willemsen	}
180*1c12ee1eSDan Willemsen}
181*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) makeFieldTypes(si structInfo) {
182*1c12ee1eSDan Willemsen	md := mi.Desc
183*1c12ee1eSDan Willemsen	fds := md.Fields()
184*1c12ee1eSDan Willemsen	for i := 0; i < fds.Len(); i++ {
185*1c12ee1eSDan Willemsen		var ft reflect.Type
186*1c12ee1eSDan Willemsen		fd := fds.Get(i)
187*1c12ee1eSDan Willemsen		fs := si.fieldsByNumber[fd.Number()]
188*1c12ee1eSDan Willemsen		isOneof := fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic()
189*1c12ee1eSDan Willemsen		if isOneof {
190*1c12ee1eSDan Willemsen			fs = si.oneofsByName[fd.ContainingOneof().Name()]
191*1c12ee1eSDan Willemsen		}
192*1c12ee1eSDan Willemsen		var isMessage bool
193*1c12ee1eSDan Willemsen		switch {
194*1c12ee1eSDan Willemsen		case fs.Type == nil:
195*1c12ee1eSDan Willemsen			continue // never occurs for officially generated message types
196*1c12ee1eSDan Willemsen		case isOneof:
197*1c12ee1eSDan Willemsen			if fd.Enum() != nil || fd.Message() != nil {
198*1c12ee1eSDan Willemsen				ft = si.oneofWrappersByNumber[fd.Number()].Field(0).Type
199*1c12ee1eSDan Willemsen			}
200*1c12ee1eSDan Willemsen		case fd.IsMap():
201*1c12ee1eSDan Willemsen			if fd.MapValue().Enum() != nil || fd.MapValue().Message() != nil {
202*1c12ee1eSDan Willemsen				ft = fs.Type.Elem()
203*1c12ee1eSDan Willemsen			}
204*1c12ee1eSDan Willemsen			isMessage = fd.MapValue().Message() != nil
205*1c12ee1eSDan Willemsen		case fd.IsList():
206*1c12ee1eSDan Willemsen			if fd.Enum() != nil || fd.Message() != nil {
207*1c12ee1eSDan Willemsen				ft = fs.Type.Elem()
208*1c12ee1eSDan Willemsen			}
209*1c12ee1eSDan Willemsen			isMessage = fd.Message() != nil
210*1c12ee1eSDan Willemsen		case fd.Enum() != nil:
211*1c12ee1eSDan Willemsen			ft = fs.Type
212*1c12ee1eSDan Willemsen			if fd.HasPresence() && ft.Kind() == reflect.Ptr {
213*1c12ee1eSDan Willemsen				ft = ft.Elem()
214*1c12ee1eSDan Willemsen			}
215*1c12ee1eSDan Willemsen		case fd.Message() != nil:
216*1c12ee1eSDan Willemsen			ft = fs.Type
217*1c12ee1eSDan Willemsen			if fd.IsWeak() {
218*1c12ee1eSDan Willemsen				ft = nil
219*1c12ee1eSDan Willemsen			}
220*1c12ee1eSDan Willemsen			isMessage = true
221*1c12ee1eSDan Willemsen		}
222*1c12ee1eSDan Willemsen		if isMessage && ft != nil && ft.Kind() != reflect.Ptr {
223*1c12ee1eSDan Willemsen			ft = reflect.PtrTo(ft) // never occurs for officially generated message types
224*1c12ee1eSDan Willemsen		}
225*1c12ee1eSDan Willemsen		if ft != nil {
226*1c12ee1eSDan Willemsen			if mi.fieldTypes == nil {
227*1c12ee1eSDan Willemsen				mi.fieldTypes = make(map[protoreflect.FieldNumber]interface{})
228*1c12ee1eSDan Willemsen			}
229*1c12ee1eSDan Willemsen			mi.fieldTypes[fd.Number()] = reflect.Zero(ft).Interface()
230*1c12ee1eSDan Willemsen		}
231*1c12ee1eSDan Willemsen	}
232*1c12ee1eSDan Willemsen}
233*1c12ee1eSDan Willemsen
234*1c12ee1eSDan Willemsentype extensionMap map[int32]ExtensionField
235*1c12ee1eSDan Willemsen
236*1c12ee1eSDan Willemsenfunc (m *extensionMap) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
237*1c12ee1eSDan Willemsen	if m != nil {
238*1c12ee1eSDan Willemsen		for _, x := range *m {
239*1c12ee1eSDan Willemsen			xd := x.Type().TypeDescriptor()
240*1c12ee1eSDan Willemsen			v := x.Value()
241*1c12ee1eSDan Willemsen			if xd.IsList() && v.List().Len() == 0 {
242*1c12ee1eSDan Willemsen				continue
243*1c12ee1eSDan Willemsen			}
244*1c12ee1eSDan Willemsen			if !f(xd, v) {
245*1c12ee1eSDan Willemsen				return
246*1c12ee1eSDan Willemsen			}
247*1c12ee1eSDan Willemsen		}
248*1c12ee1eSDan Willemsen	}
249*1c12ee1eSDan Willemsen}
250*1c12ee1eSDan Willemsenfunc (m *extensionMap) Has(xt protoreflect.ExtensionType) (ok bool) {
251*1c12ee1eSDan Willemsen	if m == nil {
252*1c12ee1eSDan Willemsen		return false
253*1c12ee1eSDan Willemsen	}
254*1c12ee1eSDan Willemsen	xd := xt.TypeDescriptor()
255*1c12ee1eSDan Willemsen	x, ok := (*m)[int32(xd.Number())]
256*1c12ee1eSDan Willemsen	if !ok {
257*1c12ee1eSDan Willemsen		return false
258*1c12ee1eSDan Willemsen	}
259*1c12ee1eSDan Willemsen	switch {
260*1c12ee1eSDan Willemsen	case xd.IsList():
261*1c12ee1eSDan Willemsen		return x.Value().List().Len() > 0
262*1c12ee1eSDan Willemsen	case xd.IsMap():
263*1c12ee1eSDan Willemsen		return x.Value().Map().Len() > 0
264*1c12ee1eSDan Willemsen	case xd.Message() != nil:
265*1c12ee1eSDan Willemsen		return x.Value().Message().IsValid()
266*1c12ee1eSDan Willemsen	}
267*1c12ee1eSDan Willemsen	return true
268*1c12ee1eSDan Willemsen}
269*1c12ee1eSDan Willemsenfunc (m *extensionMap) Clear(xt protoreflect.ExtensionType) {
270*1c12ee1eSDan Willemsen	delete(*m, int32(xt.TypeDescriptor().Number()))
271*1c12ee1eSDan Willemsen}
272*1c12ee1eSDan Willemsenfunc (m *extensionMap) Get(xt protoreflect.ExtensionType) protoreflect.Value {
273*1c12ee1eSDan Willemsen	xd := xt.TypeDescriptor()
274*1c12ee1eSDan Willemsen	if m != nil {
275*1c12ee1eSDan Willemsen		if x, ok := (*m)[int32(xd.Number())]; ok {
276*1c12ee1eSDan Willemsen			return x.Value()
277*1c12ee1eSDan Willemsen		}
278*1c12ee1eSDan Willemsen	}
279*1c12ee1eSDan Willemsen	return xt.Zero()
280*1c12ee1eSDan Willemsen}
281*1c12ee1eSDan Willemsenfunc (m *extensionMap) Set(xt protoreflect.ExtensionType, v protoreflect.Value) {
282*1c12ee1eSDan Willemsen	xd := xt.TypeDescriptor()
283*1c12ee1eSDan Willemsen	isValid := true
284*1c12ee1eSDan Willemsen	switch {
285*1c12ee1eSDan Willemsen	case !xt.IsValidValue(v):
286*1c12ee1eSDan Willemsen		isValid = false
287*1c12ee1eSDan Willemsen	case xd.IsList():
288*1c12ee1eSDan Willemsen		isValid = v.List().IsValid()
289*1c12ee1eSDan Willemsen	case xd.IsMap():
290*1c12ee1eSDan Willemsen		isValid = v.Map().IsValid()
291*1c12ee1eSDan Willemsen	case xd.Message() != nil:
292*1c12ee1eSDan Willemsen		isValid = v.Message().IsValid()
293*1c12ee1eSDan Willemsen	}
294*1c12ee1eSDan Willemsen	if !isValid {
295*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("%v: assigning invalid value", xt.TypeDescriptor().FullName()))
296*1c12ee1eSDan Willemsen	}
297*1c12ee1eSDan Willemsen
298*1c12ee1eSDan Willemsen	if *m == nil {
299*1c12ee1eSDan Willemsen		*m = make(map[int32]ExtensionField)
300*1c12ee1eSDan Willemsen	}
301*1c12ee1eSDan Willemsen	var x ExtensionField
302*1c12ee1eSDan Willemsen	x.Set(xt, v)
303*1c12ee1eSDan Willemsen	(*m)[int32(xd.Number())] = x
304*1c12ee1eSDan Willemsen}
305*1c12ee1eSDan Willemsenfunc (m *extensionMap) Mutable(xt protoreflect.ExtensionType) protoreflect.Value {
306*1c12ee1eSDan Willemsen	xd := xt.TypeDescriptor()
307*1c12ee1eSDan Willemsen	if xd.Kind() != protoreflect.MessageKind && xd.Kind() != protoreflect.GroupKind && !xd.IsList() && !xd.IsMap() {
308*1c12ee1eSDan Willemsen		panic("invalid Mutable on field with non-composite type")
309*1c12ee1eSDan Willemsen	}
310*1c12ee1eSDan Willemsen	if x, ok := (*m)[int32(xd.Number())]; ok {
311*1c12ee1eSDan Willemsen		return x.Value()
312*1c12ee1eSDan Willemsen	}
313*1c12ee1eSDan Willemsen	v := xt.New()
314*1c12ee1eSDan Willemsen	m.Set(xt, v)
315*1c12ee1eSDan Willemsen	return v
316*1c12ee1eSDan Willemsen}
317*1c12ee1eSDan Willemsen
318*1c12ee1eSDan Willemsen// MessageState is a data structure that is nested as the first field in a
319*1c12ee1eSDan Willemsen// concrete message. It provides a way to implement the ProtoReflect method
320*1c12ee1eSDan Willemsen// in an allocation-free way without needing to have a shadow Go type generated
321*1c12ee1eSDan Willemsen// for every message type. This technique only works using unsafe.
322*1c12ee1eSDan Willemsen//
323*1c12ee1eSDan Willemsen// Example generated code:
324*1c12ee1eSDan Willemsen//
325*1c12ee1eSDan Willemsen//	type M struct {
326*1c12ee1eSDan Willemsen//		state protoimpl.MessageState
327*1c12ee1eSDan Willemsen//
328*1c12ee1eSDan Willemsen//		Field1 int32
329*1c12ee1eSDan Willemsen//		Field2 string
330*1c12ee1eSDan Willemsen//		Field3 *BarMessage
331*1c12ee1eSDan Willemsen//		...
332*1c12ee1eSDan Willemsen//	}
333*1c12ee1eSDan Willemsen//
334*1c12ee1eSDan Willemsen//	func (m *M) ProtoReflect() protoreflect.Message {
335*1c12ee1eSDan Willemsen//		mi := &file_fizz_buzz_proto_msgInfos[5]
336*1c12ee1eSDan Willemsen//		if protoimpl.UnsafeEnabled && m != nil {
337*1c12ee1eSDan Willemsen//			ms := protoimpl.X.MessageStateOf(Pointer(m))
338*1c12ee1eSDan Willemsen//			if ms.LoadMessageInfo() == nil {
339*1c12ee1eSDan Willemsen//				ms.StoreMessageInfo(mi)
340*1c12ee1eSDan Willemsen//			}
341*1c12ee1eSDan Willemsen//			return ms
342*1c12ee1eSDan Willemsen//		}
343*1c12ee1eSDan Willemsen//		return mi.MessageOf(m)
344*1c12ee1eSDan Willemsen//	}
345*1c12ee1eSDan Willemsen//
346*1c12ee1eSDan Willemsen// The MessageState type holds a *MessageInfo, which must be atomically set to
347*1c12ee1eSDan Willemsen// the message info associated with a given message instance.
348*1c12ee1eSDan Willemsen// By unsafely converting a *M into a *MessageState, the MessageState object
349*1c12ee1eSDan Willemsen// has access to all the information needed to implement protobuf reflection.
350*1c12ee1eSDan Willemsen// It has access to the message info as its first field, and a pointer to the
351*1c12ee1eSDan Willemsen// MessageState is identical to a pointer to the concrete message value.
352*1c12ee1eSDan Willemsen//
353*1c12ee1eSDan Willemsen// Requirements:
354*1c12ee1eSDan Willemsen//   - The type M must implement protoreflect.ProtoMessage.
355*1c12ee1eSDan Willemsen//   - The address of m must not be nil.
356*1c12ee1eSDan Willemsen//   - The address of m and the address of m.state must be equal,
357*1c12ee1eSDan Willemsen//     even though they are different Go types.
358*1c12ee1eSDan Willemsentype MessageState struct {
359*1c12ee1eSDan Willemsen	pragma.NoUnkeyedLiterals
360*1c12ee1eSDan Willemsen	pragma.DoNotCompare
361*1c12ee1eSDan Willemsen	pragma.DoNotCopy
362*1c12ee1eSDan Willemsen
363*1c12ee1eSDan Willemsen	atomicMessageInfo *MessageInfo
364*1c12ee1eSDan Willemsen}
365*1c12ee1eSDan Willemsen
366*1c12ee1eSDan Willemsentype messageState MessageState
367*1c12ee1eSDan Willemsen
368*1c12ee1eSDan Willemsenvar (
369*1c12ee1eSDan Willemsen	_ protoreflect.Message = (*messageState)(nil)
370*1c12ee1eSDan Willemsen	_ unwrapper            = (*messageState)(nil)
371*1c12ee1eSDan Willemsen)
372*1c12ee1eSDan Willemsen
373*1c12ee1eSDan Willemsen// messageDataType is a tuple of a pointer to the message data and
374*1c12ee1eSDan Willemsen// a pointer to the message type. It is a generalized way of providing a
375*1c12ee1eSDan Willemsen// reflective view over a message instance. The disadvantage of this approach
376*1c12ee1eSDan Willemsen// is the need to allocate this tuple of 16B.
377*1c12ee1eSDan Willemsentype messageDataType struct {
378*1c12ee1eSDan Willemsen	p  pointer
379*1c12ee1eSDan Willemsen	mi *MessageInfo
380*1c12ee1eSDan Willemsen}
381*1c12ee1eSDan Willemsen
382*1c12ee1eSDan Willemsentype (
383*1c12ee1eSDan Willemsen	messageReflectWrapper messageDataType
384*1c12ee1eSDan Willemsen	messageIfaceWrapper   messageDataType
385*1c12ee1eSDan Willemsen)
386*1c12ee1eSDan Willemsen
387*1c12ee1eSDan Willemsenvar (
388*1c12ee1eSDan Willemsen	_ protoreflect.Message      = (*messageReflectWrapper)(nil)
389*1c12ee1eSDan Willemsen	_ unwrapper                 = (*messageReflectWrapper)(nil)
390*1c12ee1eSDan Willemsen	_ protoreflect.ProtoMessage = (*messageIfaceWrapper)(nil)
391*1c12ee1eSDan Willemsen	_ unwrapper                 = (*messageIfaceWrapper)(nil)
392*1c12ee1eSDan Willemsen)
393*1c12ee1eSDan Willemsen
394*1c12ee1eSDan Willemsen// MessageOf returns a reflective view over a message. The input must be a
395*1c12ee1eSDan Willemsen// pointer to a named Go struct. If the provided type has a ProtoReflect method,
396*1c12ee1eSDan Willemsen// it must be implemented by calling this method.
397*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) MessageOf(m interface{}) protoreflect.Message {
398*1c12ee1eSDan Willemsen	if reflect.TypeOf(m) != mi.GoReflectType {
399*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("type mismatch: got %T, want %v", m, mi.GoReflectType))
400*1c12ee1eSDan Willemsen	}
401*1c12ee1eSDan Willemsen	p := pointerOfIface(m)
402*1c12ee1eSDan Willemsen	if p.IsNil() {
403*1c12ee1eSDan Willemsen		return mi.nilMessage.Init(mi)
404*1c12ee1eSDan Willemsen	}
405*1c12ee1eSDan Willemsen	return &messageReflectWrapper{p, mi}
406*1c12ee1eSDan Willemsen}
407*1c12ee1eSDan Willemsen
408*1c12ee1eSDan Willemsenfunc (m *messageReflectWrapper) pointer() pointer          { return m.p }
409*1c12ee1eSDan Willemsenfunc (m *messageReflectWrapper) messageInfo() *MessageInfo { return m.mi }
410*1c12ee1eSDan Willemsen
411*1c12ee1eSDan Willemsen// Reset implements the v1 proto.Message.Reset method.
412*1c12ee1eSDan Willemsenfunc (m *messageIfaceWrapper) Reset() {
413*1c12ee1eSDan Willemsen	if mr, ok := m.protoUnwrap().(interface{ Reset() }); ok {
414*1c12ee1eSDan Willemsen		mr.Reset()
415*1c12ee1eSDan Willemsen		return
416*1c12ee1eSDan Willemsen	}
417*1c12ee1eSDan Willemsen	rv := reflect.ValueOf(m.protoUnwrap())
418*1c12ee1eSDan Willemsen	if rv.Kind() == reflect.Ptr && !rv.IsNil() {
419*1c12ee1eSDan Willemsen		rv.Elem().Set(reflect.Zero(rv.Type().Elem()))
420*1c12ee1eSDan Willemsen	}
421*1c12ee1eSDan Willemsen}
422*1c12ee1eSDan Willemsenfunc (m *messageIfaceWrapper) ProtoReflect() protoreflect.Message {
423*1c12ee1eSDan Willemsen	return (*messageReflectWrapper)(m)
424*1c12ee1eSDan Willemsen}
425*1c12ee1eSDan Willemsenfunc (m *messageIfaceWrapper) protoUnwrap() interface{} {
426*1c12ee1eSDan Willemsen	return m.p.AsIfaceOf(m.mi.GoReflectType.Elem())
427*1c12ee1eSDan Willemsen}
428*1c12ee1eSDan Willemsen
429*1c12ee1eSDan Willemsen// checkField verifies that the provided field descriptor is valid.
430*1c12ee1eSDan Willemsen// Exactly one of the returned values is populated.
431*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) checkField(fd protoreflect.FieldDescriptor) (*fieldInfo, protoreflect.ExtensionType) {
432*1c12ee1eSDan Willemsen	var fi *fieldInfo
433*1c12ee1eSDan Willemsen	if n := fd.Number(); 0 < n && int(n) < len(mi.denseFields) {
434*1c12ee1eSDan Willemsen		fi = mi.denseFields[n]
435*1c12ee1eSDan Willemsen	} else {
436*1c12ee1eSDan Willemsen		fi = mi.fields[n]
437*1c12ee1eSDan Willemsen	}
438*1c12ee1eSDan Willemsen	if fi != nil {
439*1c12ee1eSDan Willemsen		if fi.fieldDesc != fd {
440*1c12ee1eSDan Willemsen			if got, want := fd.FullName(), fi.fieldDesc.FullName(); got != want {
441*1c12ee1eSDan Willemsen				panic(fmt.Sprintf("mismatching field: got %v, want %v", got, want))
442*1c12ee1eSDan Willemsen			}
443*1c12ee1eSDan Willemsen			panic(fmt.Sprintf("mismatching field: %v", fd.FullName()))
444*1c12ee1eSDan Willemsen		}
445*1c12ee1eSDan Willemsen		return fi, nil
446*1c12ee1eSDan Willemsen	}
447*1c12ee1eSDan Willemsen
448*1c12ee1eSDan Willemsen	if fd.IsExtension() {
449*1c12ee1eSDan Willemsen		if got, want := fd.ContainingMessage().FullName(), mi.Desc.FullName(); got != want {
450*1c12ee1eSDan Willemsen			// TODO: Should this be exact containing message descriptor match?
451*1c12ee1eSDan Willemsen			panic(fmt.Sprintf("extension %v has mismatching containing message: got %v, want %v", fd.FullName(), got, want))
452*1c12ee1eSDan Willemsen		}
453*1c12ee1eSDan Willemsen		if !mi.Desc.ExtensionRanges().Has(fd.Number()) {
454*1c12ee1eSDan Willemsen			panic(fmt.Sprintf("extension %v extends %v outside the extension range", fd.FullName(), mi.Desc.FullName()))
455*1c12ee1eSDan Willemsen		}
456*1c12ee1eSDan Willemsen		xtd, ok := fd.(protoreflect.ExtensionTypeDescriptor)
457*1c12ee1eSDan Willemsen		if !ok {
458*1c12ee1eSDan Willemsen			panic(fmt.Sprintf("extension %v does not implement protoreflect.ExtensionTypeDescriptor", fd.FullName()))
459*1c12ee1eSDan Willemsen		}
460*1c12ee1eSDan Willemsen		return nil, xtd.Type()
461*1c12ee1eSDan Willemsen	}
462*1c12ee1eSDan Willemsen	panic(fmt.Sprintf("field %v is invalid", fd.FullName()))
463*1c12ee1eSDan Willemsen}
464