blob: 61c88c1dd2fc91cb7733bf0a0825e495bf3329cb [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 (
8 "reflect"
9 "sort"
10
11 "google.golang.org/protobuf/internal/encoding/wire"
12 pref "google.golang.org/protobuf/reflect/protoreflect"
13 piface "google.golang.org/protobuf/runtime/protoiface"
14)
15
16// coderMessageInfo contains per-message information used by the fast-path functions.
17// This is a different type from MessageInfo to keep MessageInfo as general-purpose as
18// possible.
19type coderMessageInfo struct {
20 orderedCoderFields []*coderFieldInfo
Damien Neile91877d2019-06-27 10:54:42 -070021 denseCoderFields []*coderFieldInfo
22 coderFields map[wire.Number]*coderFieldInfo
Damien Neil4ae30bb2019-06-20 10:12:23 -070023 sizecacheOffset offset
Damien Neil4ae30bb2019-06-20 10:12:23 -070024 unknownOffset offset
Joe Tsaic0e4bb22019-07-06 13:05:11 -070025 extensionOffset offset
Damien Neil4ae30bb2019-06-20 10:12:23 -070026 needsInitCheck bool
27}
28
29type coderFieldInfo struct {
30 funcs pointerCoderFuncs // fast-path per-field functions
31 num pref.FieldNumber // field number
32 offset offset // struct field offset
33 wiretag uint64 // field tag (number + wire type)
34 tagsize int // size of the varint-encoded tag
35 isPointer bool // true if IsNil may be called on the struct field
36 isRequired bool // true if field is required
37}
38
39func (mi *MessageInfo) makeMethods(t reflect.Type, si structInfo) {
Joe Tsai93fd9682019-07-06 13:02:14 -070040 mi.sizecacheOffset = si.sizecacheOffset
41 mi.unknownOffset = si.unknownOffset
42 mi.extensionOffset = si.extensionOffset
Damien Neil4ae30bb2019-06-20 10:12:23 -070043
Damien Neile91877d2019-06-27 10:54:42 -070044 mi.coderFields = make(map[wire.Number]*coderFieldInfo)
Damien Neil4ae30bb2019-06-20 10:12:23 -070045 for i := 0; i < mi.PBType.Descriptor().Fields().Len(); i++ {
46 fd := mi.PBType.Descriptor().Fields().Get(i)
Damien Neil4ae30bb2019-06-20 10:12:23 -070047
48 fs := si.fieldsByNumber[fd.Number()]
Damien Neile91877d2019-06-27 10:54:42 -070049 if fd.ContainingOneof() != nil {
50 fs = si.oneofsByName[fd.ContainingOneof().Name()]
51 }
Damien Neil4ae30bb2019-06-20 10:12:23 -070052 ft := fs.Type
53 var wiretag uint64
54 if !fd.IsPacked() {
55 wiretag = wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
56 } else {
57 wiretag = wire.EncodeTag(fd.Number(), wire.BytesType)
58 }
Damien Neile91877d2019-06-27 10:54:42 -070059 var funcs pointerCoderFuncs
60 if fd.ContainingOneof() != nil {
61 funcs = makeOneofFieldCoder(si, fd)
62 } else {
63 funcs = fieldCoder(fd, ft)
64 }
65 cf := &coderFieldInfo{
Damien Neil4ae30bb2019-06-20 10:12:23 -070066 num: fd.Number(),
Joe Tsaic0e4bb22019-07-06 13:05:11 -070067 offset: offsetOf(fs, mi.Exporter),
Damien Neil4ae30bb2019-06-20 10:12:23 -070068 wiretag: wiretag,
69 tagsize: wire.SizeVarint(wiretag),
Damien Neile91877d2019-06-27 10:54:42 -070070 funcs: funcs,
Damien Neil4ae30bb2019-06-20 10:12:23 -070071 isPointer: (fd.Cardinality() == pref.Repeated ||
72 fd.Kind() == pref.MessageKind ||
73 fd.Kind() == pref.GroupKind ||
74 fd.Syntax() != pref.Proto3),
75 isRequired: fd.Cardinality() == pref.Required,
Damien Neile91877d2019-06-27 10:54:42 -070076 }
77 mi.orderedCoderFields = append(mi.orderedCoderFields, cf)
78 mi.coderFields[cf.num] = cf
Damien Neil4ae30bb2019-06-20 10:12:23 -070079 }
80 sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
81 return mi.orderedCoderFields[i].num < mi.orderedCoderFields[j].num
82 })
83
Damien Neile91877d2019-06-27 10:54:42 -070084 var maxDense pref.FieldNumber
85 for _, cf := range mi.orderedCoderFields {
86 if cf.num >= 16 && cf.num >= 2*maxDense {
87 break
88 }
89 maxDense = cf.num
90 }
91 mi.denseCoderFields = make([]*coderFieldInfo, maxDense+1)
92 for _, cf := range mi.orderedCoderFields {
93 if int(cf.num) > len(mi.denseCoderFields) {
94 break
95 }
96 mi.denseCoderFields[cf.num] = cf
97 }
98
Damien Neil4ae30bb2019-06-20 10:12:23 -070099 mi.needsInitCheck = needsInitCheck(mi.PBType)
100 mi.methods = piface.Methods{
101 Flags: piface.MethodFlagDeterministicMarshal,
102 MarshalAppend: mi.marshalAppend,
Damien Neile91877d2019-06-27 10:54:42 -0700103 Unmarshal: mi.unmarshal,
Damien Neil4ae30bb2019-06-20 10:12:23 -0700104 Size: mi.size,
105 IsInitialized: mi.isInitialized,
106 }
107}