xref: /aosp_15_r20/external/golang-protobuf/internal/impl/codec_message.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	"sort"
11*1c12ee1eSDan Willemsen
12*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/encoding/protowire"
13*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/encoding/messageset"
14*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/order"
15*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoreflect"
16*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/runtime/protoiface"
17*1c12ee1eSDan Willemsen)
18*1c12ee1eSDan Willemsen
19*1c12ee1eSDan Willemsen// coderMessageInfo contains per-message information used by the fast-path functions.
20*1c12ee1eSDan Willemsen// This is a different type from MessageInfo to keep MessageInfo as general-purpose as
21*1c12ee1eSDan Willemsen// possible.
22*1c12ee1eSDan Willemsentype coderMessageInfo struct {
23*1c12ee1eSDan Willemsen	methods protoiface.Methods
24*1c12ee1eSDan Willemsen
25*1c12ee1eSDan Willemsen	orderedCoderFields []*coderFieldInfo
26*1c12ee1eSDan Willemsen	denseCoderFields   []*coderFieldInfo
27*1c12ee1eSDan Willemsen	coderFields        map[protowire.Number]*coderFieldInfo
28*1c12ee1eSDan Willemsen	sizecacheOffset    offset
29*1c12ee1eSDan Willemsen	unknownOffset      offset
30*1c12ee1eSDan Willemsen	unknownPtrKind     bool
31*1c12ee1eSDan Willemsen	extensionOffset    offset
32*1c12ee1eSDan Willemsen	needsInitCheck     bool
33*1c12ee1eSDan Willemsen	isMessageSet       bool
34*1c12ee1eSDan Willemsen	numRequiredFields  uint8
35*1c12ee1eSDan Willemsen}
36*1c12ee1eSDan Willemsen
37*1c12ee1eSDan Willemsentype coderFieldInfo struct {
38*1c12ee1eSDan Willemsen	funcs      pointerCoderFuncs // fast-path per-field functions
39*1c12ee1eSDan Willemsen	mi         *MessageInfo      // field's message
40*1c12ee1eSDan Willemsen	ft         reflect.Type
41*1c12ee1eSDan Willemsen	validation validationInfo           // information used by message validation
42*1c12ee1eSDan Willemsen	num        protoreflect.FieldNumber // field number
43*1c12ee1eSDan Willemsen	offset     offset                   // struct field offset
44*1c12ee1eSDan Willemsen	wiretag    uint64                   // field tag (number + wire type)
45*1c12ee1eSDan Willemsen	tagsize    int                      // size of the varint-encoded tag
46*1c12ee1eSDan Willemsen	isPointer  bool                     // true if IsNil may be called on the struct field
47*1c12ee1eSDan Willemsen	isRequired bool                     // true if field is required
48*1c12ee1eSDan Willemsen}
49*1c12ee1eSDan Willemsen
50*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) makeCoderMethods(t reflect.Type, si structInfo) {
51*1c12ee1eSDan Willemsen	mi.sizecacheOffset = invalidOffset
52*1c12ee1eSDan Willemsen	mi.unknownOffset = invalidOffset
53*1c12ee1eSDan Willemsen	mi.extensionOffset = invalidOffset
54*1c12ee1eSDan Willemsen
55*1c12ee1eSDan Willemsen	if si.sizecacheOffset.IsValid() && si.sizecacheType == sizecacheType {
56*1c12ee1eSDan Willemsen		mi.sizecacheOffset = si.sizecacheOffset
57*1c12ee1eSDan Willemsen	}
58*1c12ee1eSDan Willemsen	if si.unknownOffset.IsValid() && (si.unknownType == unknownFieldsAType || si.unknownType == unknownFieldsBType) {
59*1c12ee1eSDan Willemsen		mi.unknownOffset = si.unknownOffset
60*1c12ee1eSDan Willemsen		mi.unknownPtrKind = si.unknownType.Kind() == reflect.Ptr
61*1c12ee1eSDan Willemsen	}
62*1c12ee1eSDan Willemsen	if si.extensionOffset.IsValid() && si.extensionType == extensionFieldsType {
63*1c12ee1eSDan Willemsen		mi.extensionOffset = si.extensionOffset
64*1c12ee1eSDan Willemsen	}
65*1c12ee1eSDan Willemsen
66*1c12ee1eSDan Willemsen	mi.coderFields = make(map[protowire.Number]*coderFieldInfo)
67*1c12ee1eSDan Willemsen	fields := mi.Desc.Fields()
68*1c12ee1eSDan Willemsen	preallocFields := make([]coderFieldInfo, fields.Len())
69*1c12ee1eSDan Willemsen	for i := 0; i < fields.Len(); i++ {
70*1c12ee1eSDan Willemsen		fd := fields.Get(i)
71*1c12ee1eSDan Willemsen
72*1c12ee1eSDan Willemsen		fs := si.fieldsByNumber[fd.Number()]
73*1c12ee1eSDan Willemsen		isOneof := fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic()
74*1c12ee1eSDan Willemsen		if isOneof {
75*1c12ee1eSDan Willemsen			fs = si.oneofsByName[fd.ContainingOneof().Name()]
76*1c12ee1eSDan Willemsen		}
77*1c12ee1eSDan Willemsen		ft := fs.Type
78*1c12ee1eSDan Willemsen		var wiretag uint64
79*1c12ee1eSDan Willemsen		if !fd.IsPacked() {
80*1c12ee1eSDan Willemsen			wiretag = protowire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
81*1c12ee1eSDan Willemsen		} else {
82*1c12ee1eSDan Willemsen			wiretag = protowire.EncodeTag(fd.Number(), protowire.BytesType)
83*1c12ee1eSDan Willemsen		}
84*1c12ee1eSDan Willemsen		var fieldOffset offset
85*1c12ee1eSDan Willemsen		var funcs pointerCoderFuncs
86*1c12ee1eSDan Willemsen		var childMessage *MessageInfo
87*1c12ee1eSDan Willemsen		switch {
88*1c12ee1eSDan Willemsen		case ft == nil:
89*1c12ee1eSDan Willemsen			// This never occurs for generated message types.
90*1c12ee1eSDan Willemsen			// It implies that a hand-crafted type has missing Go fields
91*1c12ee1eSDan Willemsen			// for specific protobuf message fields.
92*1c12ee1eSDan Willemsen			funcs = pointerCoderFuncs{
93*1c12ee1eSDan Willemsen				size: func(p pointer, f *coderFieldInfo, opts marshalOptions) int {
94*1c12ee1eSDan Willemsen					return 0
95*1c12ee1eSDan Willemsen				},
96*1c12ee1eSDan Willemsen				marshal: func(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
97*1c12ee1eSDan Willemsen					return nil, nil
98*1c12ee1eSDan Willemsen				},
99*1c12ee1eSDan Willemsen				unmarshal: func(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error) {
100*1c12ee1eSDan Willemsen					panic("missing Go struct field for " + string(fd.FullName()))
101*1c12ee1eSDan Willemsen				},
102*1c12ee1eSDan Willemsen				isInit: func(p pointer, f *coderFieldInfo) error {
103*1c12ee1eSDan Willemsen					panic("missing Go struct field for " + string(fd.FullName()))
104*1c12ee1eSDan Willemsen				},
105*1c12ee1eSDan Willemsen				merge: func(dst, src pointer, f *coderFieldInfo, opts mergeOptions) {
106*1c12ee1eSDan Willemsen					panic("missing Go struct field for " + string(fd.FullName()))
107*1c12ee1eSDan Willemsen				},
108*1c12ee1eSDan Willemsen			}
109*1c12ee1eSDan Willemsen		case isOneof:
110*1c12ee1eSDan Willemsen			fieldOffset = offsetOf(fs, mi.Exporter)
111*1c12ee1eSDan Willemsen		case fd.IsWeak():
112*1c12ee1eSDan Willemsen			fieldOffset = si.weakOffset
113*1c12ee1eSDan Willemsen			funcs = makeWeakMessageFieldCoder(fd)
114*1c12ee1eSDan Willemsen		default:
115*1c12ee1eSDan Willemsen			fieldOffset = offsetOf(fs, mi.Exporter)
116*1c12ee1eSDan Willemsen			childMessage, funcs = fieldCoder(fd, ft)
117*1c12ee1eSDan Willemsen		}
118*1c12ee1eSDan Willemsen		cf := &preallocFields[i]
119*1c12ee1eSDan Willemsen		*cf = coderFieldInfo{
120*1c12ee1eSDan Willemsen			num:        fd.Number(),
121*1c12ee1eSDan Willemsen			offset:     fieldOffset,
122*1c12ee1eSDan Willemsen			wiretag:    wiretag,
123*1c12ee1eSDan Willemsen			ft:         ft,
124*1c12ee1eSDan Willemsen			tagsize:    protowire.SizeVarint(wiretag),
125*1c12ee1eSDan Willemsen			funcs:      funcs,
126*1c12ee1eSDan Willemsen			mi:         childMessage,
127*1c12ee1eSDan Willemsen			validation: newFieldValidationInfo(mi, si, fd, ft),
128*1c12ee1eSDan Willemsen			isPointer:  fd.Cardinality() == protoreflect.Repeated || fd.HasPresence(),
129*1c12ee1eSDan Willemsen			isRequired: fd.Cardinality() == protoreflect.Required,
130*1c12ee1eSDan Willemsen		}
131*1c12ee1eSDan Willemsen		mi.orderedCoderFields = append(mi.orderedCoderFields, cf)
132*1c12ee1eSDan Willemsen		mi.coderFields[cf.num] = cf
133*1c12ee1eSDan Willemsen	}
134*1c12ee1eSDan Willemsen	for i, oneofs := 0, mi.Desc.Oneofs(); i < oneofs.Len(); i++ {
135*1c12ee1eSDan Willemsen		if od := oneofs.Get(i); !od.IsSynthetic() {
136*1c12ee1eSDan Willemsen			mi.initOneofFieldCoders(od, si)
137*1c12ee1eSDan Willemsen		}
138*1c12ee1eSDan Willemsen	}
139*1c12ee1eSDan Willemsen	if messageset.IsMessageSet(mi.Desc) {
140*1c12ee1eSDan Willemsen		if !mi.extensionOffset.IsValid() {
141*1c12ee1eSDan Willemsen			panic(fmt.Sprintf("%v: MessageSet with no extensions field", mi.Desc.FullName()))
142*1c12ee1eSDan Willemsen		}
143*1c12ee1eSDan Willemsen		if !mi.unknownOffset.IsValid() {
144*1c12ee1eSDan Willemsen			panic(fmt.Sprintf("%v: MessageSet with no unknown field", mi.Desc.FullName()))
145*1c12ee1eSDan Willemsen		}
146*1c12ee1eSDan Willemsen		mi.isMessageSet = true
147*1c12ee1eSDan Willemsen	}
148*1c12ee1eSDan Willemsen	sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
149*1c12ee1eSDan Willemsen		return mi.orderedCoderFields[i].num < mi.orderedCoderFields[j].num
150*1c12ee1eSDan Willemsen	})
151*1c12ee1eSDan Willemsen
152*1c12ee1eSDan Willemsen	var maxDense protoreflect.FieldNumber
153*1c12ee1eSDan Willemsen	for _, cf := range mi.orderedCoderFields {
154*1c12ee1eSDan Willemsen		if cf.num >= 16 && cf.num >= 2*maxDense {
155*1c12ee1eSDan Willemsen			break
156*1c12ee1eSDan Willemsen		}
157*1c12ee1eSDan Willemsen		maxDense = cf.num
158*1c12ee1eSDan Willemsen	}
159*1c12ee1eSDan Willemsen	mi.denseCoderFields = make([]*coderFieldInfo, maxDense+1)
160*1c12ee1eSDan Willemsen	for _, cf := range mi.orderedCoderFields {
161*1c12ee1eSDan Willemsen		if int(cf.num) >= len(mi.denseCoderFields) {
162*1c12ee1eSDan Willemsen			break
163*1c12ee1eSDan Willemsen		}
164*1c12ee1eSDan Willemsen		mi.denseCoderFields[cf.num] = cf
165*1c12ee1eSDan Willemsen	}
166*1c12ee1eSDan Willemsen
167*1c12ee1eSDan Willemsen	// To preserve compatibility with historic wire output, marshal oneofs last.
168*1c12ee1eSDan Willemsen	if mi.Desc.Oneofs().Len() > 0 {
169*1c12ee1eSDan Willemsen		sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
170*1c12ee1eSDan Willemsen			fi := fields.ByNumber(mi.orderedCoderFields[i].num)
171*1c12ee1eSDan Willemsen			fj := fields.ByNumber(mi.orderedCoderFields[j].num)
172*1c12ee1eSDan Willemsen			return order.LegacyFieldOrder(fi, fj)
173*1c12ee1eSDan Willemsen		})
174*1c12ee1eSDan Willemsen	}
175*1c12ee1eSDan Willemsen
176*1c12ee1eSDan Willemsen	mi.needsInitCheck = needsInitCheck(mi.Desc)
177*1c12ee1eSDan Willemsen	if mi.methods.Marshal == nil && mi.methods.Size == nil {
178*1c12ee1eSDan Willemsen		mi.methods.Flags |= protoiface.SupportMarshalDeterministic
179*1c12ee1eSDan Willemsen		mi.methods.Marshal = mi.marshal
180*1c12ee1eSDan Willemsen		mi.methods.Size = mi.size
181*1c12ee1eSDan Willemsen	}
182*1c12ee1eSDan Willemsen	if mi.methods.Unmarshal == nil {
183*1c12ee1eSDan Willemsen		mi.methods.Flags |= protoiface.SupportUnmarshalDiscardUnknown
184*1c12ee1eSDan Willemsen		mi.methods.Unmarshal = mi.unmarshal
185*1c12ee1eSDan Willemsen	}
186*1c12ee1eSDan Willemsen	if mi.methods.CheckInitialized == nil {
187*1c12ee1eSDan Willemsen		mi.methods.CheckInitialized = mi.checkInitialized
188*1c12ee1eSDan Willemsen	}
189*1c12ee1eSDan Willemsen	if mi.methods.Merge == nil {
190*1c12ee1eSDan Willemsen		mi.methods.Merge = mi.merge
191*1c12ee1eSDan Willemsen	}
192*1c12ee1eSDan Willemsen}
193*1c12ee1eSDan Willemsen
194*1c12ee1eSDan Willemsen// getUnknownBytes returns a *[]byte for the unknown fields.
195*1c12ee1eSDan Willemsen// It is the caller's responsibility to check whether the pointer is nil.
196*1c12ee1eSDan Willemsen// This function is specially designed to be inlineable.
197*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) getUnknownBytes(p pointer) *[]byte {
198*1c12ee1eSDan Willemsen	if mi.unknownPtrKind {
199*1c12ee1eSDan Willemsen		return *p.Apply(mi.unknownOffset).BytesPtr()
200*1c12ee1eSDan Willemsen	} else {
201*1c12ee1eSDan Willemsen		return p.Apply(mi.unknownOffset).Bytes()
202*1c12ee1eSDan Willemsen	}
203*1c12ee1eSDan Willemsen}
204*1c12ee1eSDan Willemsen
205*1c12ee1eSDan Willemsen// mutableUnknownBytes returns a *[]byte for the unknown fields.
206*1c12ee1eSDan Willemsen// The returned pointer is guaranteed to not be nil.
207*1c12ee1eSDan Willemsenfunc (mi *MessageInfo) mutableUnknownBytes(p pointer) *[]byte {
208*1c12ee1eSDan Willemsen	if mi.unknownPtrKind {
209*1c12ee1eSDan Willemsen		bp := p.Apply(mi.unknownOffset).BytesPtr()
210*1c12ee1eSDan Willemsen		if *bp == nil {
211*1c12ee1eSDan Willemsen			*bp = new([]byte)
212*1c12ee1eSDan Willemsen		}
213*1c12ee1eSDan Willemsen		return *bp
214*1c12ee1eSDan Willemsen	} else {
215*1c12ee1eSDan Willemsen		return p.Apply(mi.unknownOffset).Bytes()
216*1c12ee1eSDan Willemsen	}
217*1c12ee1eSDan Willemsen}
218