blob: ec9be4ecdc0c53a8bc4e5a46b021ff23396ba24c [file] [log] [blame]
Joe Tsaifa02f4e2018-09-12 16:20:37 -07001// 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
5package impl
6
7import (
Joe Tsaic6b75612018-09-13 14:24:37 -07008 "fmt"
Joe Tsaifa02f4e2018-09-12 16:20:37 -07009 "reflect"
10 "strconv"
11 "strings"
Joe Tsaic6b75612018-09-13 14:24:37 -070012 "sync"
Damien Neilc37adef2019-04-01 13:49:56 -070013 "sync/atomic"
Joe Tsaifa02f4e2018-09-12 16:20:37 -070014
Damien Neile89e6242019-05-13 23:55:40 -070015 pvalue "google.golang.org/protobuf/internal/value"
16 pref "google.golang.org/protobuf/reflect/protoreflect"
17 piface "google.golang.org/protobuf/runtime/protoiface"
Joe Tsaifa02f4e2018-09-12 16:20:37 -070018)
19
Joe Tsai4fe96632019-05-22 05:12:36 -040020// MessageInfo provides protobuf related functionality for a given Go type
21// that represents a message. A given instance of MessageInfo is tied to
Joe Tsaic6b75612018-09-13 14:24:37 -070022// exactly one Go type, which must be a pointer to a struct type.
Joe Tsai4fe96632019-05-22 05:12:36 -040023type MessageInfo struct {
Damien Neil8012b442019-01-18 09:32:24 -080024 // GoType is the underlying message Go type and must be populated.
Joe Tsaic6b75612018-09-13 14:24:37 -070025 // Once set, this field must never be mutated.
Damien Neil8012b442019-01-18 09:32:24 -080026 GoType reflect.Type // pointer to struct
27
28 // PBType is the underlying message descriptor type and must be populated.
29 // Once set, this field must never be mutated.
30 PBType pref.MessageType
Joe Tsaic6b75612018-09-13 14:24:37 -070031
Joe Tsaic0e4bb22019-07-06 13:05:11 -070032 // Exporter must be provided in a purego environment in order to provide
33 // access to unexported fields.
34 Exporter exporter
35
Joe Tsai09912272019-07-08 10:38:11 -070036 // OneofWrappers is list of pointers to oneof wrapper struct types.
37 OneofWrappers []interface{}
38
Damien Neilc37adef2019-04-01 13:49:56 -070039 initMu sync.Mutex // protects all unexported fields
40 initDone uint32
Joe Tsaic6b75612018-09-13 14:24:37 -070041
Damien Neil4ae30bb2019-06-20 10:12:23 -070042 fields map[pref.FieldNumber]*fieldInfo
Joe Tsai4ec39c72019-04-03 13:40:53 -070043 oneofs map[pref.Name]*oneofInfo
Joe Tsaibe5348c2018-10-23 18:31:18 -070044
Joe Tsai378c1322019-04-25 23:48:08 -070045 getUnknown func(pointer) pref.RawFields
46 setUnknown func(pointer, pref.RawFields)
47
48 extensionMap func(pointer) *extensionMap
49
Damien Neil4ae30bb2019-06-20 10:12:23 -070050 // Information used by the fast-path methods.
Joe Tsai4a539f42019-06-17 12:30:25 -070051 methods piface.Methods
Damien Neil4ae30bb2019-06-20 10:12:23 -070052 coderMessageInfo
Damien Neilc37adef2019-04-01 13:49:56 -070053
Damien Neilc37adef2019-04-01 13:49:56 -070054 extensionFieldInfosMu sync.RWMutex
Joe Tsai89d49632019-06-04 16:20:00 -070055 extensionFieldInfos map[pref.ExtensionType]*extensionFieldInfo
Damien Neilc37adef2019-04-01 13:49:56 -070056}
57
Joe Tsaic0e4bb22019-07-06 13:05:11 -070058// exporter is a function that returns a reference to the ith field of v,
59// where v is a pointer to a struct. It returns nil if it does not support
60// exporting the requested field (e.g., already exported).
61type exporter func(v interface{}, i int) interface{}
62
Damien Neilc37adef2019-04-01 13:49:56 -070063var prefMessageType = reflect.TypeOf((*pref.Message)(nil)).Elem()
64
Joe Tsai4fe96632019-05-22 05:12:36 -040065// getMessageInfo returns the MessageInfo (if any) for a type.
Damien Neilc37adef2019-04-01 13:49:56 -070066//
Joe Tsai4fe96632019-05-22 05:12:36 -040067// We find the MessageInfo by calling the ProtoReflect method on the type's
Damien Neilc37adef2019-04-01 13:49:56 -070068// zero value and looking at the returned type to see if it is a
Joe Tsai4fe96632019-05-22 05:12:36 -040069// messageReflectWrapper. Note that the MessageInfo may still be uninitialized
Damien Neilc37adef2019-04-01 13:49:56 -070070// at this point.
Joe Tsai4fe96632019-05-22 05:12:36 -040071func getMessageInfo(mt reflect.Type) (mi *MessageInfo, ok bool) {
Damien Neilc37adef2019-04-01 13:49:56 -070072 method, ok := mt.MethodByName("ProtoReflect")
73 if !ok {
74 return nil, false
75 }
76 if method.Type.NumIn() != 1 || method.Type.NumOut() != 1 || method.Type.Out(0) != prefMessageType {
77 return nil, false
78 }
79 ret := reflect.Zero(mt).Method(method.Index).Call(nil)
80 m, ok := ret[0].Elem().Interface().(*messageReflectWrapper)
81 if !ok {
82 return nil, ok
83 }
84 return m.mi, true
Joe Tsaifa02f4e2018-09-12 16:20:37 -070085}
86
Joe Tsai4fe96632019-05-22 05:12:36 -040087func (mi *MessageInfo) init() {
Damien Neilc37adef2019-04-01 13:49:56 -070088 // This function is called in the hot path. Inline the sync.Once
89 // logic, since allocating a closure for Once.Do is expensive.
90 // Keep init small to ensure that it can be inlined.
91 if atomic.LoadUint32(&mi.initDone) == 1 {
92 return
93 }
94 mi.initOnce()
95}
Joe Tsaic6b75612018-09-13 14:24:37 -070096
Joe Tsai4fe96632019-05-22 05:12:36 -040097func (mi *MessageInfo) initOnce() {
Damien Neilc37adef2019-04-01 13:49:56 -070098 mi.initMu.Lock()
99 defer mi.initMu.Unlock()
100 if mi.initDone == 1 {
101 return
102 }
103
104 t := mi.GoType
105 if t.Kind() != reflect.Ptr && t.Elem().Kind() != reflect.Struct {
106 panic(fmt.Sprintf("got %v, want *struct kind", t))
107 }
108
109 si := mi.makeStructInfo(t.Elem())
110 mi.makeKnownFieldsFunc(si)
Joe Tsai93fd9682019-07-06 13:02:14 -0700111 mi.makeUnknownFieldsFunc(t.Elem(), si)
112 mi.makeExtensionFieldsFunc(t.Elem(), si)
Damien Neil4ae30bb2019-06-20 10:12:23 -0700113 mi.makeMethods(t.Elem(), si)
Damien Neilc37adef2019-04-01 13:49:56 -0700114
115 atomic.StoreUint32(&mi.initDone, 1)
116}
117
Joe Tsai378c1322019-04-25 23:48:08 -0700118type (
119 SizeCache = int32
120 UnknownFields = []byte
121 ExtensionFields = map[int32]ExtensionField
122)
123
124var (
125 sizecacheType = reflect.TypeOf(SizeCache(0))
126 unknownFieldsType = reflect.TypeOf(UnknownFields(nil))
127 extensionFieldsType = reflect.TypeOf(ExtensionFields(nil))
128)
Damien Neilc37adef2019-04-01 13:49:56 -0700129
Damien Neil3eaddf02019-05-09 11:33:55 -0700130type structInfo struct {
Joe Tsai93fd9682019-07-06 13:02:14 -0700131 sizecacheOffset offset
Joe Tsai93fd9682019-07-06 13:02:14 -0700132 unknownOffset offset
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700133 extensionOffset offset
Joe Tsai93fd9682019-07-06 13:02:14 -0700134
Damien Neil3eaddf02019-05-09 11:33:55 -0700135 fieldsByNumber map[pref.FieldNumber]reflect.StructField
136 oneofsByName map[pref.Name]reflect.StructField
137 oneofWrappersByType map[reflect.Type]pref.FieldNumber
138 oneofWrappersByNumber map[pref.FieldNumber]reflect.Type
139}
140
Joe Tsai4fe96632019-05-22 05:12:36 -0400141func (mi *MessageInfo) makeStructInfo(t reflect.Type) structInfo {
Damien Neil3eaddf02019-05-09 11:33:55 -0700142 si := structInfo{
Joe Tsai93fd9682019-07-06 13:02:14 -0700143 sizecacheOffset: invalidOffset,
Joe Tsai93fd9682019-07-06 13:02:14 -0700144 unknownOffset: invalidOffset,
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700145 extensionOffset: invalidOffset,
Joe Tsai93fd9682019-07-06 13:02:14 -0700146
Damien Neil3eaddf02019-05-09 11:33:55 -0700147 fieldsByNumber: map[pref.FieldNumber]reflect.StructField{},
148 oneofsByName: map[pref.Name]reflect.StructField{},
149 oneofWrappersByType: map[reflect.Type]pref.FieldNumber{},
150 oneofWrappersByNumber: map[pref.FieldNumber]reflect.Type{},
151 }
Joe Tsai93fd9682019-07-06 13:02:14 -0700152
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700153 if f, _ := t.FieldByName("sizeCache"); f.Type == sizecacheType {
154 si.sizecacheOffset = offsetOf(f, mi.Exporter)
155 }
Joe Tsai93fd9682019-07-06 13:02:14 -0700156 if f, _ := t.FieldByName("XXX_sizecache"); f.Type == sizecacheType {
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700157 si.sizecacheOffset = offsetOf(f, mi.Exporter)
Joe Tsai93fd9682019-07-06 13:02:14 -0700158 }
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700159 if f, _ := t.FieldByName("unknownFields"); f.Type == unknownFieldsType {
160 si.unknownOffset = offsetOf(f, mi.Exporter)
Joe Tsai93fd9682019-07-06 13:02:14 -0700161 }
162 if f, _ := t.FieldByName("XXX_unrecognized"); f.Type == unknownFieldsType {
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700163 si.unknownOffset = offsetOf(f, mi.Exporter)
164 }
165 if f, _ := t.FieldByName("extensionFields"); f.Type == extensionFieldsType {
166 si.extensionOffset = offsetOf(f, mi.Exporter)
167 }
168 if f, _ := t.FieldByName("XXX_InternalExtensions"); f.Type == extensionFieldsType {
169 si.extensionOffset = offsetOf(f, mi.Exporter)
170 }
171 if f, _ := t.FieldByName("XXX_extensions"); f.Type == extensionFieldsType {
172 si.extensionOffset = offsetOf(f, mi.Exporter)
Joe Tsai93fd9682019-07-06 13:02:14 -0700173 }
174
175 // Generate a mapping of field numbers and names to Go struct field or type.
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700176fieldLoop:
177 for i := 0; i < t.NumField(); i++ {
178 f := t.Field(i)
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)
Damien Neil3eaddf02019-05-09 11:33:55 -0700182 si.fieldsByNumber[pref.FieldNumber(n)] = f
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700183 continue fieldLoop
184 }
185 }
186 if s := f.Tag.Get("protobuf_oneof"); len(s) > 0 {
Damien Neil3eaddf02019-05-09 11:33:55 -0700187 si.oneofsByName[pref.Name(s)] = f
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700188 continue fieldLoop
189 }
190 }
Joe Tsai93fd9682019-07-06 13:02:14 -0700191
192 // Derive a mapping of oneof wrappers to fields.
Joe Tsai09912272019-07-08 10:38:11 -0700193 oneofWrappers := mi.OneofWrappers
Joe Tsai2c870bb2018-10-17 11:46:52 -0700194 if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok {
Joe Tsaid7e97bc2018-11-26 12:57:27 -0800195 oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3].Interface().([]interface{})
196 }
197 if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok {
198 oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0].Interface().([]interface{})
199 }
200 for _, v := range oneofWrappers {
201 tf := reflect.TypeOf(v).Elem()
202 f := tf.Field(0)
203 for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
204 if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
205 n, _ := strconv.ParseUint(s, 10, 64)
Damien Neil3eaddf02019-05-09 11:33:55 -0700206 si.oneofWrappersByType[tf] = pref.FieldNumber(n)
207 si.oneofWrappersByNumber[pref.FieldNumber(n)] = tf
Joe Tsaid7e97bc2018-11-26 12:57:27 -0800208 break
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700209 }
210 }
211 }
Joe Tsai93fd9682019-07-06 13:02:14 -0700212
Damien Neil3eaddf02019-05-09 11:33:55 -0700213 return si
214}
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700215
Damien Neil3eaddf02019-05-09 11:33:55 -0700216// makeKnownFieldsFunc generates functions for operations that can be performed
217// on each protobuf message field. It takes in a reflect.Type representing the
218// Go struct and matches message fields with struct fields.
219//
220// This code assumes that the struct is well-formed and panics if there are
221// any discrepancies.
Joe Tsai4fe96632019-05-22 05:12:36 -0400222func (mi *MessageInfo) makeKnownFieldsFunc(si structInfo) {
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700223 mi.fields = map[pref.FieldNumber]*fieldInfo{}
Joe Tsai0fc49f82019-05-01 12:29:25 -0700224 for i := 0; i < mi.PBType.Descriptor().Fields().Len(); i++ {
225 fd := mi.PBType.Descriptor().Fields().Get(i)
Damien Neil3eaddf02019-05-09 11:33:55 -0700226 fs := si.fieldsByNumber[fd.Number()]
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700227 var fi fieldInfo
228 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700229 case fd.ContainingOneof() != nil:
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700230 fi = fieldInfoForOneof(fd, si.oneofsByName[fd.ContainingOneof().Name()], mi.Exporter, si.oneofWrappersByNumber[fd.Number()])
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700231 case fd.IsMap():
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700232 fi = fieldInfoForMap(fd, fs, mi.Exporter)
Joe Tsaiac31a352019-05-13 14:32:56 -0700233 case fd.IsList():
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700234 fi = fieldInfoForList(fd, fs, mi.Exporter)
Joe Tsaic6b75612018-09-13 14:24:37 -0700235 case fd.Kind() == pref.MessageKind || fd.Kind() == pref.GroupKind:
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700236 fi = fieldInfoForMessage(fd, fs, mi.Exporter)
Joe Tsaic6b75612018-09-13 14:24:37 -0700237 default:
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700238 fi = fieldInfoForScalar(fd, fs, mi.Exporter)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700239 }
240 mi.fields[fd.Number()] = &fi
241 }
Joe Tsai4ec39c72019-04-03 13:40:53 -0700242
243 mi.oneofs = map[pref.Name]*oneofInfo{}
Joe Tsai0fc49f82019-05-01 12:29:25 -0700244 for i := 0; i < mi.PBType.Descriptor().Oneofs().Len(); i++ {
245 od := mi.PBType.Descriptor().Oneofs().Get(i)
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700246 mi.oneofs[od.Name()] = makeOneofInfo(od, si.oneofsByName[od.Name()], mi.Exporter, si.oneofWrappersByType)
Joe Tsai4ec39c72019-04-03 13:40:53 -0700247 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700248}
Joe Tsaic6b75612018-09-13 14:24:37 -0700249
Joe Tsai93fd9682019-07-06 13:02:14 -0700250func (mi *MessageInfo) makeUnknownFieldsFunc(t reflect.Type, si structInfo) {
Joe Tsai378c1322019-04-25 23:48:08 -0700251 mi.getUnknown = func(pointer) pref.RawFields { return nil }
252 mi.setUnknown = func(pointer, pref.RawFields) { return }
Joe Tsai93fd9682019-07-06 13:02:14 -0700253 if si.unknownOffset.IsValid() {
Joe Tsai378c1322019-04-25 23:48:08 -0700254 mi.getUnknown = func(p pointer) pref.RawFields {
255 if p.IsNil() {
256 return nil
257 }
Joe Tsai93fd9682019-07-06 13:02:14 -0700258 rv := p.Apply(si.unknownOffset).AsValueOf(unknownFieldsType)
Joe Tsai378c1322019-04-25 23:48:08 -0700259 return pref.RawFields(*rv.Interface().(*[]byte))
260 }
261 mi.setUnknown = func(p pointer, b pref.RawFields) {
262 if p.IsNil() {
263 panic("invalid SetUnknown on nil Message")
264 }
Joe Tsai93fd9682019-07-06 13:02:14 -0700265 rv := p.Apply(si.unknownOffset).AsValueOf(unknownFieldsType)
Joe Tsai378c1322019-04-25 23:48:08 -0700266 *rv.Interface().(*[]byte) = []byte(b)
267 }
268 } else {
269 mi.getUnknown = func(pointer) pref.RawFields {
270 return nil
271 }
272 mi.setUnknown = func(p pointer, _ pref.RawFields) {
273 if p.IsNil() {
274 panic("invalid SetUnknown on nil Message")
275 }
276 }
Joe Tsaibe5348c2018-10-23 18:31:18 -0700277 }
278}
279
Joe Tsai93fd9682019-07-06 13:02:14 -0700280func (mi *MessageInfo) makeExtensionFieldsFunc(t reflect.Type, si structInfo) {
281 if si.extensionOffset.IsValid() {
Joe Tsai378c1322019-04-25 23:48:08 -0700282 mi.extensionMap = func(p pointer) *extensionMap {
Joe Tsaid8881392019-06-06 13:01:53 -0700283 if p.IsNil() {
284 return (*extensionMap)(nil)
285 }
Joe Tsai93fd9682019-07-06 13:02:14 -0700286 v := p.Apply(si.extensionOffset).AsValueOf(extensionFieldsType)
Joe Tsai378c1322019-04-25 23:48:08 -0700287 return (*extensionMap)(v.Interface().(*map[int32]ExtensionField))
288 }
289 } else {
290 mi.extensionMap = func(pointer) *extensionMap {
291 return (*extensionMap)(nil)
292 }
Joe Tsaibe5348c2018-10-23 18:31:18 -0700293 }
294}
295
Joe Tsai4fe96632019-05-22 05:12:36 -0400296func (mi *MessageInfo) MessageOf(p interface{}) pref.Message {
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700297 return (*messageReflectWrapper)(mi.dataTypeOf(p))
Joe Tsai08e00302018-11-26 22:32:06 -0800298}
299
Joe Tsai4fe96632019-05-22 05:12:36 -0400300func (mi *MessageInfo) Methods() *piface.Methods {
Damien Neilc37adef2019-04-01 13:49:56 -0700301 mi.init()
302 return &mi.methods
Damien Neil0d3e8cc2019-04-01 13:31:55 -0700303}
304
Joe Tsai4fe96632019-05-22 05:12:36 -0400305func (mi *MessageInfo) dataTypeOf(p interface{}) *messageDataType {
Damien Neil8012b442019-01-18 09:32:24 -0800306 // TODO: Remove this check? This API is primarily used by generated code,
307 // and should not violate this assumption. Leave this check in for now to
308 // provide some sanity checks during development. This can be removed if
309 // it proves to be detrimental to performance.
310 if reflect.TypeOf(p) != mi.GoType {
311 panic(fmt.Sprintf("type mismatch: got %T, want %v", p, mi.GoType))
312 }
Joe Tsai6cf80c42018-12-01 04:57:09 -0800313 return &messageDataType{pointerOfIface(p), mi}
Joe Tsaic6b75612018-09-13 14:24:37 -0700314}
315
316// messageDataType is a tuple of a pointer to the message data and
317// a pointer to the message type.
318//
Joe Tsai4fe96632019-05-22 05:12:36 -0400319// TODO: Unfortunately, we need to close over a pointer and MessageInfo,
Joe Tsaic6b75612018-09-13 14:24:37 -0700320// which incurs an an allocation. This pair is similar to a Go interface,
321// which is essentially a tuple of the same thing. We can make this efficient
322// with reflect.NamedOf (see https://golang.org/issues/16522).
323//
324// With that hypothetical API, we could dynamically create a new named type
Joe Tsai4fe96632019-05-22 05:12:36 -0400325// that has the same underlying type as MessageInfo.GoType, and
326// dynamically create methods that close over MessageInfo.
Joe Tsaic6b75612018-09-13 14:24:37 -0700327// Since the new type would have the same underlying type, we could directly
328// convert between pointers of those types, giving us an efficient way to swap
329// out the method set.
330//
331// Barring the ability to dynamically create named types, the workaround is
332// 1. either to accept the cost of an allocation for this wrapper struct or
333// 2. generate more types and methods, at the expense of binary size increase.
334type messageDataType struct {
335 p pointer
Joe Tsai4fe96632019-05-22 05:12:36 -0400336 mi *MessageInfo
Joe Tsaic6b75612018-09-13 14:24:37 -0700337}
338
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700339type messageReflectWrapper messageDataType
Joe Tsai08e00302018-11-26 22:32:06 -0800340
Joe Tsai0fc49f82019-05-01 12:29:25 -0700341func (m *messageReflectWrapper) Descriptor() pref.MessageDescriptor {
342 return m.mi.PBType.Descriptor()
343}
Joe Tsai0fc49f82019-05-01 12:29:25 -0700344func (m *messageReflectWrapper) New() pref.Message {
345 return m.mi.PBType.New()
346}
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700347func (m *messageReflectWrapper) Interface() pref.ProtoMessage {
Joe Tsai08e00302018-11-26 22:32:06 -0800348 if m, ok := m.ProtoUnwrap().(pref.ProtoMessage); ok {
349 return m
350 }
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700351 return (*messageIfaceWrapper)(m)
Joe Tsai08e00302018-11-26 22:32:06 -0800352}
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700353func (m *messageReflectWrapper) ProtoUnwrap() interface{} {
Damien Neil8012b442019-01-18 09:32:24 -0800354 return m.p.AsIfaceOf(m.mi.GoType.Elem())
Joe Tsai08e00302018-11-26 22:32:06 -0800355}
Joe Tsai08e00302018-11-26 22:32:06 -0800356
Joe Tsai378c1322019-04-25 23:48:08 -0700357func (m *messageReflectWrapper) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
358 m.mi.init()
359 for _, fi := range m.mi.fields {
360 if fi.has(m.p) {
361 if !f(fi.fieldDesc, fi.get(m.p)) {
362 return
363 }
364 }
365 }
366 m.mi.extensionMap(m.p).Range(f)
367}
368func (m *messageReflectWrapper) Has(fd pref.FieldDescriptor) bool {
369 if fi, xt := m.checkField(fd); fi != nil {
370 return fi.has(m.p)
371 } else {
372 return m.mi.extensionMap(m.p).Has(xt)
373 }
374}
375func (m *messageReflectWrapper) Clear(fd pref.FieldDescriptor) {
376 if fi, xt := m.checkField(fd); fi != nil {
377 fi.clear(m.p)
378 } else {
379 m.mi.extensionMap(m.p).Clear(xt)
380 }
381}
382func (m *messageReflectWrapper) Get(fd pref.FieldDescriptor) pref.Value {
383 if fi, xt := m.checkField(fd); fi != nil {
384 return fi.get(m.p)
385 } else {
386 return m.mi.extensionMap(m.p).Get(xt)
387 }
388}
389func (m *messageReflectWrapper) Set(fd pref.FieldDescriptor, v pref.Value) {
390 if fi, xt := m.checkField(fd); fi != nil {
391 fi.set(m.p, v)
392 } else {
393 m.mi.extensionMap(m.p).Set(xt, v)
394 }
395}
396func (m *messageReflectWrapper) Mutable(fd pref.FieldDescriptor) pref.Value {
397 if fi, xt := m.checkField(fd); fi != nil {
398 return fi.mutable(m.p)
399 } else {
400 return m.mi.extensionMap(m.p).Mutable(xt)
401 }
402}
403func (m *messageReflectWrapper) NewMessage(fd pref.FieldDescriptor) pref.Message {
404 if fi, xt := m.checkField(fd); fi != nil {
405 return fi.newMessage()
406 } else {
407 return xt.New().Message()
408 }
409}
410func (m *messageReflectWrapper) WhichOneof(od pref.OneofDescriptor) pref.FieldDescriptor {
411 m.mi.init()
412 if oi := m.mi.oneofs[od.Name()]; oi != nil && oi.oneofDesc == od {
413 return od.Fields().ByNumber(oi.which(m.p))
414 }
415 panic("invalid oneof descriptor")
416}
417func (m *messageReflectWrapper) GetUnknown() pref.RawFields {
418 m.mi.init()
419 return m.mi.getUnknown(m.p)
420}
421func (m *messageReflectWrapper) SetUnknown(b pref.RawFields) {
422 m.mi.init()
423 m.mi.setUnknown(m.p, b)
424}
425
426// checkField verifies that the provided field descriptor is valid.
427// Exactly one of the returned values is populated.
428func (m *messageReflectWrapper) checkField(fd pref.FieldDescriptor) (*fieldInfo, pref.ExtensionType) {
429 m.mi.init()
430 if fi := m.mi.fields[fd.Number()]; fi != nil {
431 if fi.fieldDesc != fd {
432 panic("mismatching field descriptor")
433 }
434 return fi, nil
435 }
436 if fd.IsExtension() {
437 if fd.ContainingMessage().FullName() != m.mi.PBType.FullName() {
438 // TODO: Should this be exact containing message descriptor match?
439 panic("mismatching containing message")
440 }
441 if !m.mi.PBType.ExtensionRanges().Has(fd.Number()) {
442 panic("invalid extension field")
443 }
444 return nil, fd.(pref.ExtensionType)
445 }
446 panic("invalid field descriptor")
447}
448
449type extensionMap map[int32]ExtensionField
450
Joe Tsai378c1322019-04-25 23:48:08 -0700451func (m *extensionMap) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
452 if m != nil {
453 for _, x := range *m {
454 xt := x.GetType()
455 if !f(xt, xt.ValueOf(x.GetValue())) {
456 return
457 }
458 }
459 }
460}
461func (m *extensionMap) Has(xt pref.ExtensionType) (ok bool) {
462 if m != nil {
463 _, ok = (*m)[int32(xt.Number())]
464 }
465 return ok
466}
467func (m *extensionMap) Clear(xt pref.ExtensionType) {
468 delete(*m, int32(xt.Number()))
469}
470func (m *extensionMap) Get(xt pref.ExtensionType) pref.Value {
471 if m != nil {
472 if x, ok := (*m)[int32(xt.Number())]; ok {
473 return xt.ValueOf(x.GetValue())
474 }
475 }
476 if !isComposite(xt) {
477 return defaultValueOf(xt)
478 }
479 return frozenValueOf(xt.New())
480}
481func (m *extensionMap) Set(xt pref.ExtensionType, v pref.Value) {
482 if *m == nil {
483 *m = make(map[int32]ExtensionField)
484 }
485 var x ExtensionField
486 x.SetType(xt)
487 x.SetEagerValue(xt.InterfaceOf(v))
488 (*m)[int32(xt.Number())] = x
489}
490func (m *extensionMap) Mutable(xt pref.ExtensionType) pref.Value {
491 if !isComposite(xt) {
492 panic("invalid Mutable on field with non-composite type")
493 }
494 if x, ok := (*m)[int32(xt.Number())]; ok {
495 return xt.ValueOf(x.GetValue())
496 }
497 v := xt.New()
498 m.Set(xt, v)
499 return v
500}
501
502func isComposite(fd pref.FieldDescriptor) bool {
503 return fd.Kind() == pref.MessageKind || fd.Kind() == pref.GroupKind || fd.IsList() || fd.IsMap()
504}
505
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700506var _ pvalue.Unwrapper = (*messageReflectWrapper)(nil)
507
508type messageIfaceWrapper messageDataType
509
510func (m *messageIfaceWrapper) ProtoReflect() pref.Message {
511 return (*messageReflectWrapper)(m)
512}
Damien Neil0d3e8cc2019-04-01 13:31:55 -0700513func (m *messageIfaceWrapper) XXX_Methods() *piface.Methods {
Damien Neilc37adef2019-04-01 13:49:56 -0700514 // TODO: Consider not recreating this on every call.
515 m.mi.init()
516 return &piface.Methods{
517 Flags: piface.MethodFlagDeterministicMarshal,
518 MarshalAppend: m.marshalAppend,
519 Size: m.size,
520 }
Damien Neil0d3e8cc2019-04-01 13:31:55 -0700521}
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700522func (m *messageIfaceWrapper) ProtoUnwrap() interface{} {
523 return m.p.AsIfaceOf(m.mi.GoType.Elem())
524}
Damien Neilc37adef2019-04-01 13:49:56 -0700525func (m *messageIfaceWrapper) marshalAppend(b []byte, _ pref.ProtoMessage, opts piface.MarshalOptions) ([]byte, error) {
526 return m.mi.marshalAppendPointer(b, m.p, newMarshalOptions(opts))
527}
528func (m *messageIfaceWrapper) size(msg pref.ProtoMessage) (size int) {
529 return m.mi.sizePointer(m.p, 0)
530}