blob: 2d5b37643171b9da44bf0aca0b4a3dd0a3c917f7 [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
21 sizecacheOffset offset
22 extensionOffset offset
23 unknownOffset offset
24 needsInitCheck bool
25}
26
27type coderFieldInfo struct {
28 funcs pointerCoderFuncs // fast-path per-field functions
29 num pref.FieldNumber // field number
30 offset offset // struct field offset
31 wiretag uint64 // field tag (number + wire type)
32 tagsize int // size of the varint-encoded tag
33 isPointer bool // true if IsNil may be called on the struct field
34 isRequired bool // true if field is required
35}
36
37func (mi *MessageInfo) makeMethods(t reflect.Type, si structInfo) {
Joe Tsai93fd9682019-07-06 13:02:14 -070038 mi.sizecacheOffset = si.sizecacheOffset
39 mi.unknownOffset = si.unknownOffset
40 mi.extensionOffset = si.extensionOffset
Damien Neil4ae30bb2019-06-20 10:12:23 -070041
42 for i := 0; i < mi.PBType.Descriptor().Fields().Len(); i++ {
43 fd := mi.PBType.Descriptor().Fields().Get(i)
44 if fd.ContainingOneof() != nil {
45 continue
46 }
47
48 fs := si.fieldsByNumber[fd.Number()]
49 ft := fs.Type
50 var wiretag uint64
51 if !fd.IsPacked() {
52 wiretag = wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
53 } else {
54 wiretag = wire.EncodeTag(fd.Number(), wire.BytesType)
55 }
56 mi.orderedCoderFields = append(mi.orderedCoderFields, &coderFieldInfo{
57 num: fd.Number(),
58 offset: offsetOf(fs),
59 wiretag: wiretag,
60 tagsize: wire.SizeVarint(wiretag),
61 funcs: fieldCoder(fd, ft),
62 isPointer: (fd.Cardinality() == pref.Repeated ||
63 fd.Kind() == pref.MessageKind ||
64 fd.Kind() == pref.GroupKind ||
65 fd.Syntax() != pref.Proto3),
66 isRequired: fd.Cardinality() == pref.Required,
67 })
68 }
69 for i := 0; i < mi.PBType.Descriptor().Oneofs().Len(); i++ {
70 od := mi.PBType.Descriptor().Oneofs().Get(i)
71 fs := si.oneofsByName[od.Name()]
72 mi.orderedCoderFields = append(mi.orderedCoderFields, &coderFieldInfo{
73 num: od.Fields().Get(0).Number(),
74 offset: offsetOf(fs),
75 funcs: makeOneofFieldCoder(fs, od, si.fieldsByNumber, si.oneofWrappersByNumber),
76 isPointer: true,
77 })
78 }
79 sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
80 return mi.orderedCoderFields[i].num < mi.orderedCoderFields[j].num
81 })
82
83 mi.needsInitCheck = needsInitCheck(mi.PBType)
84 mi.methods = piface.Methods{
85 Flags: piface.MethodFlagDeterministicMarshal,
86 MarshalAppend: mi.marshalAppend,
87 Size: mi.size,
88 IsInitialized: mi.isInitialized,
89 }
90}