blob: 70148617eee0860d51b596e4934abe57c785d2fb [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
Damien Neil302cb322019-06-19 15:22:13 -070012 "google.golang.org/protobuf/internal/encoding/messageset"
Damien Neil4ae30bb2019-06-20 10:12:23 -070013 "google.golang.org/protobuf/internal/encoding/wire"
14 pref "google.golang.org/protobuf/reflect/protoreflect"
15 piface "google.golang.org/protobuf/runtime/protoiface"
16)
17
18// coderMessageInfo contains per-message information used by the fast-path functions.
19// This is a different type from MessageInfo to keep MessageInfo as general-purpose as
20// possible.
21type coderMessageInfo struct {
22 orderedCoderFields []*coderFieldInfo
Damien Neile91877d2019-06-27 10:54:42 -070023 denseCoderFields []*coderFieldInfo
24 coderFields map[wire.Number]*coderFieldInfo
Damien Neil4ae30bb2019-06-20 10:12:23 -070025 sizecacheOffset offset
Damien Neil4ae30bb2019-06-20 10:12:23 -070026 unknownOffset offset
Joe Tsaic0e4bb22019-07-06 13:05:11 -070027 extensionOffset offset
Damien Neil4ae30bb2019-06-20 10:12:23 -070028 needsInitCheck bool
29}
30
31type coderFieldInfo struct {
32 funcs pointerCoderFuncs // fast-path per-field functions
33 num pref.FieldNumber // field number
34 offset offset // struct field offset
35 wiretag uint64 // field tag (number + wire type)
36 tagsize int // size of the varint-encoded tag
37 isPointer bool // true if IsNil may be called on the struct field
38 isRequired bool // true if field is required
39}
40
41func (mi *MessageInfo) makeMethods(t reflect.Type, si structInfo) {
Joe Tsai93fd9682019-07-06 13:02:14 -070042 mi.sizecacheOffset = si.sizecacheOffset
43 mi.unknownOffset = si.unknownOffset
44 mi.extensionOffset = si.extensionOffset
Damien Neil4ae30bb2019-06-20 10:12:23 -070045
Damien Neile91877d2019-06-27 10:54:42 -070046 mi.coderFields = make(map[wire.Number]*coderFieldInfo)
Damien Neil92f76182019-08-02 16:58:08 -070047 fields := mi.PBType.Descriptor().Fields()
48 for i := 0; i < fields.Len(); i++ {
49 fd := fields.Get(i)
Damien Neil4ae30bb2019-06-20 10:12:23 -070050
51 fs := si.fieldsByNumber[fd.Number()]
Damien Neile91877d2019-06-27 10:54:42 -070052 if fd.ContainingOneof() != nil {
53 fs = si.oneofsByName[fd.ContainingOneof().Name()]
54 }
Damien Neil4ae30bb2019-06-20 10:12:23 -070055 ft := fs.Type
56 var wiretag uint64
57 if !fd.IsPacked() {
58 wiretag = wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
59 } else {
60 wiretag = wire.EncodeTag(fd.Number(), wire.BytesType)
61 }
Damien Neile91877d2019-06-27 10:54:42 -070062 var funcs pointerCoderFuncs
63 if fd.ContainingOneof() != nil {
64 funcs = makeOneofFieldCoder(si, fd)
65 } else {
66 funcs = fieldCoder(fd, ft)
67 }
68 cf := &coderFieldInfo{
Damien Neil4ae30bb2019-06-20 10:12:23 -070069 num: fd.Number(),
Joe Tsaic0e4bb22019-07-06 13:05:11 -070070 offset: offsetOf(fs, mi.Exporter),
Damien Neil4ae30bb2019-06-20 10:12:23 -070071 wiretag: wiretag,
72 tagsize: wire.SizeVarint(wiretag),
Damien Neile91877d2019-06-27 10:54:42 -070073 funcs: funcs,
Damien Neil4ae30bb2019-06-20 10:12:23 -070074 isPointer: (fd.Cardinality() == pref.Repeated ||
75 fd.Kind() == pref.MessageKind ||
76 fd.Kind() == pref.GroupKind ||
77 fd.Syntax() != pref.Proto3),
78 isRequired: fd.Cardinality() == pref.Required,
Damien Neile91877d2019-06-27 10:54:42 -070079 }
80 mi.orderedCoderFields = append(mi.orderedCoderFields, cf)
81 mi.coderFields[cf.num] = cf
Damien Neil4ae30bb2019-06-20 10:12:23 -070082 }
Damien Neil302cb322019-06-19 15:22:13 -070083 if messageset.IsMessageSet(mi.PBType.Descriptor()) {
84 if !mi.extensionOffset.IsValid() {
Damien Neil92f76182019-08-02 16:58:08 -070085 panic(fmt.Sprintf("%v: MessageSet with no extensions field", mi.PBType.Descriptor().FullName()))
Damien Neil302cb322019-06-19 15:22:13 -070086 }
87 cf := &coderFieldInfo{
88 num: messageset.FieldItem,
89 offset: si.extensionOffset,
90 isPointer: true,
91 funcs: makeMessageSetFieldCoder(mi),
92 }
93 mi.orderedCoderFields = append(mi.orderedCoderFields, cf)
94 mi.coderFields[cf.num] = cf
95 // Invalidate the extension offset, since the field codec handles extensions.
96 mi.extensionOffset = invalidOffset
97 }
Damien Neil4ae30bb2019-06-20 10:12:23 -070098 sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
99 return mi.orderedCoderFields[i].num < mi.orderedCoderFields[j].num
100 })
101
Damien Neile91877d2019-06-27 10:54:42 -0700102 var maxDense pref.FieldNumber
103 for _, cf := range mi.orderedCoderFields {
104 if cf.num >= 16 && cf.num >= 2*maxDense {
105 break
106 }
107 maxDense = cf.num
108 }
109 mi.denseCoderFields = make([]*coderFieldInfo, maxDense+1)
110 for _, cf := range mi.orderedCoderFields {
111 if int(cf.num) > len(mi.denseCoderFields) {
112 break
113 }
114 mi.denseCoderFields[cf.num] = cf
115 }
116
Damien Neil92f76182019-08-02 16:58:08 -0700117 mi.needsInitCheck = needsInitCheck(mi.PBType.Descriptor())
Damien Neil4ae30bb2019-06-20 10:12:23 -0700118 mi.methods = piface.Methods{
Joe Tsaif8b855d2019-07-12 13:37:59 -0700119 Flags: piface.SupportMarshalDeterministic | piface.SupportUnmarshalDiscardUnknown,
Damien Neil4ae30bb2019-06-20 10:12:23 -0700120 MarshalAppend: mi.marshalAppend,
Damien Neile91877d2019-06-27 10:54:42 -0700121 Unmarshal: mi.unmarshal,
Damien Neil4ae30bb2019-06-20 10:12:23 -0700122 Size: mi.size,
123 IsInitialized: mi.isInitialized,
124 }
125}