blob: 3eb2b1390fec5ba81cdd21e520b7a083b3b83919 [file] [log] [blame]
Joe Tsai82760ce2019-06-20 03:09:57 -07001// Copyright 2019 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 (
8 "fmt"
9 "reflect"
10
11 "google.golang.org/protobuf/internal/pragma"
Joe Tsai82760ce2019-06-20 03:09:57 -070012 pref "google.golang.org/protobuf/reflect/protoreflect"
Joe Tsai82760ce2019-06-20 03:09:57 -070013)
14
Joe Tsai0484b1a2019-08-13 15:36:08 -070015type reflectMessageInfo struct {
16 fields map[pref.FieldNumber]*fieldInfo
17 oneofs map[pref.Name]*oneofInfo
18
Joe Tsai9d637ca2019-09-18 18:08:52 -070019 // denseFields is a subset of fields where:
20 // 0 < fieldDesc.Number() < len(denseFields)
21 // It provides faster access to the fieldInfo, but may be incomplete.
22 denseFields []*fieldInfo
23
24 // rangeInfos is a list of all fields (not belonging to a oneof) and oneofs.
25 rangeInfos []interface{} // either *fieldInfo or *oneofInfo
26
Joe Tsai0484b1a2019-08-13 15:36:08 -070027 getUnknown func(pointer) pref.RawFields
28 setUnknown func(pointer, pref.RawFields)
29 extensionMap func(pointer) *extensionMap
30
31 nilMessage atomicNilMessage
32}
33
34// makeReflectFuncs generates the set of functions to support reflection.
35func (mi *MessageInfo) makeReflectFuncs(t reflect.Type, si structInfo) {
36 mi.makeKnownFieldsFunc(si)
37 mi.makeUnknownFieldsFunc(t, si)
38 mi.makeExtensionFieldsFunc(t, si)
39}
40
41// makeKnownFieldsFunc generates functions for operations that can be performed
42// on each protobuf message field. It takes in a reflect.Type representing the
43// Go struct and matches message fields with struct fields.
44//
45// This code assumes that the struct is well-formed and panics if there are
46// any discrepancies.
47func (mi *MessageInfo) makeKnownFieldsFunc(si structInfo) {
48 mi.fields = map[pref.FieldNumber]*fieldInfo{}
49 md := mi.Desc
Joe Tsai9d637ca2019-09-18 18:08:52 -070050 fds := md.Fields()
51 for i := 0; i < fds.Len(); i++ {
52 fd := fds.Get(i)
Joe Tsai0484b1a2019-08-13 15:36:08 -070053 fs := si.fieldsByNumber[fd.Number()]
54 var fi fieldInfo
55 switch {
Joe Tsai387873d2020-04-28 14:44:38 -070056 case fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic():
Joe Tsai0484b1a2019-08-13 15:36:08 -070057 fi = fieldInfoForOneof(fd, si.oneofsByName[fd.ContainingOneof().Name()], mi.Exporter, si.oneofWrappersByNumber[fd.Number()])
58 case fd.IsMap():
59 fi = fieldInfoForMap(fd, fs, mi.Exporter)
60 case fd.IsList():
61 fi = fieldInfoForList(fd, fs, mi.Exporter)
62 case fd.IsWeak():
63 fi = fieldInfoForWeakMessage(fd, si.weakOffset)
64 case fd.Kind() == pref.MessageKind || fd.Kind() == pref.GroupKind:
65 fi = fieldInfoForMessage(fd, fs, mi.Exporter)
66 default:
67 fi = fieldInfoForScalar(fd, fs, mi.Exporter)
68 }
69 mi.fields[fd.Number()] = &fi
70 }
71
72 mi.oneofs = map[pref.Name]*oneofInfo{}
73 for i := 0; i < md.Oneofs().Len(); i++ {
74 od := md.Oneofs().Get(i)
Joe Tsai387873d2020-04-28 14:44:38 -070075 mi.oneofs[od.Name()] = makeOneofInfo(od, si, mi.Exporter)
Joe Tsai0484b1a2019-08-13 15:36:08 -070076 }
Joe Tsai9d637ca2019-09-18 18:08:52 -070077
78 mi.denseFields = make([]*fieldInfo, fds.Len()*2)
79 for i := 0; i < fds.Len(); i++ {
80 if fd := fds.Get(i); int(fd.Number()) < len(mi.denseFields) {
81 mi.denseFields[fd.Number()] = mi.fields[fd.Number()]
82 }
83 }
84
85 for i := 0; i < fds.Len(); {
86 fd := fds.Get(i)
Joe Tsai387873d2020-04-28 14:44:38 -070087 if od := fd.ContainingOneof(); od != nil && !od.IsSynthetic() {
Joe Tsai9d637ca2019-09-18 18:08:52 -070088 mi.rangeInfos = append(mi.rangeInfos, mi.oneofs[od.Name()])
89 i += od.Fields().Len()
90 } else {
91 mi.rangeInfos = append(mi.rangeInfos, mi.fields[fd.Number()])
92 i++
93 }
94 }
Joe Tsai0484b1a2019-08-13 15:36:08 -070095}
96
97func (mi *MessageInfo) makeUnknownFieldsFunc(t reflect.Type, si structInfo) {
98 mi.getUnknown = func(pointer) pref.RawFields { return nil }
99 mi.setUnknown = func(pointer, pref.RawFields) { return }
100 if si.unknownOffset.IsValid() {
101 mi.getUnknown = func(p pointer) pref.RawFields {
102 if p.IsNil() {
103 return nil
104 }
105 rv := p.Apply(si.unknownOffset).AsValueOf(unknownFieldsType)
106 return pref.RawFields(*rv.Interface().(*[]byte))
107 }
108 mi.setUnknown = func(p pointer, b pref.RawFields) {
109 if p.IsNil() {
110 panic("invalid SetUnknown on nil Message")
111 }
112 rv := p.Apply(si.unknownOffset).AsValueOf(unknownFieldsType)
113 *rv.Interface().(*[]byte) = []byte(b)
114 }
115 } else {
116 mi.getUnknown = func(pointer) pref.RawFields {
117 return nil
118 }
119 mi.setUnknown = func(p pointer, _ pref.RawFields) {
120 if p.IsNil() {
121 panic("invalid SetUnknown on nil Message")
122 }
123 }
124 }
125}
126
127func (mi *MessageInfo) makeExtensionFieldsFunc(t reflect.Type, si structInfo) {
128 if si.extensionOffset.IsValid() {
129 mi.extensionMap = func(p pointer) *extensionMap {
130 if p.IsNil() {
131 return (*extensionMap)(nil)
132 }
133 v := p.Apply(si.extensionOffset).AsValueOf(extensionFieldsType)
134 return (*extensionMap)(v.Interface().(*map[int32]ExtensionField))
135 }
136 } else {
137 mi.extensionMap = func(pointer) *extensionMap {
138 return (*extensionMap)(nil)
139 }
140 }
141}
142
143type extensionMap map[int32]ExtensionField
144
145func (m *extensionMap) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
146 if m != nil {
147 for _, x := range *m {
Damien Neila0a54b82019-11-01 15:18:36 -0700148 xd := x.Type().TypeDescriptor()
149 v := x.Value()
150 if xd.IsList() && v.List().Len() == 0 {
151 continue
152 }
153 if !f(xd, v) {
Joe Tsai0484b1a2019-08-13 15:36:08 -0700154 return
155 }
156 }
157 }
158}
159func (m *extensionMap) Has(xt pref.ExtensionType) (ok bool) {
Damien Neila0a54b82019-11-01 15:18:36 -0700160 if m == nil {
161 return false
Joe Tsai0484b1a2019-08-13 15:36:08 -0700162 }
Damien Neila0a54b82019-11-01 15:18:36 -0700163 xd := xt.TypeDescriptor()
164 x, ok := (*m)[int32(xd.Number())]
165 if !ok {
166 return false
167 }
168 switch {
169 case xd.IsList():
170 return x.Value().List().Len() > 0
171 case xd.IsMap():
172 return x.Value().Map().Len() > 0
Joe Tsaib57aae92020-04-22 13:49:10 -0700173 case xd.Message() != nil:
174 return x.Value().Message().IsValid()
Damien Neila0a54b82019-11-01 15:18:36 -0700175 }
176 return true
Joe Tsai0484b1a2019-08-13 15:36:08 -0700177}
178func (m *extensionMap) Clear(xt pref.ExtensionType) {
Damien Neil79bfdbe2019-08-28 11:08:22 -0700179 delete(*m, int32(xt.TypeDescriptor().Number()))
Joe Tsai0484b1a2019-08-13 15:36:08 -0700180}
181func (m *extensionMap) Get(xt pref.ExtensionType) pref.Value {
Damien Neil79bfdbe2019-08-28 11:08:22 -0700182 xd := xt.TypeDescriptor()
Joe Tsai0484b1a2019-08-13 15:36:08 -0700183 if m != nil {
184 if x, ok := (*m)[int32(xd.Number())]; ok {
Damien Neil68b81c32019-08-22 11:41:32 -0700185 return x.Value()
Joe Tsai0484b1a2019-08-13 15:36:08 -0700186 }
187 }
188 return xt.Zero()
189}
190func (m *extensionMap) Set(xt pref.ExtensionType, v pref.Value) {
Joe Tsaib57aae92020-04-22 13:49:10 -0700191 xd := xt.TypeDescriptor()
192 isValid := true
193 switch {
194 case !xt.IsValidValue(v):
195 isValid = false
196 case xd.IsList():
197 isValid = v.List().IsValid()
198 case xd.IsMap():
199 isValid = v.Map().IsValid()
200 case xd.Message() != nil:
201 isValid = v.Message().IsValid()
202 }
203 if !isValid {
Joe Tsai09217f02019-09-06 16:57:46 -0700204 panic(fmt.Sprintf("%v: assigning invalid value", xt.TypeDescriptor().FullName()))
Damien Neil68b81c32019-08-22 11:41:32 -0700205 }
Joe Tsaib57aae92020-04-22 13:49:10 -0700206
Joe Tsai0484b1a2019-08-13 15:36:08 -0700207 if *m == nil {
208 *m = make(map[int32]ExtensionField)
209 }
210 var x ExtensionField
Damien Neil68b81c32019-08-22 11:41:32 -0700211 x.Set(xt, v)
Joe Tsaib57aae92020-04-22 13:49:10 -0700212 (*m)[int32(xd.Number())] = x
Joe Tsai0484b1a2019-08-13 15:36:08 -0700213}
214func (m *extensionMap) Mutable(xt pref.ExtensionType) pref.Value {
Damien Neil79bfdbe2019-08-28 11:08:22 -0700215 xd := xt.TypeDescriptor()
Joe Tsai0484b1a2019-08-13 15:36:08 -0700216 if xd.Kind() != pref.MessageKind && xd.Kind() != pref.GroupKind && !xd.IsList() && !xd.IsMap() {
217 panic("invalid Mutable on field with non-composite type")
218 }
219 if x, ok := (*m)[int32(xd.Number())]; ok {
Damien Neil68b81c32019-08-22 11:41:32 -0700220 return x.Value()
Joe Tsai0484b1a2019-08-13 15:36:08 -0700221 }
222 v := xt.New()
223 m.Set(xt, v)
224 return v
225}
226
Joe Tsai82760ce2019-06-20 03:09:57 -0700227// MessageState is a data structure that is nested as the first field in a
228// concrete message. It provides a way to implement the ProtoReflect method
229// in an allocation-free way without needing to have a shadow Go type generated
230// for every message type. This technique only works using unsafe.
231//
232//
233// Example generated code:
234//
235// type M struct {
236// state protoimpl.MessageState
237//
238// Field1 int32
239// Field2 string
240// Field3 *BarMessage
241// ...
242// }
243//
244// func (m *M) ProtoReflect() protoreflect.Message {
245// mi := &file_fizz_buzz_proto_msgInfos[5]
246// if protoimpl.UnsafeEnabled && m != nil {
247// ms := protoimpl.X.MessageStateOf(Pointer(m))
248// if ms.LoadMessageInfo() == nil {
249// ms.StoreMessageInfo(mi)
250// }
251// return ms
252// }
253// return mi.MessageOf(m)
254// }
255//
256// The MessageState type holds a *MessageInfo, which must be atomically set to
257// the message info associated with a given message instance.
258// By unsafely converting a *M into a *MessageState, the MessageState object
259// has access to all the information needed to implement protobuf reflection.
260// It has access to the message info as its first field, and a pointer to the
261// MessageState is identical to a pointer to the concrete message value.
262//
263//
264// Requirements:
265// • The type M must implement protoreflect.ProtoMessage.
266// • The address of m must not be nil.
267// • The address of m and the address of m.state must be equal,
268// even though they are different Go types.
269type MessageState struct {
270 pragma.NoUnkeyedLiterals
271 pragma.DoNotCompare
272 pragma.DoNotCopy
273
Damien Neil075e0742020-02-27 12:33:08 -0800274 atomicMessageInfo *MessageInfo
Joe Tsai82760ce2019-06-20 03:09:57 -0700275}
276
277type messageState MessageState
278
279var (
Damien Neil954bd922019-07-17 16:52:10 -0700280 _ pref.Message = (*messageState)(nil)
Joe Tsaifd528ff2019-09-03 16:30:39 -0700281 _ unwrapper = (*messageState)(nil)
Joe Tsai82760ce2019-06-20 03:09:57 -0700282)
283
284// messageDataType is a tuple of a pointer to the message data and
285// a pointer to the message type. It is a generalized way of providing a
286// reflective view over a message instance. The disadvantage of this approach
287// is the need to allocate this tuple of 16B.
288type messageDataType struct {
289 p pointer
290 mi *MessageInfo
291}
292
293type (
Joe Tsai82760ce2019-06-20 03:09:57 -0700294 messageReflectWrapper messageDataType
Joe Tsai0f81b382019-07-10 23:14:31 -0700295 messageIfaceWrapper messageDataType
Joe Tsai82760ce2019-06-20 03:09:57 -0700296)
297
298var (
299 _ pref.Message = (*messageReflectWrapper)(nil)
Joe Tsaifd528ff2019-09-03 16:30:39 -0700300 _ unwrapper = (*messageReflectWrapper)(nil)
Joe Tsai82760ce2019-06-20 03:09:57 -0700301 _ pref.ProtoMessage = (*messageIfaceWrapper)(nil)
Joe Tsaifd528ff2019-09-03 16:30:39 -0700302 _ unwrapper = (*messageIfaceWrapper)(nil)
Joe Tsai82760ce2019-06-20 03:09:57 -0700303)
304
305// MessageOf returns a reflective view over a message. The input must be a
306// pointer to a named Go struct. If the provided type has a ProtoReflect method,
307// it must be implemented by calling this method.
308func (mi *MessageInfo) MessageOf(m interface{}) pref.Message {
309 // TODO: Switch the input to be an opaque Pointer.
Damien Neil16163b42019-08-06 15:43:25 -0700310 if reflect.TypeOf(m) != mi.GoReflectType {
311 panic(fmt.Sprintf("type mismatch: got %T, want %v", m, mi.GoReflectType))
Joe Tsai82760ce2019-06-20 03:09:57 -0700312 }
313 p := pointerOfIface(m)
314 if p.IsNil() {
315 return mi.nilMessage.Init(mi)
316 }
317 return &messageReflectWrapper{p, mi}
318}
319
Joe Tsai2aea6142019-07-31 12:27:30 -0700320func (m *messageReflectWrapper) pointer() pointer { return m.p }
321func (m *messageReflectWrapper) messageInfo() *MessageInfo { return m.mi }
Joe Tsai82760ce2019-06-20 03:09:57 -0700322
323func (m *messageIfaceWrapper) ProtoReflect() pref.Message {
324 return (*messageReflectWrapper)(m)
325}
Joe Tsaifd528ff2019-09-03 16:30:39 -0700326func (m *messageIfaceWrapper) protoUnwrap() interface{} {
Damien Neil16163b42019-08-06 15:43:25 -0700327 return m.p.AsIfaceOf(m.mi.GoReflectType.Elem())
Joe Tsai82760ce2019-06-20 03:09:57 -0700328}
Joe Tsai82760ce2019-06-20 03:09:57 -0700329
Joe Tsai82760ce2019-06-20 03:09:57 -0700330// checkField verifies that the provided field descriptor is valid.
331// Exactly one of the returned values is populated.
332func (mi *MessageInfo) checkField(fd pref.FieldDescriptor) (*fieldInfo, pref.ExtensionType) {
Joe Tsai9d637ca2019-09-18 18:08:52 -0700333 var fi *fieldInfo
334 if n := fd.Number(); 0 < n && int(n) < len(mi.denseFields) {
335 fi = mi.denseFields[n]
336 } else {
337 fi = mi.fields[n]
338 }
339 if fi != nil {
Joe Tsai82760ce2019-06-20 03:09:57 -0700340 if fi.fieldDesc != fd {
341 panic("mismatching field descriptor")
342 }
343 return fi, nil
344 }
Joe Tsai9d637ca2019-09-18 18:08:52 -0700345
Joe Tsai82760ce2019-06-20 03:09:57 -0700346 if fd.IsExtension() {
Damien Neil16163b42019-08-06 15:43:25 -0700347 if fd.ContainingMessage().FullName() != mi.Desc.FullName() {
Joe Tsaifb5fde42020-02-20 11:00:10 -0800348 // TODO: Should this be exact containing message descriptor match?
Joe Tsai82760ce2019-06-20 03:09:57 -0700349 panic("mismatching containing message")
350 }
Damien Neil16163b42019-08-06 15:43:25 -0700351 if !mi.Desc.ExtensionRanges().Has(fd.Number()) {
Joe Tsai82760ce2019-06-20 03:09:57 -0700352 panic("invalid extension field")
353 }
Damien Neil92f76182019-08-02 16:58:08 -0700354 xtd, ok := fd.(pref.ExtensionTypeDescriptor)
355 if !ok {
356 panic("extension descriptor does not implement ExtensionTypeDescriptor")
357 }
358 return nil, xtd.Type()
Joe Tsai82760ce2019-06-20 03:09:57 -0700359 }
360 panic("invalid field descriptor")
361}