xref: /aosp_15_r20/external/golang-protobuf/internal/impl/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	"strconv"
11*1c12ee1eSDan Willemsen	"strings"
12*1c12ee1eSDan Willemsen	"sync"
13*1c12ee1eSDan Willemsen	"sync/atomic"
14*1c12ee1eSDan Willemsen
15*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/genid"
16*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoreflect"
17*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoregistry"
18*1c12ee1eSDan Willemsen)
19*1c12ee1eSDan Willemsen
20*1c12ee1eSDan Willemsen// MessageInfo provides protobuf related functionality for a given Go type
21*1c12ee1eSDan Willemsen// that represents a message. A given instance of MessageInfo is tied to
22*1c12ee1eSDan Willemsen// exactly one Go type, which must be a pointer to a struct type.
23*1c12ee1eSDan Willemsen//
24*1c12ee1eSDan Willemsen// The exported fields must be populated before any methods are called
25*1c12ee1eSDan Willemsen// and cannot be mutated after set.
26*1c12ee1eSDan Willemsentype MessageInfo struct {
27*1c12ee1eSDan Willemsen	// GoReflectType is the underlying message Go type and must be populated.
28*1c12ee1eSDan Willemsen	GoReflectType reflect.Type // pointer to struct
29*1c12ee1eSDan Willemsen
30*1c12ee1eSDan Willemsen	// Desc is the underlying message descriptor type and must be populated.
31*1c12ee1eSDan Willemsen	Desc protoreflect.MessageDescriptor
32*1c12ee1eSDan Willemsen
33*1c12ee1eSDan Willemsen	// Exporter must be provided in a purego environment in order to provide
34*1c12ee1eSDan Willemsen	// access to unexported fields.
35*1c12ee1eSDan Willemsen	Exporter exporter
36*1c12ee1eSDan Willemsen
37*1c12ee1eSDan Willemsen	// OneofWrappers is list of pointers to oneof wrapper struct types.
38*1c12ee1eSDan Willemsen	OneofWrappers []interface{}
39*1c12ee1eSDan Willemsen
40*1c12ee1eSDan Willemsen	initMu   sync.Mutex // protects all unexported fields
41*1c12ee1eSDan Willemsen	initDone uint32
42*1c12ee1eSDan Willemsen
43*1c12ee1eSDan Willemsen	reflectMessageInfo // for reflection implementation
44*1c12ee1eSDan Willemsen	coderMessageInfo   // for fast-path method implementations
45*1c12ee1eSDan Willemsen}
46*1c12ee1eSDan Willemsen
47*1c12ee1eSDan Willemsen// exporter is a function that returns a reference to the ith field of v,
48*1c12ee1eSDan Willemsen// where v is a pointer to a struct. It returns nil if it does not support
49*1c12ee1eSDan Willemsen// exporting the requested field (e.g., already exported).
50*1c12ee1eSDan Willemsentype exporter func(v interface{}, i int) interface{}
51*1c12ee1eSDan Willemsen
52*1c12ee1eSDan Willemsen// getMessageInfo returns the MessageInfo for any message type that
53*1c12ee1eSDan Willemsen// is generated by our implementation of protoc-gen-go (for v2 and on).
54*1c12ee1eSDan Willemsen// If it is unable to obtain a MessageInfo, it returns nil.
55*1c12ee1eSDan Willemsenfunc getMessageInfo(mt reflect.Type) *MessageInfo {
56*1c12ee1eSDan Willemsen	m, ok := reflect.Zero(mt).Interface().(protoreflect.ProtoMessage)
57*1c12ee1eSDan Willemsen	if !ok {
58*1c12ee1eSDan Willemsen		return nil
59*1c12ee1eSDan Willemsen	}
60*1c12ee1eSDan Willemsen	mr, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *MessageInfo })
61*1c12ee1eSDan Willemsen	if !ok {
62*1c12ee1eSDan Willemsen		return nil
63*1c12ee1eSDan Willemsen	}
64*1c12ee1eSDan Willemsen	return mr.ProtoMessageInfo()
65*1c12ee1eSDan Willemsen}
66*1c12ee1eSDan Willemsen
67*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) init() {
68*1c12ee1eSDan Willemsen	// This function is called in the hot path. Inline the sync.Once logic,
69*1c12ee1eSDan Willemsen	// since allocating a closure for Once.Do is expensive.
70*1c12ee1eSDan Willemsen	// Keep init small to ensure that it can be inlined.
71*1c12ee1eSDan Willemsen	if atomic.LoadUint32(&mi.initDone) == 0 {
72*1c12ee1eSDan Willemsen		mi.initOnce()
73*1c12ee1eSDan Willemsen	}
74*1c12ee1eSDan Willemsen}
75*1c12ee1eSDan Willemsen
76*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) initOnce() {
77*1c12ee1eSDan Willemsen	mi.initMu.Lock()
78*1c12ee1eSDan Willemsen	defer mi.initMu.Unlock()
79*1c12ee1eSDan Willemsen	if mi.initDone == 1 {
80*1c12ee1eSDan Willemsen		return
81*1c12ee1eSDan Willemsen	}
82*1c12ee1eSDan Willemsen
83*1c12ee1eSDan Willemsen	t := mi.GoReflectType
84*1c12ee1eSDan Willemsen	if t.Kind() != reflect.Ptr && t.Elem().Kind() != reflect.Struct {
85*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("got %v, want *struct kind", t))
86*1c12ee1eSDan Willemsen	}
87*1c12ee1eSDan Willemsen	t = t.Elem()
88*1c12ee1eSDan Willemsen
89*1c12ee1eSDan Willemsen	si := mi.makeStructInfo(t)
90*1c12ee1eSDan Willemsen	mi.makeReflectFuncs(t, si)
91*1c12ee1eSDan Willemsen	mi.makeCoderMethods(t, si)
92*1c12ee1eSDan Willemsen
93*1c12ee1eSDan Willemsen	atomic.StoreUint32(&mi.initDone, 1)
94*1c12ee1eSDan Willemsen}
95*1c12ee1eSDan Willemsen
96*1c12ee1eSDan Willemsen// getPointer returns the pointer for a message, which should be of
97*1c12ee1eSDan Willemsen// the type of the MessageInfo. If the message is of a different type,
98*1c12ee1eSDan Willemsen// it returns ok==false.
99*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) getPointer(m protoreflect.Message) (p pointer, ok bool) {
100*1c12ee1eSDan Willemsen	switch m := m.(type) {
101*1c12ee1eSDan Willemsen	case *messageState:
102*1c12ee1eSDan Willemsen		return m.pointer(), m.messageInfo() == mi
103*1c12ee1eSDan Willemsen	case *messageReflectWrapper:
104*1c12ee1eSDan Willemsen		return m.pointer(), m.messageInfo() == mi
105*1c12ee1eSDan Willemsen	}
106*1c12ee1eSDan Willemsen	return pointer{}, false
107*1c12ee1eSDan Willemsen}
108*1c12ee1eSDan Willemsen
109*1c12ee1eSDan Willemsentype (
110*1c12ee1eSDan Willemsen	SizeCache       = int32
111*1c12ee1eSDan Willemsen	WeakFields      = map[int32]protoreflect.ProtoMessage
112*1c12ee1eSDan Willemsen	UnknownFields   = unknownFieldsA // TODO: switch to unknownFieldsB
113*1c12ee1eSDan Willemsen	unknownFieldsA  = []byte
114*1c12ee1eSDan Willemsen	unknownFieldsB  = *[]byte
115*1c12ee1eSDan Willemsen	ExtensionFields = map[int32]ExtensionField
116*1c12ee1eSDan Willemsen)
117*1c12ee1eSDan Willemsen
118*1c12ee1eSDan Willemsenvar (
119*1c12ee1eSDan Willemsen	sizecacheType       = reflect.TypeOf(SizeCache(0))
120*1c12ee1eSDan Willemsen	weakFieldsType      = reflect.TypeOf(WeakFields(nil))
121*1c12ee1eSDan Willemsen	unknownFieldsAType  = reflect.TypeOf(unknownFieldsA(nil))
122*1c12ee1eSDan Willemsen	unknownFieldsBType  = reflect.TypeOf(unknownFieldsB(nil))
123*1c12ee1eSDan Willemsen	extensionFieldsType = reflect.TypeOf(ExtensionFields(nil))
124*1c12ee1eSDan Willemsen)
125*1c12ee1eSDan Willemsen
126*1c12ee1eSDan Willemsentype structInfo struct {
127*1c12ee1eSDan Willemsen	sizecacheOffset offset
128*1c12ee1eSDan Willemsen	sizecacheType   reflect.Type
129*1c12ee1eSDan Willemsen	weakOffset      offset
130*1c12ee1eSDan Willemsen	weakType        reflect.Type
131*1c12ee1eSDan Willemsen	unknownOffset   offset
132*1c12ee1eSDan Willemsen	unknownType     reflect.Type
133*1c12ee1eSDan Willemsen	extensionOffset offset
134*1c12ee1eSDan Willemsen	extensionType   reflect.Type
135*1c12ee1eSDan Willemsen
136*1c12ee1eSDan Willemsen	fieldsByNumber        map[protoreflect.FieldNumber]reflect.StructField
137*1c12ee1eSDan Willemsen	oneofsByName          map[protoreflect.Name]reflect.StructField
138*1c12ee1eSDan Willemsen	oneofWrappersByType   map[reflect.Type]protoreflect.FieldNumber
139*1c12ee1eSDan Willemsen	oneofWrappersByNumber map[protoreflect.FieldNumber]reflect.Type
140*1c12ee1eSDan Willemsen}
141*1c12ee1eSDan Willemsen
142*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) makeStructInfo(t reflect.Type) structInfo {
143*1c12ee1eSDan Willemsen	si := structInfo{
144*1c12ee1eSDan Willemsen		sizecacheOffset: invalidOffset,
145*1c12ee1eSDan Willemsen		weakOffset:      invalidOffset,
146*1c12ee1eSDan Willemsen		unknownOffset:   invalidOffset,
147*1c12ee1eSDan Willemsen		extensionOffset: invalidOffset,
148*1c12ee1eSDan Willemsen
149*1c12ee1eSDan Willemsen		fieldsByNumber:        map[protoreflect.FieldNumber]reflect.StructField{},
150*1c12ee1eSDan Willemsen		oneofsByName:          map[protoreflect.Name]reflect.StructField{},
151*1c12ee1eSDan Willemsen		oneofWrappersByType:   map[reflect.Type]protoreflect.FieldNumber{},
152*1c12ee1eSDan Willemsen		oneofWrappersByNumber: map[protoreflect.FieldNumber]reflect.Type{},
153*1c12ee1eSDan Willemsen	}
154*1c12ee1eSDan Willemsen
155*1c12ee1eSDan WillemsenfieldLoop:
156*1c12ee1eSDan Willemsen	for i := 0; i < t.NumField(); i++ {
157*1c12ee1eSDan Willemsen		switch f := t.Field(i); f.Name {
158*1c12ee1eSDan Willemsen		case genid.SizeCache_goname, genid.SizeCacheA_goname:
159*1c12ee1eSDan Willemsen			if f.Type == sizecacheType {
160*1c12ee1eSDan Willemsen				si.sizecacheOffset = offsetOf(f, mi.Exporter)
161*1c12ee1eSDan Willemsen				si.sizecacheType = f.Type
162*1c12ee1eSDan Willemsen			}
163*1c12ee1eSDan Willemsen		case genid.WeakFields_goname, genid.WeakFieldsA_goname:
164*1c12ee1eSDan Willemsen			if f.Type == weakFieldsType {
165*1c12ee1eSDan Willemsen				si.weakOffset = offsetOf(f, mi.Exporter)
166*1c12ee1eSDan Willemsen				si.weakType = f.Type
167*1c12ee1eSDan Willemsen			}
168*1c12ee1eSDan Willemsen		case genid.UnknownFields_goname, genid.UnknownFieldsA_goname:
169*1c12ee1eSDan Willemsen			if f.Type == unknownFieldsAType || f.Type == unknownFieldsBType {
170*1c12ee1eSDan Willemsen				si.unknownOffset = offsetOf(f, mi.Exporter)
171*1c12ee1eSDan Willemsen				si.unknownType = f.Type
172*1c12ee1eSDan Willemsen			}
173*1c12ee1eSDan Willemsen		case genid.ExtensionFields_goname, genid.ExtensionFieldsA_goname, genid.ExtensionFieldsB_goname:
174*1c12ee1eSDan Willemsen			if f.Type == extensionFieldsType {
175*1c12ee1eSDan Willemsen				si.extensionOffset = offsetOf(f, mi.Exporter)
176*1c12ee1eSDan Willemsen				si.extensionType = f.Type
177*1c12ee1eSDan Willemsen			}
178*1c12ee1eSDan Willemsen		default:
179*1c12ee1eSDan Willemsen			for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
180*1c12ee1eSDan Willemsen				if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
181*1c12ee1eSDan Willemsen					n, _ := strconv.ParseUint(s, 10, 64)
182*1c12ee1eSDan Willemsen					si.fieldsByNumber[protoreflect.FieldNumber(n)] = f
183*1c12ee1eSDan Willemsen					continue fieldLoop
184*1c12ee1eSDan Willemsen				}
185*1c12ee1eSDan Willemsen			}
186*1c12ee1eSDan Willemsen			if s := f.Tag.Get("protobuf_oneof"); len(s) > 0 {
187*1c12ee1eSDan Willemsen				si.oneofsByName[protoreflect.Name(s)] = f
188*1c12ee1eSDan Willemsen				continue fieldLoop
189*1c12ee1eSDan Willemsen			}
190*1c12ee1eSDan Willemsen		}
191*1c12ee1eSDan Willemsen	}
192*1c12ee1eSDan Willemsen
193*1c12ee1eSDan Willemsen	// Derive a mapping of oneof wrappers to fields.
194*1c12ee1eSDan Willemsen	oneofWrappers := mi.OneofWrappers
195*1c12ee1eSDan Willemsen	for _, method := range []string{"XXX_OneofFuncs", "XXX_OneofWrappers"} {
196*1c12ee1eSDan Willemsen		if fn, ok := reflect.PtrTo(t).MethodByName(method); ok {
197*1c12ee1eSDan Willemsen			for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) {
198*1c12ee1eSDan Willemsen				if vs, ok := v.Interface().([]interface{}); ok {
199*1c12ee1eSDan Willemsen					oneofWrappers = vs
200*1c12ee1eSDan Willemsen				}
201*1c12ee1eSDan Willemsen			}
202*1c12ee1eSDan Willemsen		}
203*1c12ee1eSDan Willemsen	}
204*1c12ee1eSDan Willemsen	for _, v := range oneofWrappers {
205*1c12ee1eSDan Willemsen		tf := reflect.TypeOf(v).Elem()
206*1c12ee1eSDan Willemsen		f := tf.Field(0)
207*1c12ee1eSDan Willemsen		for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
208*1c12ee1eSDan Willemsen			if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
209*1c12ee1eSDan Willemsen				n, _ := strconv.ParseUint(s, 10, 64)
210*1c12ee1eSDan Willemsen				si.oneofWrappersByType[tf] = protoreflect.FieldNumber(n)
211*1c12ee1eSDan Willemsen				si.oneofWrappersByNumber[protoreflect.FieldNumber(n)] = tf
212*1c12ee1eSDan Willemsen				break
213*1c12ee1eSDan Willemsen			}
214*1c12ee1eSDan Willemsen		}
215*1c12ee1eSDan Willemsen	}
216*1c12ee1eSDan Willemsen
217*1c12ee1eSDan Willemsen	return si
218*1c12ee1eSDan Willemsen}
219*1c12ee1eSDan Willemsen
220*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) New() protoreflect.Message {
221*1c12ee1eSDan Willemsen	m := reflect.New(mi.GoReflectType.Elem()).Interface()
222*1c12ee1eSDan Willemsen	if r, ok := m.(protoreflect.ProtoMessage); ok {
223*1c12ee1eSDan Willemsen		return r.ProtoReflect()
224*1c12ee1eSDan Willemsen	}
225*1c12ee1eSDan Willemsen	return mi.MessageOf(m)
226*1c12ee1eSDan Willemsen}
227*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) Zero() protoreflect.Message {
228*1c12ee1eSDan Willemsen	return mi.MessageOf(reflect.Zero(mi.GoReflectType).Interface())
229*1c12ee1eSDan Willemsen}
230*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) Descriptor() protoreflect.MessageDescriptor {
231*1c12ee1eSDan Willemsen	return mi.Desc
232*1c12ee1eSDan Willemsen}
233*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) Enum(i int) protoreflect.EnumType {
234*1c12ee1eSDan Willemsen	mi.init()
235*1c12ee1eSDan Willemsen	fd := mi.Desc.Fields().Get(i)
236*1c12ee1eSDan Willemsen	return Export{}.EnumTypeOf(mi.fieldTypes[fd.Number()])
237*1c12ee1eSDan Willemsen}
238*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) Message(i int) protoreflect.MessageType {
239*1c12ee1eSDan Willemsen	mi.init()
240*1c12ee1eSDan Willemsen	fd := mi.Desc.Fields().Get(i)
241*1c12ee1eSDan Willemsen	switch {
242*1c12ee1eSDan Willemsen	case fd.IsWeak():
243*1c12ee1eSDan Willemsen		mt, _ := protoregistry.GlobalTypes.FindMessageByName(fd.Message().FullName())
244*1c12ee1eSDan Willemsen		return mt
245*1c12ee1eSDan Willemsen	case fd.IsMap():
246*1c12ee1eSDan Willemsen		return mapEntryType{fd.Message(), mi.fieldTypes[fd.Number()]}
247*1c12ee1eSDan Willemsen	default:
248*1c12ee1eSDan Willemsen		return Export{}.MessageTypeOf(mi.fieldTypes[fd.Number()])
249*1c12ee1eSDan Willemsen	}
250*1c12ee1eSDan Willemsen}
251*1c12ee1eSDan Willemsen
252*1c12ee1eSDan Willemsentype mapEntryType struct {
253*1c12ee1eSDan Willemsen	desc    protoreflect.MessageDescriptor
254*1c12ee1eSDan Willemsen	valType interface{} // zero value of enum or message type
255*1c12ee1eSDan Willemsen}
256*1c12ee1eSDan Willemsen
257*1c12ee1eSDan Willemsenfunc (mt mapEntryType) New() protoreflect.Message {
258*1c12ee1eSDan Willemsen	return nil
259*1c12ee1eSDan Willemsen}
260*1c12ee1eSDan Willemsenfunc (mt mapEntryType) Zero() protoreflect.Message {
261*1c12ee1eSDan Willemsen	return nil
262*1c12ee1eSDan Willemsen}
263*1c12ee1eSDan Willemsenfunc (mt mapEntryType) Descriptor() protoreflect.MessageDescriptor {
264*1c12ee1eSDan Willemsen	return mt.desc
265*1c12ee1eSDan Willemsen}
266*1c12ee1eSDan Willemsenfunc (mt mapEntryType) Enum(i int) protoreflect.EnumType {
267*1c12ee1eSDan Willemsen	fd := mt.desc.Fields().Get(i)
268*1c12ee1eSDan Willemsen	if fd.Enum() == nil {
269*1c12ee1eSDan Willemsen		return nil
270*1c12ee1eSDan Willemsen	}
271*1c12ee1eSDan Willemsen	return Export{}.EnumTypeOf(mt.valType)
272*1c12ee1eSDan Willemsen}
273*1c12ee1eSDan Willemsenfunc (mt mapEntryType) Message(i int) protoreflect.MessageType {
274*1c12ee1eSDan Willemsen	fd := mt.desc.Fields().Get(i)
275*1c12ee1eSDan Willemsen	if fd.Message() == nil {
276*1c12ee1eSDan Willemsen		return nil
277*1c12ee1eSDan Willemsen	}
278*1c12ee1eSDan Willemsen	return Export{}.MessageTypeOf(mt.valType)
279*1c12ee1eSDan Willemsen}
280