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