1
// Copyright 2019 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
12
"google.golang.org/protobuf/encoding/protowire"
13
"google.golang.org/protobuf/internal/encoding/messageset"
14
"google.golang.org/protobuf/internal/order"
15
"google.golang.org/protobuf/reflect/protoreflect"
16
"google.golang.org/protobuf/runtime/protoiface"
19
// coderMessageInfo contains per-message information used by the fast-path functions.
20
// This is a different type from MessageInfo to keep MessageInfo as general-purpose as
22
type coderMessageInfo struct {
23
methods protoiface.Methods
25
orderedCoderFields []*coderFieldInfo
26
denseCoderFields []*coderFieldInfo
27
coderFields map[protowire.Number]*coderFieldInfo
28
sizecacheOffset offset
31
extensionOffset offset
34
numRequiredFields uint8
37
type coderFieldInfo struct {
38
funcs pointerCoderFuncs // fast-path per-field functions
39
mi *MessageInfo // field's message
41
validation validationInfo // information used by message validation
42
num protoreflect.FieldNumber // field number
43
offset offset // struct field offset
44
wiretag uint64 // field tag (number + wire type)
45
tagsize int // size of the varint-encoded tag
46
isPointer bool // true if IsNil may be called on the struct field
47
isRequired bool // true if field is required
50
func (mi *MessageInfo) makeCoderMethods(t reflect.Type, si structInfo) {
51
mi.sizecacheOffset = invalidOffset
52
mi.unknownOffset = invalidOffset
53
mi.extensionOffset = invalidOffset
55
if si.sizecacheOffset.IsValid() && si.sizecacheType == sizecacheType {
56
mi.sizecacheOffset = si.sizecacheOffset
58
if si.unknownOffset.IsValid() && (si.unknownType == unknownFieldsAType || si.unknownType == unknownFieldsBType) {
59
mi.unknownOffset = si.unknownOffset
60
mi.unknownPtrKind = si.unknownType.Kind() == reflect.Ptr
62
if si.extensionOffset.IsValid() && si.extensionType == extensionFieldsType {
63
mi.extensionOffset = si.extensionOffset
66
mi.coderFields = make(map[protowire.Number]*coderFieldInfo)
67
fields := mi.Desc.Fields()
68
preallocFields := make([]coderFieldInfo, fields.Len())
69
for i := 0; i < fields.Len(); i++ {
72
fs := si.fieldsByNumber[fd.Number()]
73
isOneof := fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic()
75
fs = si.oneofsByName[fd.ContainingOneof().Name()]
80
wiretag = protowire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
82
wiretag = protowire.EncodeTag(fd.Number(), protowire.BytesType)
84
var fieldOffset offset
85
var funcs pointerCoderFuncs
86
var childMessage *MessageInfo
89
// This never occurs for generated message types.
90
// It implies that a hand-crafted type has missing Go fields
91
// for specific protobuf message fields.
92
funcs = pointerCoderFuncs{
93
size: func(p pointer, f *coderFieldInfo, opts marshalOptions) int {
96
marshal: func(b []byte, p pointer, f *coderFieldInfo, opts marshalOptions) ([]byte, error) {
99
unmarshal: func(b []byte, p pointer, wtyp protowire.Type, f *coderFieldInfo, opts unmarshalOptions) (unmarshalOutput, error) {
100
panic("missing Go struct field for " + string(fd.FullName()))
102
isInit: func(p pointer, f *coderFieldInfo) error {
103
panic("missing Go struct field for " + string(fd.FullName()))
105
merge: func(dst, src pointer, f *coderFieldInfo, opts mergeOptions) {
106
panic("missing Go struct field for " + string(fd.FullName()))
110
fieldOffset = offsetOf(fs, mi.Exporter)
112
fieldOffset = si.weakOffset
113
funcs = makeWeakMessageFieldCoder(fd)
115
fieldOffset = offsetOf(fs, mi.Exporter)
116
childMessage, funcs = fieldCoder(fd, ft)
118
cf := &preallocFields[i]
119
*cf = coderFieldInfo{
124
tagsize: protowire.SizeVarint(wiretag),
127
validation: newFieldValidationInfo(mi, si, fd, ft),
128
isPointer: fd.Cardinality() == protoreflect.Repeated || fd.HasPresence(),
129
isRequired: fd.Cardinality() == protoreflect.Required,
131
mi.orderedCoderFields = append(mi.orderedCoderFields, cf)
132
mi.coderFields[cf.num] = cf
134
for i, oneofs := 0, mi.Desc.Oneofs(); i < oneofs.Len(); i++ {
135
if od := oneofs.Get(i); !od.IsSynthetic() {
136
mi.initOneofFieldCoders(od, si)
139
if messageset.IsMessageSet(mi.Desc) {
140
if !mi.extensionOffset.IsValid() {
141
panic(fmt.Sprintf("%v: MessageSet with no extensions field", mi.Desc.FullName()))
143
if !mi.unknownOffset.IsValid() {
144
panic(fmt.Sprintf("%v: MessageSet with no unknown field", mi.Desc.FullName()))
146
mi.isMessageSet = true
148
sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
149
return mi.orderedCoderFields[i].num < mi.orderedCoderFields[j].num
152
var maxDense protoreflect.FieldNumber
153
for _, cf := range mi.orderedCoderFields {
154
if cf.num >= 16 && cf.num >= 2*maxDense {
159
mi.denseCoderFields = make([]*coderFieldInfo, maxDense+1)
160
for _, cf := range mi.orderedCoderFields {
161
if int(cf.num) >= len(mi.denseCoderFields) {
164
mi.denseCoderFields[cf.num] = cf
167
// To preserve compatibility with historic wire output, marshal oneofs last.
168
if mi.Desc.Oneofs().Len() > 0 {
169
sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
170
fi := fields.ByNumber(mi.orderedCoderFields[i].num)
171
fj := fields.ByNumber(mi.orderedCoderFields[j].num)
172
return order.LegacyFieldOrder(fi, fj)
176
mi.needsInitCheck = needsInitCheck(mi.Desc)
177
if mi.methods.Marshal == nil && mi.methods.Size == nil {
178
mi.methods.Flags |= protoiface.SupportMarshalDeterministic
179
mi.methods.Marshal = mi.marshal
180
mi.methods.Size = mi.size
182
if mi.methods.Unmarshal == nil {
183
mi.methods.Flags |= protoiface.SupportUnmarshalDiscardUnknown
184
mi.methods.Unmarshal = mi.unmarshal
186
if mi.methods.CheckInitialized == nil {
187
mi.methods.CheckInitialized = mi.checkInitialized
189
if mi.methods.Merge == nil {
190
mi.methods.Merge = mi.merge
194
// getUnknownBytes returns a *[]byte for the unknown fields.
195
// It is the caller's responsibility to check whether the pointer is nil.
196
// This function is specially designed to be inlineable.
197
func (mi *MessageInfo) getUnknownBytes(p pointer) *[]byte {
198
if mi.unknownPtrKind {
199
return *p.Apply(mi.unknownOffset).BytesPtr()
201
return p.Apply(mi.unknownOffset).Bytes()
205
// mutableUnknownBytes returns a *[]byte for the unknown fields.
206
// The returned pointer is guaranteed to not be nil.
207
func (mi *MessageInfo) mutableUnknownBytes(p pointer) *[]byte {
208
if mi.unknownPtrKind {
209
bp := p.Apply(mi.unknownOffset).BytesPtr()
215
return p.Apply(mi.unknownOffset).Bytes()