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