256
|
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" |
260
|
17 |
"google.golang.org/protobuf/reflect/protoregistry" |
256
|
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. |
260
|
31 |
Desc protoreflect.MessageDescriptor |
256
|
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 { |
260
|
56 |
m, ok := reflect.Zero(mt).Interface().(protoreflect.ProtoMessage) |
256
|
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. |
260
|
99 |
func (mi *MessageInfo) getPointer(m protoreflect.Message) (p pointer, ok bool) { |
256
|
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 |
|
260
|
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 |
256
|
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 |
|
260
|
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{}, |
256
|
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) |
260
|
182 |
si.fieldsByNumber[protoreflect.FieldNumber(n)] = f |
256
|
183 |
continue fieldLoop |
|
184 |
} |
|
185 |
} |
|
186 |
if s := f.Tag.Get("protobuf_oneof"); len(s) > 0 { |
260
|
187 |
si.oneofsByName[protoreflect.Name(s)] = f |
256
|
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) |
260
|
210 |
si.oneofWrappersByType[tf] = protoreflect.FieldNumber(n) |
|
211 |
si.oneofWrappersByNumber[protoreflect.FieldNumber(n)] = tf |
256
|
212 |
break |
|
213 |
} |
|
214 |
} |
|
215 |
} |
|
216 |
|
|
217 |
return si |
|
218 |
} |
|
219 |
|
|
220 |
func (mi *MessageInfo) New() protoreflect.Message { |
260
|
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) |
256
|
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(): |
260
|
243 |
mt, _ := protoregistry.GlobalTypes.FindMessageByName(fd.Message().FullName()) |
256
|
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 |
} |