blob: 204049d4d40b9a4e5910e9991676e9d2c8202dcb [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) {
38 mi.sizecacheOffset = invalidOffset
39 if fx, _ := t.FieldByName("XXX_sizecache"); fx.Type == sizecacheType {
40 mi.sizecacheOffset = offsetOf(fx)
41 }
42 mi.unknownOffset = invalidOffset
43 if fx, _ := t.FieldByName("XXX_unrecognized"); fx.Type == unknownFieldsType {
44 mi.unknownOffset = offsetOf(fx)
45 }
46 mi.extensionOffset = invalidOffset
47 if fx, _ := t.FieldByName("XXX_InternalExtensions"); fx.Type == extensionFieldsType {
48 mi.extensionOffset = offsetOf(fx)
49 } else if fx, _ = t.FieldByName("XXX_extensions"); fx.Type == extensionFieldsType {
50 mi.extensionOffset = offsetOf(fx)
51 }
52
53 for i := 0; i < mi.PBType.Descriptor().Fields().Len(); i++ {
54 fd := mi.PBType.Descriptor().Fields().Get(i)
55 if fd.ContainingOneof() != nil {
56 continue
57 }
58
59 fs := si.fieldsByNumber[fd.Number()]
60 ft := fs.Type
61 var wiretag uint64
62 if !fd.IsPacked() {
63 wiretag = wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
64 } else {
65 wiretag = wire.EncodeTag(fd.Number(), wire.BytesType)
66 }
67 mi.orderedCoderFields = append(mi.orderedCoderFields, &coderFieldInfo{
68 num: fd.Number(),
69 offset: offsetOf(fs),
70 wiretag: wiretag,
71 tagsize: wire.SizeVarint(wiretag),
72 funcs: fieldCoder(fd, ft),
73 isPointer: (fd.Cardinality() == pref.Repeated ||
74 fd.Kind() == pref.MessageKind ||
75 fd.Kind() == pref.GroupKind ||
76 fd.Syntax() != pref.Proto3),
77 isRequired: fd.Cardinality() == pref.Required,
78 })
79 }
80 for i := 0; i < mi.PBType.Descriptor().Oneofs().Len(); i++ {
81 od := mi.PBType.Descriptor().Oneofs().Get(i)
82 fs := si.oneofsByName[od.Name()]
83 mi.orderedCoderFields = append(mi.orderedCoderFields, &coderFieldInfo{
84 num: od.Fields().Get(0).Number(),
85 offset: offsetOf(fs),
86 funcs: makeOneofFieldCoder(fs, od, si.fieldsByNumber, si.oneofWrappersByNumber),
87 isPointer: true,
88 })
89 }
90 sort.Slice(mi.orderedCoderFields, func(i, j int) bool {
91 return mi.orderedCoderFields[i].num < mi.orderedCoderFields[j].num
92 })
93
94 mi.needsInitCheck = needsInitCheck(mi.PBType)
95 mi.methods = piface.Methods{
96 Flags: piface.MethodFlagDeterministicMarshal,
97 MarshalAppend: mi.marshalAppend,
98 Size: mi.size,
99 IsInitialized: mi.isInitialized,
100 }
101}