1 | // Copyright 2018 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 |
|
---|
5 | package impl
|
---|
6 |
|
---|
7 | import (
|
---|
8 | "fmt"
|
---|
9 | "reflect"
|
---|
10 | "strconv"
|
---|
11 | "strings"
|
---|
12 | "sync"
|
---|
13 | "sync/atomic"
|
---|
14 |
|
---|
15 | "google.golang.org/protobuf/internal/genid"
|
---|
16 | "google.golang.org/protobuf/reflect/protoreflect"
|
---|
17 | "google.golang.org/protobuf/reflect/protoregistry"
|
---|
18 | )
|
---|
19 |
|
---|
20 | // MessageInfo provides protobuf related functionality for a given Go type
|
---|
21 | // that represents a message. A given instance of MessageInfo is tied to
|
---|
22 | // exactly one Go type, which must be a pointer to a struct type.
|
---|
23 | //
|
---|
24 | // The exported fields must be populated before any methods are called
|
---|
25 | // and cannot be mutated after set.
|
---|
26 | type MessageInfo struct {
|
---|
27 | // GoReflectType is the underlying message Go type and must be populated.
|
---|
28 | GoReflectType reflect.Type // pointer to struct
|
---|
29 |
|
---|
30 | // Desc is the underlying message descriptor type and must be populated.
|
---|
31 | Desc protoreflect.MessageDescriptor
|
---|
32 |
|
---|
33 | // Exporter must be provided in a purego environment in order to provide
|
---|
34 | // access to unexported fields.
|
---|
35 | Exporter exporter
|
---|
36 |
|
---|
37 | // OneofWrappers is list of pointers to oneof wrapper struct types.
|
---|
38 | OneofWrappers []interface{}
|
---|
39 |
|
---|
40 | initMu sync.Mutex // protects all unexported fields
|
---|
41 | initDone uint32
|
---|
42 |
|
---|
43 | reflectMessageInfo // for reflection implementation
|
---|
44 | coderMessageInfo // for fast-path method implementations
|
---|
45 | }
|
---|
46 |
|
---|
47 | // exporter is a function that returns a reference to the ith field of v,
|
---|
48 | // where v is a pointer to a struct. It returns nil if it does not support
|
---|
49 | // exporting the requested field (e.g., already exported).
|
---|
50 | type exporter func(v interface{}, i int) interface{}
|
---|
51 |
|
---|
52 | // getMessageInfo returns the MessageInfo for any message type that
|
---|
53 | // is generated by our implementation of protoc-gen-go (for v2 and on).
|
---|
54 | // If it is unable to obtain a MessageInfo, it returns nil.
|
---|
55 | func getMessageInfo(mt reflect.Type) *MessageInfo {
|
---|
56 | m, ok := reflect.Zero(mt).Interface().(protoreflect.ProtoMessage)
|
---|
57 | if !ok {
|
---|
58 | return nil
|
---|
59 | }
|
---|
60 | mr, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *MessageInfo })
|
---|
61 | if !ok {
|
---|
62 | return nil
|
---|
63 | }
|
---|
64 | return mr.ProtoMessageInfo()
|
---|
65 | }
|
---|
66 |
|
---|
67 | func (mi *MessageInfo) init() {
|
---|
68 | // This function is called in the hot path. Inline the sync.Once logic,
|
---|
69 | // since allocating a closure for Once.Do is expensive.
|
---|
70 | // Keep init small to ensure that it can be inlined.
|
---|
71 | if atomic.LoadUint32(&mi.initDone) == 0 {
|
---|
72 | mi.initOnce()
|
---|
73 | }
|
---|
74 | }
|
---|
75 |
|
---|
76 | func (mi *MessageInfo) initOnce() {
|
---|
77 | mi.initMu.Lock()
|
---|
78 | defer mi.initMu.Unlock()
|
---|
79 | if mi.initDone == 1 {
|
---|
80 | return
|
---|
81 | }
|
---|
82 |
|
---|
83 | t := mi.GoReflectType
|
---|
84 | if t.Kind() != reflect.Ptr && t.Elem().Kind() != reflect.Struct {
|
---|
85 | panic(fmt.Sprintf("got %v, want *struct kind", t))
|
---|
86 | }
|
---|
87 | t = t.Elem()
|
---|
88 |
|
---|
89 | si := mi.makeStructInfo(t)
|
---|
90 | mi.makeReflectFuncs(t, si)
|
---|
91 | mi.makeCoderMethods(t, si)
|
---|
92 |
|
---|
93 | atomic.StoreUint32(&mi.initDone, 1)
|
---|
94 | }
|
---|
95 |
|
---|
96 | // getPointer returns the pointer for a message, which should be of
|
---|
97 | // the type of the MessageInfo. If the message is of a different type,
|
---|
98 | // it returns ok==false.
|
---|
99 | func (mi *MessageInfo) getPointer(m protoreflect.Message) (p pointer, ok bool) {
|
---|
100 | switch m := m.(type) {
|
---|
101 | case *messageState:
|
---|
102 | return m.pointer(), m.messageInfo() == mi
|
---|
103 | case *messageReflectWrapper:
|
---|
104 | return m.pointer(), m.messageInfo() == mi
|
---|
105 | }
|
---|
106 | return pointer{}, false
|
---|
107 | }
|
---|
108 |
|
---|
109 | type (
|
---|
110 | SizeCache = int32
|
---|
111 | WeakFields = map[int32]protoreflect.ProtoMessage
|
---|
112 | UnknownFields = unknownFieldsA // TODO: switch to unknownFieldsB
|
---|
113 | unknownFieldsA = []byte
|
---|
114 | unknownFieldsB = *[]byte
|
---|
115 | ExtensionFields = map[int32]ExtensionField
|
---|
116 | )
|
---|
117 |
|
---|
118 | var (
|
---|
119 | sizecacheType = reflect.TypeOf(SizeCache(0))
|
---|
120 | weakFieldsType = reflect.TypeOf(WeakFields(nil))
|
---|
121 | unknownFieldsAType = reflect.TypeOf(unknownFieldsA(nil))
|
---|
122 | unknownFieldsBType = reflect.TypeOf(unknownFieldsB(nil))
|
---|
123 | extensionFieldsType = reflect.TypeOf(ExtensionFields(nil))
|
---|
124 | )
|
---|
125 |
|
---|
126 | type structInfo struct {
|
---|
127 | sizecacheOffset offset
|
---|
128 | sizecacheType reflect.Type
|
---|
129 | weakOffset offset
|
---|
130 | weakType reflect.Type
|
---|
131 | unknownOffset offset
|
---|
132 | unknownType reflect.Type
|
---|
133 | extensionOffset offset
|
---|
134 | extensionType reflect.Type
|
---|
135 |
|
---|
136 | fieldsByNumber map[protoreflect.FieldNumber]reflect.StructField
|
---|
137 | oneofsByName map[protoreflect.Name]reflect.StructField
|
---|
138 | oneofWrappersByType map[reflect.Type]protoreflect.FieldNumber
|
---|
139 | oneofWrappersByNumber map[protoreflect.FieldNumber]reflect.Type
|
---|
140 | }
|
---|
141 |
|
---|
142 | func (mi *MessageInfo) makeStructInfo(t reflect.Type) structInfo {
|
---|
143 | si := structInfo{
|
---|
144 | sizecacheOffset: invalidOffset,
|
---|
145 | weakOffset: invalidOffset,
|
---|
146 | unknownOffset: invalidOffset,
|
---|
147 | extensionOffset: invalidOffset,
|
---|
148 |
|
---|
149 | fieldsByNumber: map[protoreflect.FieldNumber]reflect.StructField{},
|
---|
150 | oneofsByName: map[protoreflect.Name]reflect.StructField{},
|
---|
151 | oneofWrappersByType: map[reflect.Type]protoreflect.FieldNumber{},
|
---|
152 | oneofWrappersByNumber: map[protoreflect.FieldNumber]reflect.Type{},
|
---|
153 | }
|
---|
154 |
|
---|
155 | fieldLoop:
|
---|
156 | for i := 0; i < t.NumField(); i++ {
|
---|
157 | switch f := t.Field(i); f.Name {
|
---|
158 | case genid.SizeCache_goname, genid.SizeCacheA_goname:
|
---|
159 | if f.Type == sizecacheType {
|
---|
160 | si.sizecacheOffset = offsetOf(f, mi.Exporter)
|
---|
161 | si.sizecacheType = f.Type
|
---|
162 | }
|
---|
163 | case genid.WeakFields_goname, genid.WeakFieldsA_goname:
|
---|
164 | if f.Type == weakFieldsType {
|
---|
165 | si.weakOffset = offsetOf(f, mi.Exporter)
|
---|
166 | si.weakType = f.Type
|
---|
167 | }
|
---|
168 | case genid.UnknownFields_goname, genid.UnknownFieldsA_goname:
|
---|
169 | if f.Type == unknownFieldsAType || f.Type == unknownFieldsBType {
|
---|
170 | si.unknownOffset = offsetOf(f, mi.Exporter)
|
---|
171 | si.unknownType = f.Type
|
---|
172 | }
|
---|
173 | case genid.ExtensionFields_goname, genid.ExtensionFieldsA_goname, genid.ExtensionFieldsB_goname:
|
---|
174 | if f.Type == extensionFieldsType {
|
---|
175 | si.extensionOffset = offsetOf(f, mi.Exporter)
|
---|
176 | si.extensionType = f.Type
|
---|
177 | }
|
---|
178 | default:
|
---|
179 | for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
|
---|
180 | if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
|
---|
181 | n, _ := strconv.ParseUint(s, 10, 64)
|
---|
182 | si.fieldsByNumber[protoreflect.FieldNumber(n)] = f
|
---|
183 | continue fieldLoop
|
---|
184 | }
|
---|
185 | }
|
---|
186 | if s := f.Tag.Get("protobuf_oneof"); len(s) > 0 {
|
---|
187 | si.oneofsByName[protoreflect.Name(s)] = f
|
---|
188 | continue fieldLoop
|
---|
189 | }
|
---|
190 | }
|
---|
191 | }
|
---|
192 |
|
---|
193 | // Derive a mapping of oneof wrappers to fields.
|
---|
194 | oneofWrappers := mi.OneofWrappers
|
---|
195 | for _, method := range []string{"XXX_OneofFuncs", "XXX_OneofWrappers"} {
|
---|
196 | if fn, ok := reflect.PtrTo(t).MethodByName(method); ok {
|
---|
197 | for _, v := range fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))}) {
|
---|
198 | if vs, ok := v.Interface().([]interface{}); ok {
|
---|
199 | oneofWrappers = vs
|
---|
200 | }
|
---|
201 | }
|
---|
202 | }
|
---|
203 | }
|
---|
204 | for _, v := range oneofWrappers {
|
---|
205 | tf := reflect.TypeOf(v).Elem()
|
---|
206 | f := tf.Field(0)
|
---|
207 | for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
|
---|
208 | if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
|
---|
209 | n, _ := strconv.ParseUint(s, 10, 64)
|
---|
210 | si.oneofWrappersByType[tf] = protoreflect.FieldNumber(n)
|
---|
211 | si.oneofWrappersByNumber[protoreflect.FieldNumber(n)] = tf
|
---|
212 | break
|
---|
213 | }
|
---|
214 | }
|
---|
215 | }
|
---|
216 |
|
---|
217 | return si
|
---|
218 | }
|
---|
219 |
|
---|
220 | func (mi *MessageInfo) New() protoreflect.Message {
|
---|
221 | m := reflect.New(mi.GoReflectType.Elem()).Interface()
|
---|
222 | if r, ok := m.(protoreflect.ProtoMessage); ok {
|
---|
223 | return r.ProtoReflect()
|
---|
224 | }
|
---|
225 | return mi.MessageOf(m)
|
---|
226 | }
|
---|
227 | func (mi *MessageInfo) Zero() protoreflect.Message {
|
---|
228 | return mi.MessageOf(reflect.Zero(mi.GoReflectType).Interface())
|
---|
229 | }
|
---|
230 | func (mi *MessageInfo) Descriptor() protoreflect.MessageDescriptor {
|
---|
231 | return mi.Desc
|
---|
232 | }
|
---|
233 | func (mi *MessageInfo) Enum(i int) protoreflect.EnumType {
|
---|
234 | mi.init()
|
---|
235 | fd := mi.Desc.Fields().Get(i)
|
---|
236 | return Export{}.EnumTypeOf(mi.fieldTypes[fd.Number()])
|
---|
237 | }
|
---|
238 | func (mi *MessageInfo) Message(i int) protoreflect.MessageType {
|
---|
239 | mi.init()
|
---|
240 | fd := mi.Desc.Fields().Get(i)
|
---|
241 | switch {
|
---|
242 | case fd.IsWeak():
|
---|
243 | mt, _ := protoregistry.GlobalTypes.FindMessageByName(fd.Message().FullName())
|
---|
244 | return mt
|
---|
245 | case fd.IsMap():
|
---|
246 | return mapEntryType{fd.Message(), mi.fieldTypes[fd.Number()]}
|
---|
247 | default:
|
---|
248 | return Export{}.MessageTypeOf(mi.fieldTypes[fd.Number()])
|
---|
249 | }
|
---|
250 | }
|
---|
251 |
|
---|
252 | type mapEntryType struct {
|
---|
253 | desc protoreflect.MessageDescriptor
|
---|
254 | valType interface{} // zero value of enum or message type
|
---|
255 | }
|
---|
256 |
|
---|
257 | func (mt mapEntryType) New() protoreflect.Message {
|
---|
258 | return nil
|
---|
259 | }
|
---|
260 | func (mt mapEntryType) Zero() protoreflect.Message {
|
---|
261 | return nil
|
---|
262 | }
|
---|
263 | func (mt mapEntryType) Descriptor() protoreflect.MessageDescriptor {
|
---|
264 | return mt.desc
|
---|
265 | }
|
---|
266 | func (mt mapEntryType) Enum(i int) protoreflect.EnumType {
|
---|
267 | fd := mt.desc.Fields().Get(i)
|
---|
268 | if fd.Enum() == nil {
|
---|
269 | return nil
|
---|
270 | }
|
---|
271 | return Export{}.EnumTypeOf(mt.valType)
|
---|
272 | }
|
---|
273 | func (mt mapEntryType) Message(i int) protoreflect.MessageType {
|
---|
274 | fd := mt.desc.Fields().Get(i)
|
---|
275 | if fd.Message() == nil {
|
---|
276 | return nil
|
---|
277 | }
|
---|
278 | return Export{}.MessageTypeOf(mt.valType)
|
---|
279 | }
|
---|