blob: bc5030302c0014f20d71fa4475cfaf4ffe37d574 [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 {
56 case fd.ContainingOneof() != nil:
57 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)
75 mi.oneofs[od.Name()] = makeOneofInfo(od, si.oneofsByName[od.Name()], mi.Exporter, si.oneofWrappersByType)
76 }
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)
87 if od := fd.ContainingOneof(); od != nil {
88 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 Neilef19a2a2019-11-01 12:00:37 -0700148 xt := x.Type()
Damien Neil68b81c32019-08-22 11:41:32 -0700149 if !f(xt.TypeDescriptor(), x.Value()) {
Joe Tsai0484b1a2019-08-13 15:36:08 -0700150 return
151 }
152 }
153 }
154}
155func (m *extensionMap) Has(xt pref.ExtensionType) (ok bool) {
156 if m != nil {
Damien Neil79bfdbe2019-08-28 11:08:22 -0700157 _, ok = (*m)[int32(xt.TypeDescriptor().Number())]
Joe Tsai0484b1a2019-08-13 15:36:08 -0700158 }
159 return ok
160}
161func (m *extensionMap) Clear(xt pref.ExtensionType) {
Damien Neil79bfdbe2019-08-28 11:08:22 -0700162 delete(*m, int32(xt.TypeDescriptor().Number()))
Joe Tsai0484b1a2019-08-13 15:36:08 -0700163}
164func (m *extensionMap) Get(xt pref.ExtensionType) pref.Value {
Damien Neil79bfdbe2019-08-28 11:08:22 -0700165 xd := xt.TypeDescriptor()
Joe Tsai0484b1a2019-08-13 15:36:08 -0700166 if m != nil {
167 if x, ok := (*m)[int32(xd.Number())]; ok {
Damien Neil68b81c32019-08-22 11:41:32 -0700168 return x.Value()
Joe Tsai0484b1a2019-08-13 15:36:08 -0700169 }
170 }
171 return xt.Zero()
172}
173func (m *extensionMap) Set(xt pref.ExtensionType, v pref.Value) {
Damien Neil68b81c32019-08-22 11:41:32 -0700174 if !xt.IsValidValue(v) {
Joe Tsai09217f02019-09-06 16:57:46 -0700175 panic(fmt.Sprintf("%v: assigning invalid value", xt.TypeDescriptor().FullName()))
Damien Neil68b81c32019-08-22 11:41:32 -0700176 }
Joe Tsai0484b1a2019-08-13 15:36:08 -0700177 if *m == nil {
178 *m = make(map[int32]ExtensionField)
179 }
180 var x ExtensionField
Damien Neil68b81c32019-08-22 11:41:32 -0700181 x.Set(xt, v)
Damien Neil79bfdbe2019-08-28 11:08:22 -0700182 (*m)[int32(xt.TypeDescriptor().Number())] = x
Joe Tsai0484b1a2019-08-13 15:36:08 -0700183}
184func (m *extensionMap) Mutable(xt pref.ExtensionType) pref.Value {
Damien Neil79bfdbe2019-08-28 11:08:22 -0700185 xd := xt.TypeDescriptor()
Joe Tsai0484b1a2019-08-13 15:36:08 -0700186 if xd.Kind() != pref.MessageKind && xd.Kind() != pref.GroupKind && !xd.IsList() && !xd.IsMap() {
187 panic("invalid Mutable on field with non-composite type")
188 }
189 if x, ok := (*m)[int32(xd.Number())]; ok {
Damien Neil68b81c32019-08-22 11:41:32 -0700190 return x.Value()
Joe Tsai0484b1a2019-08-13 15:36:08 -0700191 }
192 v := xt.New()
193 m.Set(xt, v)
194 return v
195}
196
Joe Tsai82760ce2019-06-20 03:09:57 -0700197// MessageState is a data structure that is nested as the first field in a
198// concrete message. It provides a way to implement the ProtoReflect method
199// in an allocation-free way without needing to have a shadow Go type generated
200// for every message type. This technique only works using unsafe.
201//
202//
203// Example generated code:
204//
205// type M struct {
206// state protoimpl.MessageState
207//
208// Field1 int32
209// Field2 string
210// Field3 *BarMessage
211// ...
212// }
213//
214// func (m *M) ProtoReflect() protoreflect.Message {
215// mi := &file_fizz_buzz_proto_msgInfos[5]
216// if protoimpl.UnsafeEnabled && m != nil {
217// ms := protoimpl.X.MessageStateOf(Pointer(m))
218// if ms.LoadMessageInfo() == nil {
219// ms.StoreMessageInfo(mi)
220// }
221// return ms
222// }
223// return mi.MessageOf(m)
224// }
225//
226// The MessageState type holds a *MessageInfo, which must be atomically set to
227// the message info associated with a given message instance.
228// By unsafely converting a *M into a *MessageState, the MessageState object
229// has access to all the information needed to implement protobuf reflection.
230// It has access to the message info as its first field, and a pointer to the
231// MessageState is identical to a pointer to the concrete message value.
232//
233//
234// Requirements:
235// • The type M must implement protoreflect.ProtoMessage.
236// • The address of m must not be nil.
237// • The address of m and the address of m.state must be equal,
238// even though they are different Go types.
239type MessageState struct {
240 pragma.NoUnkeyedLiterals
241 pragma.DoNotCompare
242 pragma.DoNotCopy
243
244 mi *MessageInfo
245}
246
247type messageState MessageState
248
249var (
Damien Neil954bd922019-07-17 16:52:10 -0700250 _ pref.Message = (*messageState)(nil)
Joe Tsaifd528ff2019-09-03 16:30:39 -0700251 _ unwrapper = (*messageState)(nil)
Joe Tsai82760ce2019-06-20 03:09:57 -0700252)
253
254// messageDataType is a tuple of a pointer to the message data and
255// a pointer to the message type. It is a generalized way of providing a
256// reflective view over a message instance. The disadvantage of this approach
257// is the need to allocate this tuple of 16B.
258type messageDataType struct {
259 p pointer
260 mi *MessageInfo
261}
262
263type (
Joe Tsai82760ce2019-06-20 03:09:57 -0700264 messageReflectWrapper messageDataType
Joe Tsai0f81b382019-07-10 23:14:31 -0700265 messageIfaceWrapper messageDataType
Joe Tsai82760ce2019-06-20 03:09:57 -0700266)
267
268var (
269 _ pref.Message = (*messageReflectWrapper)(nil)
Joe Tsaifd528ff2019-09-03 16:30:39 -0700270 _ unwrapper = (*messageReflectWrapper)(nil)
Joe Tsai82760ce2019-06-20 03:09:57 -0700271 _ pref.ProtoMessage = (*messageIfaceWrapper)(nil)
Joe Tsaifd528ff2019-09-03 16:30:39 -0700272 _ unwrapper = (*messageIfaceWrapper)(nil)
Joe Tsai82760ce2019-06-20 03:09:57 -0700273)
274
275// MessageOf returns a reflective view over a message. The input must be a
276// pointer to a named Go struct. If the provided type has a ProtoReflect method,
277// it must be implemented by calling this method.
278func (mi *MessageInfo) MessageOf(m interface{}) pref.Message {
279 // TODO: Switch the input to be an opaque Pointer.
Damien Neil16163b42019-08-06 15:43:25 -0700280 if reflect.TypeOf(m) != mi.GoReflectType {
281 panic(fmt.Sprintf("type mismatch: got %T, want %v", m, mi.GoReflectType))
Joe Tsai82760ce2019-06-20 03:09:57 -0700282 }
283 p := pointerOfIface(m)
284 if p.IsNil() {
285 return mi.nilMessage.Init(mi)
286 }
287 return &messageReflectWrapper{p, mi}
288}
289
Joe Tsai2aea6142019-07-31 12:27:30 -0700290func (m *messageReflectWrapper) pointer() pointer { return m.p }
291func (m *messageReflectWrapper) messageInfo() *MessageInfo { return m.mi }
Joe Tsai82760ce2019-06-20 03:09:57 -0700292
293func (m *messageIfaceWrapper) ProtoReflect() pref.Message {
294 return (*messageReflectWrapper)(m)
295}
Joe Tsaifd528ff2019-09-03 16:30:39 -0700296func (m *messageIfaceWrapper) protoUnwrap() interface{} {
Damien Neil16163b42019-08-06 15:43:25 -0700297 return m.p.AsIfaceOf(m.mi.GoReflectType.Elem())
Joe Tsai82760ce2019-06-20 03:09:57 -0700298}
Joe Tsai82760ce2019-06-20 03:09:57 -0700299
Joe Tsai82760ce2019-06-20 03:09:57 -0700300// checkField verifies that the provided field descriptor is valid.
301// Exactly one of the returned values is populated.
302func (mi *MessageInfo) checkField(fd pref.FieldDescriptor) (*fieldInfo, pref.ExtensionType) {
Joe Tsai9d637ca2019-09-18 18:08:52 -0700303 var fi *fieldInfo
304 if n := fd.Number(); 0 < n && int(n) < len(mi.denseFields) {
305 fi = mi.denseFields[n]
306 } else {
307 fi = mi.fields[n]
308 }
309 if fi != nil {
Joe Tsai82760ce2019-06-20 03:09:57 -0700310 if fi.fieldDesc != fd {
311 panic("mismatching field descriptor")
312 }
313 return fi, nil
314 }
Joe Tsai9d637ca2019-09-18 18:08:52 -0700315
Joe Tsai82760ce2019-06-20 03:09:57 -0700316 if fd.IsExtension() {
Damien Neil16163b42019-08-06 15:43:25 -0700317 if fd.ContainingMessage().FullName() != mi.Desc.FullName() {
Joe Tsai82760ce2019-06-20 03:09:57 -0700318 // TODO: Should this be exact containing message descriptor match?
319 panic("mismatching containing message")
320 }
Damien Neil16163b42019-08-06 15:43:25 -0700321 if !mi.Desc.ExtensionRanges().Has(fd.Number()) {
Joe Tsai82760ce2019-06-20 03:09:57 -0700322 panic("invalid extension field")
323 }
Damien Neil92f76182019-08-02 16:58:08 -0700324 xtd, ok := fd.(pref.ExtensionTypeDescriptor)
325 if !ok {
326 panic("extension descriptor does not implement ExtensionTypeDescriptor")
327 }
328 return nil, xtd.Type()
Joe Tsai82760ce2019-06-20 03:09:57 -0700329 }
330 panic("invalid field descriptor")
331}