blob: 29ed59b445dc9188b57be9606df85954fa18f89b [file] [log] [blame]
Damien Neil4ae30bb2019-06-20 10:12:23 -07001// 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 (
Damien Neil302cb322019-06-19 15:22:13 -07008 "fmt"
Damien Neil4ae30bb2019-06-20 10:12:23 -07009 "reflect"
10 "sort"
11
Joe Tsaicd108d02020-02-14 18:08:02 -080012 "google.golang.org/protobuf/encoding/protowire"
Damien Neil302cb322019-06-19 15:22:13 -070013 "google.golang.org/protobuf/internal/encoding/messageset"
Damien Neil01c0e8d2019-11-12 12:33:12 -080014 "google.golang.org/protobuf/internal/fieldsort"
Damien Neil4ae30bb2019-06-20 10:12:23 -070015 pref "google.golang.org/protobuf/reflect/protoreflect"
16 piface "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 {
Joe Tsai0484b1a2019-08-13 15:36:08 -070023 methods piface.Methods
24
Damien Neil4ae30bb2019-06-20 10:12:23 -070025 orderedCoderFields []*coderFieldInfo
Damien Neile91877d2019-06-27 10:54:42 -070026 denseCoderFields []*coderFieldInfo
Joe Tsaicd108d02020-02-14 18:08:02 -080027 coderFields map[protowire.Number]*coderFieldInfo
Damien Neil4ae30bb2019-06-20 10:12:23 -070028 sizecacheOffset offset
Damien Neil4ae30bb2019-06-20 10:12:23 -070029 unknownOffset offset
Joe Tsaic0e4bb22019-07-06 13:05:11 -070030 extensionOffset offset
Damien Neil4ae30bb2019-06-20 10:12:23 -070031 needsInitCheck bool
Damien Neilce3384c2019-11-06 13:18:28 -080032 isMessageSet bool
Damien Neilb0c26f12019-12-16 09:37:59 -080033 numRequiredFields uint8
Damien Neil98f56d12020-04-21 10:46:11 -070034
35 // Include space for a number of coderFieldInfos to improve cache locality.
36 // The number of entries is chosen through a combination of guesswork and
37 // empirical testing.
38 coderFieldBuf [32]coderFieldInfo
Damien Neil4ae30bb2019-06-20 10:12:23 -070039}
40
41type coderFieldInfo struct {
42 funcs pointerCoderFuncs // fast-path per-field functions
Damien Neil316febd2020-02-09 12:26:50 -080043 mi *MessageInfo // field's message
44 ft reflect.Type
45 validation validationInfo // information used by message validation
46 num pref.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
Damien Neil4ae30bb2019-06-20 10:12:23 -070052}
53
Joe Tsai0484b1a2019-08-13 15:36:08 -070054func (mi *MessageInfo) makeCoderMethods(t reflect.Type, si structInfo) {
Joe Tsai93fd9682019-07-06 13:02:14 -070055 mi.sizecacheOffset = si.sizecacheOffset
56 mi.unknownOffset = si.unknownOffset
57 mi.extensionOffset = si.extensionOffset
Damien Neil4ae30bb2019-06-20 10:12:23 -070058
Joe Tsaicd108d02020-02-14 18:08:02 -080059 mi.coderFields = make(map[protowire.Number]*coderFieldInfo)
Damien Neil16163b42019-08-06 15:43:25 -070060 fields := mi.Desc.Fields()
Damien Neil98f56d12020-04-21 10:46:11 -070061 preallocFields := mi.coderFieldBuf[:]
Damien Neil92f76182019-08-02 16:58:08 -070062 for i := 0; i < fields.Len(); i++ {
63 fd := fields.Get(i)
Damien Neil4ae30bb2019-06-20 10:12:23 -070064
65 fs := si.fieldsByNumber[fd.Number()]
Joe Tsai387873d2020-04-28 14:44:38 -070066 isOneof := fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic()
67 if isOneof {
Damien Neile91877d2019-06-27 10:54:42 -070068 fs = si.oneofsByName[fd.ContainingOneof().Name()]
69 }
Damien Neil4ae30bb2019-06-20 10:12:23 -070070 ft := fs.Type
71 var wiretag uint64
72 if !fd.IsPacked() {
Joe Tsaicd108d02020-02-14 18:08:02 -080073 wiretag = protowire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
Damien Neil4ae30bb2019-06-20 10:12:23 -070074 } else {
Joe Tsaicd108d02020-02-14 18:08:02 -080075 wiretag = protowire.EncodeTag(fd.Number(), protowire.BytesType)
Damien Neil4ae30bb2019-06-20 10:12:23 -070076 }
Joe Tsai6e095992019-08-10 13:56:36 -070077 var fieldOffset offset
Damien Neile91877d2019-06-27 10:54:42 -070078 var funcs pointerCoderFuncs
Damien Neil316febd2020-02-09 12:26:50 -080079 var childMessage *MessageInfo
Joe Tsai6e095992019-08-10 13:56:36 -070080 switch {
Joe Tsai387873d2020-04-28 14:44:38 -070081 case isOneof:
Joe Tsai6e095992019-08-10 13:56:36 -070082 fieldOffset = offsetOf(fs, mi.Exporter)
Joe Tsai6e095992019-08-10 13:56:36 -070083 case fd.IsWeak():
84 fieldOffset = si.weakOffset
85 funcs = makeWeakMessageFieldCoder(fd)
86 default:
87 fieldOffset = offsetOf(fs, mi.Exporter)
Damien Neil316febd2020-02-09 12:26:50 -080088 childMessage, funcs = fieldCoder(fd, ft)
Damien Neile91877d2019-06-27 10:54:42 -070089 }
Damien Neil98f56d12020-04-21 10:46:11 -070090 var cf *coderFieldInfo
91 if len(preallocFields) > 0 {
92 cf = &preallocFields[0]
93 preallocFields = preallocFields[1:]
94 } else {
95 cf = new(coderFieldInfo)
96 }
97 *cf = coderFieldInfo{
Damien Neilb0c26f12019-12-16 09:37:59 -080098 num: fd.Number(),
99 offset: fieldOffset,
100 wiretag: wiretag,
Damien Neil316febd2020-02-09 12:26:50 -0800101 ft: ft,
Joe Tsaicd108d02020-02-14 18:08:02 -0800102 tagsize: protowire.SizeVarint(wiretag),
Damien Neilb0c26f12019-12-16 09:37:59 -0800103 funcs: funcs,
Damien Neil316febd2020-02-09 12:26:50 -0800104 mi: childMessage,
Damien Neilb0c26f12019-12-16 09:37:59 -0800105 validation: newFieldValidationInfo(mi, si, fd, ft),
Joe Tsai387873d2020-04-28 14:44:38 -0700106 isPointer: fd.Cardinality() == pref.Repeated || fd.HasPresence(),
Damien Neil4ae30bb2019-06-20 10:12:23 -0700107 isRequired: fd.Cardinality() == pref.Required,
Damien Neile91877d2019-06-27 10:54:42 -0700108 }
109 mi.orderedCoderFields = append(mi.orderedCoderFields, cf)
110 mi.coderFields[cf.num] = cf
Damien Neil4ae30bb2019-06-20 10:12:23 -0700111 }
Damien Neilce413af2019-12-05 16:36:28 -0800112 for i, oneofs := 0, mi.Desc.Oneofs(); i < oneofs.Len(); i++ {
Joe Tsai387873d2020-04-28 14:44:38 -0700113 if od := oneofs.Get(i); !od.IsSynthetic() {
114 mi.initOneofFieldCoders(od, si)
115 }
Damien Neilce413af2019-12-05 16:36:28 -0800116 }
Damien Neil16163b42019-08-06 15:43:25 -0700117 if messageset.IsMessageSet(mi.Desc) {
Damien Neil302cb322019-06-19 15:22:13 -0700118 if !mi.extensionOffset.IsValid() {
Damien Neil16163b42019-08-06 15:43:25 -0700119 panic(fmt.Sprintf("%v: MessageSet with no extensions field", mi.Desc.FullName()))
Damien Neil302cb322019-06-19 15:22:13 -0700120 }
Damien Neilce3384c2019-11-06 13:18:28 -0800121 if !mi.unknownOffset.IsValid() {
122 panic(fmt.Sprintf("%v: MessageSet with no unknown field", mi.Desc.FullName()))
Damien Neil302cb322019-06-19 15:22:13 -0700123 }
Damien Neilce3384c2019-11-06 13:18:28 -0800124 mi.isMessageSet = true
Damien Neil302cb322019-06-19 15:22:13 -0700125 }
Damien Neil4ae30bb2019-06-20 10:12:23 -0700126 sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
127 return mi.orderedCoderFields[i].num < mi.orderedCoderFields[j].num
128 })
129
Damien Neile91877d2019-06-27 10:54:42 -0700130 var maxDense pref.FieldNumber
131 for _, cf := range mi.orderedCoderFields {
132 if cf.num >= 16 && cf.num >= 2*maxDense {
133 break
134 }
135 maxDense = cf.num
136 }
137 mi.denseCoderFields = make([]*coderFieldInfo, maxDense+1)
138 for _, cf := range mi.orderedCoderFields {
Damien Neila5526f02020-04-21 13:56:02 -0700139 if int(cf.num) >= len(mi.denseCoderFields) {
Damien Neile91877d2019-06-27 10:54:42 -0700140 break
141 }
142 mi.denseCoderFields[cf.num] = cf
143 }
144
Damien Neil01c0e8d2019-11-12 12:33:12 -0800145 // To preserve compatibility with historic wire output, marshal oneofs last.
146 if mi.Desc.Oneofs().Len() > 0 {
147 sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
148 fi := fields.ByNumber(mi.orderedCoderFields[i].num)
149 fj := fields.ByNumber(mi.orderedCoderFields[j].num)
150 return fieldsort.Less(fi, fj)
151 })
152 }
153
Damien Neil16163b42019-08-06 15:43:25 -0700154 mi.needsInitCheck = needsInitCheck(mi.Desc)
Damien Neil61781dd2020-01-21 13:29:51 -0800155 if mi.methods.Marshal == nil && mi.methods.Size == nil {
Damien Neil37ef6912019-09-25 16:51:15 -0700156 mi.methods.Flags |= piface.SupportMarshalDeterministic
Damien Neil61781dd2020-01-21 13:29:51 -0800157 mi.methods.Marshal = mi.marshal
Damien Neil37ef6912019-09-25 16:51:15 -0700158 mi.methods.Size = mi.size
159 }
160 if mi.methods.Unmarshal == nil {
161 mi.methods.Flags |= piface.SupportUnmarshalDiscardUnknown
162 mi.methods.Unmarshal = mi.unmarshal
163 }
Joe Tsaif26a9e72020-02-20 10:05:37 -0800164 if mi.methods.CheckInitialized == nil {
165 mi.methods.CheckInitialized = mi.checkInitialized
Damien Neil4ae30bb2019-06-20 10:12:23 -0700166 }
Damien Neile8e88752020-02-11 11:25:16 -0800167 if mi.methods.Merge == nil {
168 mi.methods.Merge = mi.merge
169 }
Damien Neil4ae30bb2019-06-20 10:12:23 -0700170}