blob: 12265111956eda2a60938bf6188953451a33497a [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"
Damien Neilc37adef2019-04-01 13:49:56 -070010 "sort"
Joe Tsaifa02f4e2018-09-12 16:20:37 -070011 "strconv"
12 "strings"
Joe Tsaic6b75612018-09-13 14:24:37 -070013 "sync"
Damien Neilc37adef2019-04-01 13:49:56 -070014 "sync/atomic"
Joe Tsaifa02f4e2018-09-12 16:20:37 -070015
Damien Neile89e6242019-05-13 23:55:40 -070016 pvalue "google.golang.org/protobuf/internal/value"
17 pref "google.golang.org/protobuf/reflect/protoreflect"
18 piface "google.golang.org/protobuf/runtime/protoiface"
Joe Tsaifa02f4e2018-09-12 16:20:37 -070019)
20
Joe Tsai4fe96632019-05-22 05:12:36 -040021// MessageInfo provides protobuf related functionality for a given Go type
22// that represents a message. A given instance of MessageInfo is tied to
Joe Tsaic6b75612018-09-13 14:24:37 -070023// exactly one Go type, which must be a pointer to a struct type.
Joe Tsai4fe96632019-05-22 05:12:36 -040024type MessageInfo struct {
Damien Neil8012b442019-01-18 09:32:24 -080025 // GoType is the underlying message Go type and must be populated.
Joe Tsaic6b75612018-09-13 14:24:37 -070026 // Once set, this field must never be mutated.
Damien Neil8012b442019-01-18 09:32:24 -080027 GoType reflect.Type // pointer to struct
28
29 // PBType is the underlying message descriptor type and must be populated.
30 // Once set, this field must never be mutated.
31 PBType pref.MessageType
Joe Tsaic6b75612018-09-13 14:24:37 -070032
Damien Neilc37adef2019-04-01 13:49:56 -070033 initMu sync.Mutex // protects all unexported fields
34 initDone uint32
Joe Tsaic6b75612018-09-13 14:24:37 -070035
Damien Neilc37adef2019-04-01 13:49:56 -070036 // Keep a separate slice of fields for efficient field encoding in tag order
37 // and because iterating over a slice is substantially faster than a map.
38 fields map[pref.FieldNumber]*fieldInfo
39 fieldsOrdered []*fieldInfo
40
Joe Tsai4ec39c72019-04-03 13:40:53 -070041 oneofs map[pref.Name]*oneofInfo
Joe Tsaibe5348c2018-10-23 18:31:18 -070042
Joe Tsai378c1322019-04-25 23:48:08 -070043 getUnknown func(pointer) pref.RawFields
44 setUnknown func(pointer, pref.RawFields)
45
46 extensionMap func(pointer) *extensionMap
47
Joe Tsai4a539f42019-06-17 12:30:25 -070048 methods piface.Methods
Damien Neilc37adef2019-04-01 13:49:56 -070049
Damien Neil5322bdb2019-04-09 15:57:05 -070050 needsInitCheck bool
Damien Neilc37adef2019-04-01 13:49:56 -070051 sizecacheOffset offset
Joe Tsai378c1322019-04-25 23:48:08 -070052 extensionOffset offset
Damien Neilc37adef2019-04-01 13:49:56 -070053 unknownOffset offset
54 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
58var prefMessageType = reflect.TypeOf((*pref.Message)(nil)).Elem()
59
Joe Tsai4fe96632019-05-22 05:12:36 -040060// getMessageInfo returns the MessageInfo (if any) for a type.
Damien Neilc37adef2019-04-01 13:49:56 -070061//
Joe Tsai4fe96632019-05-22 05:12:36 -040062// We find the MessageInfo by calling the ProtoReflect method on the type's
Damien Neilc37adef2019-04-01 13:49:56 -070063// zero value and looking at the returned type to see if it is a
Joe Tsai4fe96632019-05-22 05:12:36 -040064// messageReflectWrapper. Note that the MessageInfo may still be uninitialized
Damien Neilc37adef2019-04-01 13:49:56 -070065// at this point.
Joe Tsai4fe96632019-05-22 05:12:36 -040066func getMessageInfo(mt reflect.Type) (mi *MessageInfo, ok bool) {
Damien Neilc37adef2019-04-01 13:49:56 -070067 method, ok := mt.MethodByName("ProtoReflect")
68 if !ok {
69 return nil, false
70 }
71 if method.Type.NumIn() != 1 || method.Type.NumOut() != 1 || method.Type.Out(0) != prefMessageType {
72 return nil, false
73 }
74 ret := reflect.Zero(mt).Method(method.Index).Call(nil)
75 m, ok := ret[0].Elem().Interface().(*messageReflectWrapper)
76 if !ok {
77 return nil, ok
78 }
79 return m.mi, true
Joe Tsaifa02f4e2018-09-12 16:20:37 -070080}
81
Joe Tsai4fe96632019-05-22 05:12:36 -040082func (mi *MessageInfo) init() {
Damien Neilc37adef2019-04-01 13:49:56 -070083 // This function is called in the hot path. Inline the sync.Once
84 // logic, since allocating a closure for Once.Do is expensive.
85 // Keep init small to ensure that it can be inlined.
86 if atomic.LoadUint32(&mi.initDone) == 1 {
87 return
88 }
89 mi.initOnce()
90}
Joe Tsaic6b75612018-09-13 14:24:37 -070091
Joe Tsai4fe96632019-05-22 05:12:36 -040092func (mi *MessageInfo) initOnce() {
Damien Neilc37adef2019-04-01 13:49:56 -070093 mi.initMu.Lock()
94 defer mi.initMu.Unlock()
95 if mi.initDone == 1 {
96 return
97 }
98
99 t := mi.GoType
100 if t.Kind() != reflect.Ptr && t.Elem().Kind() != reflect.Struct {
101 panic(fmt.Sprintf("got %v, want *struct kind", t))
102 }
103
104 si := mi.makeStructInfo(t.Elem())
Damien Neil5322bdb2019-04-09 15:57:05 -0700105 mi.needsInitCheck = needsInitCheck(mi.PBType)
Damien Neilc37adef2019-04-01 13:49:56 -0700106 mi.makeKnownFieldsFunc(si)
107 mi.makeUnknownFieldsFunc(t.Elem())
108 mi.makeExtensionFieldsFunc(t.Elem())
109 mi.makeMethods(t.Elem())
110
111 atomic.StoreUint32(&mi.initDone, 1)
112}
113
Joe Tsai378c1322019-04-25 23:48:08 -0700114type (
115 SizeCache = int32
116 UnknownFields = []byte
117 ExtensionFields = map[int32]ExtensionField
118)
119
120var (
121 sizecacheType = reflect.TypeOf(SizeCache(0))
122 unknownFieldsType = reflect.TypeOf(UnknownFields(nil))
123 extensionFieldsType = reflect.TypeOf(ExtensionFields(nil))
124)
Damien Neilc37adef2019-04-01 13:49:56 -0700125
Joe Tsai4fe96632019-05-22 05:12:36 -0400126func (mi *MessageInfo) makeMethods(t reflect.Type) {
Damien Neilc37adef2019-04-01 13:49:56 -0700127 mi.sizecacheOffset = invalidOffset
128 if fx, _ := t.FieldByName("XXX_sizecache"); fx.Type == sizecacheType {
129 mi.sizecacheOffset = offsetOf(fx)
130 }
131 mi.unknownOffset = invalidOffset
Joe Tsai378c1322019-04-25 23:48:08 -0700132 if fx, _ := t.FieldByName("XXX_unrecognized"); fx.Type == unknownFieldsType {
Damien Neilc37adef2019-04-01 13:49:56 -0700133 mi.unknownOffset = offsetOf(fx)
134 }
Joe Tsai378c1322019-04-25 23:48:08 -0700135 mi.extensionOffset = invalidOffset
136 if fx, _ := t.FieldByName("XXX_InternalExtensions"); fx.Type == extensionFieldsType {
137 mi.extensionOffset = offsetOf(fx)
138 } else if fx, _ = t.FieldByName("XXX_extensions"); fx.Type == extensionFieldsType {
139 mi.extensionOffset = offsetOf(fx)
140 }
Damien Neilc37adef2019-04-01 13:49:56 -0700141 mi.methods.Flags = piface.MethodFlagDeterministicMarshal
142 mi.methods.MarshalAppend = mi.marshalAppend
143 mi.methods.Size = mi.size
Damien Neil5322bdb2019-04-09 15:57:05 -0700144 mi.methods.IsInitialized = mi.isInitialized
Joe Tsaic6b75612018-09-13 14:24:37 -0700145}
146
Damien Neil3eaddf02019-05-09 11:33:55 -0700147type structInfo struct {
148 fieldsByNumber map[pref.FieldNumber]reflect.StructField
149 oneofsByName map[pref.Name]reflect.StructField
150 oneofWrappersByType map[reflect.Type]pref.FieldNumber
151 oneofWrappersByNumber map[pref.FieldNumber]reflect.Type
152}
153
Joe Tsai4fe96632019-05-22 05:12:36 -0400154func (mi *MessageInfo) makeStructInfo(t reflect.Type) structInfo {
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700155 // Generate a mapping of field numbers and names to Go struct field or type.
Damien Neil3eaddf02019-05-09 11:33:55 -0700156 si := structInfo{
157 fieldsByNumber: map[pref.FieldNumber]reflect.StructField{},
158 oneofsByName: map[pref.Name]reflect.StructField{},
159 oneofWrappersByType: map[reflect.Type]pref.FieldNumber{},
160 oneofWrappersByNumber: map[pref.FieldNumber]reflect.Type{},
161 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700162fieldLoop:
163 for i := 0; i < t.NumField(); i++ {
164 f := t.Field(i)
165 for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
166 if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
167 n, _ := strconv.ParseUint(s, 10, 64)
Damien Neil3eaddf02019-05-09 11:33:55 -0700168 si.fieldsByNumber[pref.FieldNumber(n)] = f
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700169 continue fieldLoop
170 }
171 }
172 if s := f.Tag.Get("protobuf_oneof"); len(s) > 0 {
Damien Neil3eaddf02019-05-09 11:33:55 -0700173 si.oneofsByName[pref.Name(s)] = f
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700174 continue fieldLoop
175 }
176 }
Joe Tsaid7e97bc2018-11-26 12:57:27 -0800177 var oneofWrappers []interface{}
Joe Tsai2c870bb2018-10-17 11:46:52 -0700178 if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok {
Joe Tsaid7e97bc2018-11-26 12:57:27 -0800179 oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3].Interface().([]interface{})
180 }
181 if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok {
182 oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0].Interface().([]interface{})
183 }
184 for _, v := range oneofWrappers {
185 tf := reflect.TypeOf(v).Elem()
186 f := tf.Field(0)
187 for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
188 if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
189 n, _ := strconv.ParseUint(s, 10, 64)
Damien Neil3eaddf02019-05-09 11:33:55 -0700190 si.oneofWrappersByType[tf] = pref.FieldNumber(n)
191 si.oneofWrappersByNumber[pref.FieldNumber(n)] = tf
Joe Tsaid7e97bc2018-11-26 12:57:27 -0800192 break
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700193 }
194 }
195 }
Damien Neil3eaddf02019-05-09 11:33:55 -0700196 return si
197}
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700198
Damien Neil3eaddf02019-05-09 11:33:55 -0700199// makeKnownFieldsFunc generates functions for operations that can be performed
200// on each protobuf message field. It takes in a reflect.Type representing the
201// Go struct and matches message fields with struct fields.
202//
203// This code assumes that the struct is well-formed and panics if there are
204// any discrepancies.
Joe Tsai4fe96632019-05-22 05:12:36 -0400205func (mi *MessageInfo) makeKnownFieldsFunc(si structInfo) {
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700206 mi.fields = map[pref.FieldNumber]*fieldInfo{}
Damien Neilc37adef2019-04-01 13:49:56 -0700207 mi.fieldsOrdered = make([]*fieldInfo, 0, mi.PBType.Fields().Len())
Joe Tsai0fc49f82019-05-01 12:29:25 -0700208 for i := 0; i < mi.PBType.Descriptor().Fields().Len(); i++ {
209 fd := mi.PBType.Descriptor().Fields().Get(i)
Damien Neil3eaddf02019-05-09 11:33:55 -0700210 fs := si.fieldsByNumber[fd.Number()]
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700211 var fi fieldInfo
212 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700213 case fd.ContainingOneof() != nil:
214 fi = fieldInfoForOneof(fd, si.oneofsByName[fd.ContainingOneof().Name()], si.oneofWrappersByNumber[fd.Number()])
Damien Neilc37adef2019-04-01 13:49:56 -0700215 // There is one fieldInfo for each proto message field, but only one struct
216 // field for all message fields in a oneof. We install the encoder functions
217 // on the fieldInfo for the first field in the oneof.
218 //
219 // A slightly simpler approach would be to have each fieldInfo's encoder
220 // handle the case where that field is set, but this would require more
221 // checks against the current oneof type than a single map lookup.
222 if fd.ContainingOneof().Fields().Get(0).Name() == fd.Name() {
223 fi.funcs = makeOneofFieldCoder(si.oneofsByName[fd.ContainingOneof().Name()], fd.ContainingOneof(), si.fieldsByNumber, si.oneofWrappersByNumber)
224 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700225 case fd.IsMap():
226 fi = fieldInfoForMap(fd, fs)
Joe Tsaiac31a352019-05-13 14:32:56 -0700227 case fd.IsList():
Joe Tsai4b7aff62018-11-14 14:05:19 -0800228 fi = fieldInfoForList(fd, fs)
Joe Tsaic6b75612018-09-13 14:24:37 -0700229 case fd.Kind() == pref.MessageKind || fd.Kind() == pref.GroupKind:
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700230 fi = fieldInfoForMessage(fd, fs)
Joe Tsaic6b75612018-09-13 14:24:37 -0700231 default:
232 fi = fieldInfoForScalar(fd, fs)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700233 }
Damien Neilc37adef2019-04-01 13:49:56 -0700234 fi.num = fd.Number()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700235 mi.fields[fd.Number()] = &fi
Damien Neilc37adef2019-04-01 13:49:56 -0700236 mi.fieldsOrdered = append(mi.fieldsOrdered, &fi)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700237 }
Damien Neilc37adef2019-04-01 13:49:56 -0700238 sort.Slice(mi.fieldsOrdered, func(i, j int) bool {
239 return mi.fieldsOrdered[i].num < mi.fieldsOrdered[j].num
240 })
Joe Tsai4ec39c72019-04-03 13:40:53 -0700241
242 mi.oneofs = map[pref.Name]*oneofInfo{}
Joe Tsai0fc49f82019-05-01 12:29:25 -0700243 for i := 0; i < mi.PBType.Descriptor().Oneofs().Len(); i++ {
244 od := mi.PBType.Descriptor().Oneofs().Get(i)
Damien Neil3eaddf02019-05-09 11:33:55 -0700245 mi.oneofs[od.Name()] = makeOneofInfo(od, si.oneofsByName[od.Name()], si.oneofWrappersByType)
Joe Tsai4ec39c72019-04-03 13:40:53 -0700246 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700247}
Joe Tsaic6b75612018-09-13 14:24:37 -0700248
Joe Tsai4fe96632019-05-22 05:12:36 -0400249func (mi *MessageInfo) makeUnknownFieldsFunc(t reflect.Type) {
Joe Tsai378c1322019-04-25 23:48:08 -0700250 mi.getUnknown = func(pointer) pref.RawFields { return nil }
251 mi.setUnknown = func(pointer, pref.RawFields) { return }
252 fu, _ := t.FieldByName("XXX_unrecognized")
253 if fu.Type == unknownFieldsType {
254 fieldOffset := offsetOf(fu)
255 mi.getUnknown = func(p pointer) pref.RawFields {
256 if p.IsNil() {
257 return nil
258 }
259 rv := p.Apply(fieldOffset).AsValueOf(unknownFieldsType)
260 return pref.RawFields(*rv.Interface().(*[]byte))
261 }
262 mi.setUnknown = func(p pointer, b pref.RawFields) {
263 if p.IsNil() {
264 panic("invalid SetUnknown on nil Message")
265 }
266 rv := p.Apply(fieldOffset).AsValueOf(unknownFieldsType)
267 *rv.Interface().(*[]byte) = []byte(b)
268 }
269 } else {
270 mi.getUnknown = func(pointer) pref.RawFields {
271 return nil
272 }
273 mi.setUnknown = func(p pointer, _ pref.RawFields) {
274 if p.IsNil() {
275 panic("invalid SetUnknown on nil Message")
276 }
277 }
Joe Tsaibe5348c2018-10-23 18:31:18 -0700278 }
279}
280
Joe Tsai4fe96632019-05-22 05:12:36 -0400281func (mi *MessageInfo) makeExtensionFieldsFunc(t reflect.Type) {
Joe Tsai378c1322019-04-25 23:48:08 -0700282 fx, _ := t.FieldByName("XXX_extensions")
283 if fx.Type != extensionFieldsType {
284 fx, _ = t.FieldByName("XXX_InternalExtensions")
Joe Tsaif0c01e42018-11-06 13:05:20 -0800285 }
Joe Tsai378c1322019-04-25 23:48:08 -0700286 if fx.Type == extensionFieldsType {
287 fieldOffset := offsetOf(fx)
288 mi.extensionMap = func(p pointer) *extensionMap {
Joe Tsaid8881392019-06-06 13:01:53 -0700289 if p.IsNil() {
290 return (*extensionMap)(nil)
291 }
Joe Tsai378c1322019-04-25 23:48:08 -0700292 v := p.Apply(fieldOffset).AsValueOf(extensionFieldsType)
293 return (*extensionMap)(v.Interface().(*map[int32]ExtensionField))
294 }
295 } else {
296 mi.extensionMap = func(pointer) *extensionMap {
297 return (*extensionMap)(nil)
298 }
Joe Tsaibe5348c2018-10-23 18:31:18 -0700299 }
300}
301
Joe Tsai4fe96632019-05-22 05:12:36 -0400302func (mi *MessageInfo) MessageOf(p interface{}) pref.Message {
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700303 return (*messageReflectWrapper)(mi.dataTypeOf(p))
Joe Tsai08e00302018-11-26 22:32:06 -0800304}
305
Joe Tsai4fe96632019-05-22 05:12:36 -0400306func (mi *MessageInfo) Methods() *piface.Methods {
Damien Neilc37adef2019-04-01 13:49:56 -0700307 mi.init()
308 return &mi.methods
Damien Neil0d3e8cc2019-04-01 13:31:55 -0700309}
310
Joe Tsai4fe96632019-05-22 05:12:36 -0400311func (mi *MessageInfo) dataTypeOf(p interface{}) *messageDataType {
Damien Neil8012b442019-01-18 09:32:24 -0800312 // TODO: Remove this check? This API is primarily used by generated code,
313 // and should not violate this assumption. Leave this check in for now to
314 // provide some sanity checks during development. This can be removed if
315 // it proves to be detrimental to performance.
316 if reflect.TypeOf(p) != mi.GoType {
317 panic(fmt.Sprintf("type mismatch: got %T, want %v", p, mi.GoType))
318 }
Joe Tsai6cf80c42018-12-01 04:57:09 -0800319 return &messageDataType{pointerOfIface(p), mi}
Joe Tsaic6b75612018-09-13 14:24:37 -0700320}
321
322// messageDataType is a tuple of a pointer to the message data and
323// a pointer to the message type.
324//
Joe Tsai4fe96632019-05-22 05:12:36 -0400325// TODO: Unfortunately, we need to close over a pointer and MessageInfo,
Joe Tsaic6b75612018-09-13 14:24:37 -0700326// which incurs an an allocation. This pair is similar to a Go interface,
327// which is essentially a tuple of the same thing. We can make this efficient
328// with reflect.NamedOf (see https://golang.org/issues/16522).
329//
330// With that hypothetical API, we could dynamically create a new named type
Joe Tsai4fe96632019-05-22 05:12:36 -0400331// that has the same underlying type as MessageInfo.GoType, and
332// dynamically create methods that close over MessageInfo.
Joe Tsaic6b75612018-09-13 14:24:37 -0700333// Since the new type would have the same underlying type, we could directly
334// convert between pointers of those types, giving us an efficient way to swap
335// out the method set.
336//
337// Barring the ability to dynamically create named types, the workaround is
338// 1. either to accept the cost of an allocation for this wrapper struct or
339// 2. generate more types and methods, at the expense of binary size increase.
340type messageDataType struct {
341 p pointer
Joe Tsai4fe96632019-05-22 05:12:36 -0400342 mi *MessageInfo
Joe Tsaic6b75612018-09-13 14:24:37 -0700343}
344
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700345type messageReflectWrapper messageDataType
Joe Tsai08e00302018-11-26 22:32:06 -0800346
Joe Tsai0fc49f82019-05-01 12:29:25 -0700347func (m *messageReflectWrapper) Descriptor() pref.MessageDescriptor {
348 return m.mi.PBType.Descriptor()
349}
Joe Tsai0fc49f82019-05-01 12:29:25 -0700350func (m *messageReflectWrapper) New() pref.Message {
351 return m.mi.PBType.New()
352}
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700353func (m *messageReflectWrapper) Interface() pref.ProtoMessage {
Joe Tsai08e00302018-11-26 22:32:06 -0800354 if m, ok := m.ProtoUnwrap().(pref.ProtoMessage); ok {
355 return m
356 }
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700357 return (*messageIfaceWrapper)(m)
Joe Tsai08e00302018-11-26 22:32:06 -0800358}
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700359func (m *messageReflectWrapper) ProtoUnwrap() interface{} {
Damien Neil8012b442019-01-18 09:32:24 -0800360 return m.p.AsIfaceOf(m.mi.GoType.Elem())
Joe Tsai08e00302018-11-26 22:32:06 -0800361}
Joe Tsai08e00302018-11-26 22:32:06 -0800362
Joe Tsai378c1322019-04-25 23:48:08 -0700363func (m *messageReflectWrapper) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
364 m.mi.init()
365 for _, fi := range m.mi.fields {
366 if fi.has(m.p) {
367 if !f(fi.fieldDesc, fi.get(m.p)) {
368 return
369 }
370 }
371 }
372 m.mi.extensionMap(m.p).Range(f)
373}
374func (m *messageReflectWrapper) Has(fd pref.FieldDescriptor) bool {
375 if fi, xt := m.checkField(fd); fi != nil {
376 return fi.has(m.p)
377 } else {
378 return m.mi.extensionMap(m.p).Has(xt)
379 }
380}
381func (m *messageReflectWrapper) Clear(fd pref.FieldDescriptor) {
382 if fi, xt := m.checkField(fd); fi != nil {
383 fi.clear(m.p)
384 } else {
385 m.mi.extensionMap(m.p).Clear(xt)
386 }
387}
388func (m *messageReflectWrapper) Get(fd pref.FieldDescriptor) pref.Value {
389 if fi, xt := m.checkField(fd); fi != nil {
390 return fi.get(m.p)
391 } else {
392 return m.mi.extensionMap(m.p).Get(xt)
393 }
394}
395func (m *messageReflectWrapper) Set(fd pref.FieldDescriptor, v pref.Value) {
396 if fi, xt := m.checkField(fd); fi != nil {
397 fi.set(m.p, v)
398 } else {
399 m.mi.extensionMap(m.p).Set(xt, v)
400 }
401}
402func (m *messageReflectWrapper) Mutable(fd pref.FieldDescriptor) pref.Value {
403 if fi, xt := m.checkField(fd); fi != nil {
404 return fi.mutable(m.p)
405 } else {
406 return m.mi.extensionMap(m.p).Mutable(xt)
407 }
408}
409func (m *messageReflectWrapper) NewMessage(fd pref.FieldDescriptor) pref.Message {
410 if fi, xt := m.checkField(fd); fi != nil {
411 return fi.newMessage()
412 } else {
413 return xt.New().Message()
414 }
415}
416func (m *messageReflectWrapper) WhichOneof(od pref.OneofDescriptor) pref.FieldDescriptor {
417 m.mi.init()
418 if oi := m.mi.oneofs[od.Name()]; oi != nil && oi.oneofDesc == od {
419 return od.Fields().ByNumber(oi.which(m.p))
420 }
421 panic("invalid oneof descriptor")
422}
423func (m *messageReflectWrapper) GetUnknown() pref.RawFields {
424 m.mi.init()
425 return m.mi.getUnknown(m.p)
426}
427func (m *messageReflectWrapper) SetUnknown(b pref.RawFields) {
428 m.mi.init()
429 m.mi.setUnknown(m.p, b)
430}
431
432// checkField verifies that the provided field descriptor is valid.
433// Exactly one of the returned values is populated.
434func (m *messageReflectWrapper) checkField(fd pref.FieldDescriptor) (*fieldInfo, pref.ExtensionType) {
435 m.mi.init()
436 if fi := m.mi.fields[fd.Number()]; fi != nil {
437 if fi.fieldDesc != fd {
438 panic("mismatching field descriptor")
439 }
440 return fi, nil
441 }
442 if fd.IsExtension() {
443 if fd.ContainingMessage().FullName() != m.mi.PBType.FullName() {
444 // TODO: Should this be exact containing message descriptor match?
445 panic("mismatching containing message")
446 }
447 if !m.mi.PBType.ExtensionRanges().Has(fd.Number()) {
448 panic("invalid extension field")
449 }
450 return nil, fd.(pref.ExtensionType)
451 }
452 panic("invalid field descriptor")
453}
454
455type extensionMap map[int32]ExtensionField
456
Joe Tsai378c1322019-04-25 23:48:08 -0700457func (m *extensionMap) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
458 if m != nil {
459 for _, x := range *m {
460 xt := x.GetType()
461 if !f(xt, xt.ValueOf(x.GetValue())) {
462 return
463 }
464 }
465 }
466}
467func (m *extensionMap) Has(xt pref.ExtensionType) (ok bool) {
468 if m != nil {
469 _, ok = (*m)[int32(xt.Number())]
470 }
471 return ok
472}
473func (m *extensionMap) Clear(xt pref.ExtensionType) {
474 delete(*m, int32(xt.Number()))
475}
476func (m *extensionMap) Get(xt pref.ExtensionType) pref.Value {
477 if m != nil {
478 if x, ok := (*m)[int32(xt.Number())]; ok {
479 return xt.ValueOf(x.GetValue())
480 }
481 }
482 if !isComposite(xt) {
483 return defaultValueOf(xt)
484 }
485 return frozenValueOf(xt.New())
486}
487func (m *extensionMap) Set(xt pref.ExtensionType, v pref.Value) {
488 if *m == nil {
489 *m = make(map[int32]ExtensionField)
490 }
491 var x ExtensionField
492 x.SetType(xt)
493 x.SetEagerValue(xt.InterfaceOf(v))
494 (*m)[int32(xt.Number())] = x
495}
496func (m *extensionMap) Mutable(xt pref.ExtensionType) pref.Value {
497 if !isComposite(xt) {
498 panic("invalid Mutable on field with non-composite type")
499 }
500 if x, ok := (*m)[int32(xt.Number())]; ok {
501 return xt.ValueOf(x.GetValue())
502 }
503 v := xt.New()
504 m.Set(xt, v)
505 return v
506}
507
508func isComposite(fd pref.FieldDescriptor) bool {
509 return fd.Kind() == pref.MessageKind || fd.Kind() == pref.GroupKind || fd.IsList() || fd.IsMap()
510}
511
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700512var _ pvalue.Unwrapper = (*messageReflectWrapper)(nil)
513
514type messageIfaceWrapper messageDataType
515
516func (m *messageIfaceWrapper) ProtoReflect() pref.Message {
517 return (*messageReflectWrapper)(m)
518}
Damien Neil0d3e8cc2019-04-01 13:31:55 -0700519func (m *messageIfaceWrapper) XXX_Methods() *piface.Methods {
Damien Neilc37adef2019-04-01 13:49:56 -0700520 // TODO: Consider not recreating this on every call.
521 m.mi.init()
522 return &piface.Methods{
523 Flags: piface.MethodFlagDeterministicMarshal,
524 MarshalAppend: m.marshalAppend,
525 Size: m.size,
526 }
Damien Neil0d3e8cc2019-04-01 13:31:55 -0700527}
Joe Tsai22b1ebd2019-03-11 13:45:14 -0700528func (m *messageIfaceWrapper) ProtoUnwrap() interface{} {
529 return m.p.AsIfaceOf(m.mi.GoType.Elem())
530}
Damien Neilc37adef2019-04-01 13:49:56 -0700531func (m *messageIfaceWrapper) marshalAppend(b []byte, _ pref.ProtoMessage, opts piface.MarshalOptions) ([]byte, error) {
532 return m.mi.marshalAppendPointer(b, m.p, newMarshalOptions(opts))
533}
534func (m *messageIfaceWrapper) size(msg pref.ProtoMessage) (size int) {
535 return m.mi.sizePointer(m.p, 0)
536}