blob: f0bb02fc9c2d4526702a69125b31f7f3f7a9abcd [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
Joe Tsai1726b832020-06-25 10:40:16 -070011 "google.golang.org/protobuf/internal/detrand"
Joe Tsai82760ce2019-06-20 03:09:57 -070012 "google.golang.org/protobuf/internal/pragma"
Joe Tsai82760ce2019-06-20 03:09:57 -070013 pref "google.golang.org/protobuf/reflect/protoreflect"
Joe Tsai82760ce2019-06-20 03:09:57 -070014)
15
Joe Tsai0484b1a2019-08-13 15:36:08 -070016type reflectMessageInfo struct {
17 fields map[pref.FieldNumber]*fieldInfo
18 oneofs map[pref.Name]*oneofInfo
19
Joe Tsai9d637ca2019-09-18 18:08:52 -070020 // denseFields is a subset of fields where:
21 // 0 < fieldDesc.Number() < len(denseFields)
22 // It provides faster access to the fieldInfo, but may be incomplete.
23 denseFields []*fieldInfo
24
25 // rangeInfos is a list of all fields (not belonging to a oneof) and oneofs.
26 rangeInfos []interface{} // either *fieldInfo or *oneofInfo
27
Joe Tsai0484b1a2019-08-13 15:36:08 -070028 getUnknown func(pointer) pref.RawFields
29 setUnknown func(pointer, pref.RawFields)
30 extensionMap func(pointer) *extensionMap
31
32 nilMessage atomicNilMessage
33}
34
35// makeReflectFuncs generates the set of functions to support reflection.
36func (mi *MessageInfo) makeReflectFuncs(t reflect.Type, si structInfo) {
37 mi.makeKnownFieldsFunc(si)
38 mi.makeUnknownFieldsFunc(t, si)
39 mi.makeExtensionFieldsFunc(t, si)
40}
41
42// makeKnownFieldsFunc generates functions for operations that can be performed
43// on each protobuf message field. It takes in a reflect.Type representing the
44// Go struct and matches message fields with struct fields.
45//
46// This code assumes that the struct is well-formed and panics if there are
47// any discrepancies.
48func (mi *MessageInfo) makeKnownFieldsFunc(si structInfo) {
49 mi.fields = map[pref.FieldNumber]*fieldInfo{}
50 md := mi.Desc
Joe Tsai9d637ca2019-09-18 18:08:52 -070051 fds := md.Fields()
52 for i := 0; i < fds.Len(); i++ {
53 fd := fds.Get(i)
Joe Tsai0484b1a2019-08-13 15:36:08 -070054 fs := si.fieldsByNumber[fd.Number()]
55 var fi fieldInfo
56 switch {
Joe Tsai387873d2020-04-28 14:44:38 -070057 case fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic():
Joe Tsai0484b1a2019-08-13 15:36:08 -070058 fi = fieldInfoForOneof(fd, si.oneofsByName[fd.ContainingOneof().Name()], mi.Exporter, si.oneofWrappersByNumber[fd.Number()])
59 case fd.IsMap():
60 fi = fieldInfoForMap(fd, fs, mi.Exporter)
61 case fd.IsList():
62 fi = fieldInfoForList(fd, fs, mi.Exporter)
63 case fd.IsWeak():
64 fi = fieldInfoForWeakMessage(fd, si.weakOffset)
65 case fd.Kind() == pref.MessageKind || fd.Kind() == pref.GroupKind:
66 fi = fieldInfoForMessage(fd, fs, mi.Exporter)
67 default:
68 fi = fieldInfoForScalar(fd, fs, mi.Exporter)
69 }
70 mi.fields[fd.Number()] = &fi
71 }
72
73 mi.oneofs = map[pref.Name]*oneofInfo{}
74 for i := 0; i < md.Oneofs().Len(); i++ {
75 od := md.Oneofs().Get(i)
Joe Tsai387873d2020-04-28 14:44:38 -070076 mi.oneofs[od.Name()] = makeOneofInfo(od, si, mi.Exporter)
Joe Tsai0484b1a2019-08-13 15:36:08 -070077 }
Joe Tsai9d637ca2019-09-18 18:08:52 -070078
79 mi.denseFields = make([]*fieldInfo, fds.Len()*2)
80 for i := 0; i < fds.Len(); i++ {
81 if fd := fds.Get(i); int(fd.Number()) < len(mi.denseFields) {
82 mi.denseFields[fd.Number()] = mi.fields[fd.Number()]
83 }
84 }
85
86 for i := 0; i < fds.Len(); {
87 fd := fds.Get(i)
Joe Tsai387873d2020-04-28 14:44:38 -070088 if od := fd.ContainingOneof(); od != nil && !od.IsSynthetic() {
Joe Tsai9d637ca2019-09-18 18:08:52 -070089 mi.rangeInfos = append(mi.rangeInfos, mi.oneofs[od.Name()])
90 i += od.Fields().Len()
91 } else {
92 mi.rangeInfos = append(mi.rangeInfos, mi.fields[fd.Number()])
93 i++
94 }
95 }
Joe Tsai1726b832020-06-25 10:40:16 -070096
97 // Introduce instability to iteration order, but keep it deterministic.
98 if len(mi.rangeInfos) > 1 && detrand.Bool() {
99 i := detrand.Intn(len(mi.rangeInfos) - 1)
100 mi.rangeInfos[i], mi.rangeInfos[i+1] = mi.rangeInfos[i+1], mi.rangeInfos[i]
101 }
Joe Tsai0484b1a2019-08-13 15:36:08 -0700102}
103
104func (mi *MessageInfo) makeUnknownFieldsFunc(t reflect.Type, si structInfo) {
105 mi.getUnknown = func(pointer) pref.RawFields { return nil }
106 mi.setUnknown = func(pointer, pref.RawFields) { return }
107 if si.unknownOffset.IsValid() {
108 mi.getUnknown = func(p pointer) pref.RawFields {
109 if p.IsNil() {
110 return nil
111 }
112 rv := p.Apply(si.unknownOffset).AsValueOf(unknownFieldsType)
113 return pref.RawFields(*rv.Interface().(*[]byte))
114 }
115 mi.setUnknown = func(p pointer, b pref.RawFields) {
116 if p.IsNil() {
117 panic("invalid SetUnknown on nil Message")
118 }
119 rv := p.Apply(si.unknownOffset).AsValueOf(unknownFieldsType)
120 *rv.Interface().(*[]byte) = []byte(b)
121 }
122 } else {
123 mi.getUnknown = func(pointer) pref.RawFields {
124 return nil
125 }
126 mi.setUnknown = func(p pointer, _ pref.RawFields) {
127 if p.IsNil() {
128 panic("invalid SetUnknown on nil Message")
129 }
130 }
131 }
132}
133
134func (mi *MessageInfo) makeExtensionFieldsFunc(t reflect.Type, si structInfo) {
135 if si.extensionOffset.IsValid() {
136 mi.extensionMap = func(p pointer) *extensionMap {
137 if p.IsNil() {
138 return (*extensionMap)(nil)
139 }
140 v := p.Apply(si.extensionOffset).AsValueOf(extensionFieldsType)
141 return (*extensionMap)(v.Interface().(*map[int32]ExtensionField))
142 }
143 } else {
144 mi.extensionMap = func(pointer) *extensionMap {
145 return (*extensionMap)(nil)
146 }
147 }
148}
149
150type extensionMap map[int32]ExtensionField
151
152func (m *extensionMap) Range(f func(pref.FieldDescriptor, pref.Value) bool) {
153 if m != nil {
154 for _, x := range *m {
Damien Neila0a54b82019-11-01 15:18:36 -0700155 xd := x.Type().TypeDescriptor()
156 v := x.Value()
157 if xd.IsList() && v.List().Len() == 0 {
158 continue
159 }
160 if !f(xd, v) {
Joe Tsai0484b1a2019-08-13 15:36:08 -0700161 return
162 }
163 }
164 }
165}
166func (m *extensionMap) Has(xt pref.ExtensionType) (ok bool) {
Damien Neila0a54b82019-11-01 15:18:36 -0700167 if m == nil {
168 return false
Joe Tsai0484b1a2019-08-13 15:36:08 -0700169 }
Damien Neila0a54b82019-11-01 15:18:36 -0700170 xd := xt.TypeDescriptor()
171 x, ok := (*m)[int32(xd.Number())]
172 if !ok {
173 return false
174 }
175 switch {
176 case xd.IsList():
177 return x.Value().List().Len() > 0
178 case xd.IsMap():
179 return x.Value().Map().Len() > 0
Joe Tsaib57aae92020-04-22 13:49:10 -0700180 case xd.Message() != nil:
181 return x.Value().Message().IsValid()
Damien Neila0a54b82019-11-01 15:18:36 -0700182 }
183 return true
Joe Tsai0484b1a2019-08-13 15:36:08 -0700184}
185func (m *extensionMap) Clear(xt pref.ExtensionType) {
Damien Neil79bfdbe2019-08-28 11:08:22 -0700186 delete(*m, int32(xt.TypeDescriptor().Number()))
Joe Tsai0484b1a2019-08-13 15:36:08 -0700187}
188func (m *extensionMap) Get(xt pref.ExtensionType) pref.Value {
Damien Neil79bfdbe2019-08-28 11:08:22 -0700189 xd := xt.TypeDescriptor()
Joe Tsai0484b1a2019-08-13 15:36:08 -0700190 if m != nil {
191 if x, ok := (*m)[int32(xd.Number())]; ok {
Damien Neil68b81c32019-08-22 11:41:32 -0700192 return x.Value()
Joe Tsai0484b1a2019-08-13 15:36:08 -0700193 }
194 }
195 return xt.Zero()
196}
197func (m *extensionMap) Set(xt pref.ExtensionType, v pref.Value) {
Joe Tsaib57aae92020-04-22 13:49:10 -0700198 xd := xt.TypeDescriptor()
199 isValid := true
200 switch {
201 case !xt.IsValidValue(v):
202 isValid = false
203 case xd.IsList():
204 isValid = v.List().IsValid()
205 case xd.IsMap():
206 isValid = v.Map().IsValid()
207 case xd.Message() != nil:
208 isValid = v.Message().IsValid()
209 }
210 if !isValid {
Joe Tsai09217f02019-09-06 16:57:46 -0700211 panic(fmt.Sprintf("%v: assigning invalid value", xt.TypeDescriptor().FullName()))
Damien Neil68b81c32019-08-22 11:41:32 -0700212 }
Joe Tsaib57aae92020-04-22 13:49:10 -0700213
Joe Tsai0484b1a2019-08-13 15:36:08 -0700214 if *m == nil {
215 *m = make(map[int32]ExtensionField)
216 }
217 var x ExtensionField
Damien Neil68b81c32019-08-22 11:41:32 -0700218 x.Set(xt, v)
Joe Tsaib57aae92020-04-22 13:49:10 -0700219 (*m)[int32(xd.Number())] = x
Joe Tsai0484b1a2019-08-13 15:36:08 -0700220}
221func (m *extensionMap) Mutable(xt pref.ExtensionType) pref.Value {
Damien Neil79bfdbe2019-08-28 11:08:22 -0700222 xd := xt.TypeDescriptor()
Joe Tsai0484b1a2019-08-13 15:36:08 -0700223 if xd.Kind() != pref.MessageKind && xd.Kind() != pref.GroupKind && !xd.IsList() && !xd.IsMap() {
224 panic("invalid Mutable on field with non-composite type")
225 }
226 if x, ok := (*m)[int32(xd.Number())]; ok {
Damien Neil68b81c32019-08-22 11:41:32 -0700227 return x.Value()
Joe Tsai0484b1a2019-08-13 15:36:08 -0700228 }
229 v := xt.New()
230 m.Set(xt, v)
231 return v
232}
233
Joe Tsai82760ce2019-06-20 03:09:57 -0700234// MessageState is a data structure that is nested as the first field in a
235// concrete message. It provides a way to implement the ProtoReflect method
236// in an allocation-free way without needing to have a shadow Go type generated
237// for every message type. This technique only works using unsafe.
238//
239//
240// Example generated code:
241//
242// type M struct {
243// state protoimpl.MessageState
244//
245// Field1 int32
246// Field2 string
247// Field3 *BarMessage
248// ...
249// }
250//
251// func (m *M) ProtoReflect() protoreflect.Message {
252// mi := &file_fizz_buzz_proto_msgInfos[5]
253// if protoimpl.UnsafeEnabled && m != nil {
254// ms := protoimpl.X.MessageStateOf(Pointer(m))
255// if ms.LoadMessageInfo() == nil {
256// ms.StoreMessageInfo(mi)
257// }
258// return ms
259// }
260// return mi.MessageOf(m)
261// }
262//
263// The MessageState type holds a *MessageInfo, which must be atomically set to
264// the message info associated with a given message instance.
265// By unsafely converting a *M into a *MessageState, the MessageState object
266// has access to all the information needed to implement protobuf reflection.
267// It has access to the message info as its first field, and a pointer to the
268// MessageState is identical to a pointer to the concrete message value.
269//
270//
271// Requirements:
272// • The type M must implement protoreflect.ProtoMessage.
273// • The address of m must not be nil.
274// • The address of m and the address of m.state must be equal,
275// even though they are different Go types.
276type MessageState struct {
277 pragma.NoUnkeyedLiterals
278 pragma.DoNotCompare
279 pragma.DoNotCopy
280
Damien Neil075e0742020-02-27 12:33:08 -0800281 atomicMessageInfo *MessageInfo
Joe Tsai82760ce2019-06-20 03:09:57 -0700282}
283
284type messageState MessageState
285
286var (
Damien Neil954bd922019-07-17 16:52:10 -0700287 _ pref.Message = (*messageState)(nil)
Joe Tsaifd528ff2019-09-03 16:30:39 -0700288 _ unwrapper = (*messageState)(nil)
Joe Tsai82760ce2019-06-20 03:09:57 -0700289)
290
291// messageDataType is a tuple of a pointer to the message data and
292// a pointer to the message type. It is a generalized way of providing a
293// reflective view over a message instance. The disadvantage of this approach
294// is the need to allocate this tuple of 16B.
295type messageDataType struct {
296 p pointer
297 mi *MessageInfo
298}
299
300type (
Joe Tsai82760ce2019-06-20 03:09:57 -0700301 messageReflectWrapper messageDataType
Joe Tsai0f81b382019-07-10 23:14:31 -0700302 messageIfaceWrapper messageDataType
Joe Tsai82760ce2019-06-20 03:09:57 -0700303)
304
305var (
306 _ pref.Message = (*messageReflectWrapper)(nil)
Joe Tsaifd528ff2019-09-03 16:30:39 -0700307 _ unwrapper = (*messageReflectWrapper)(nil)
Joe Tsai82760ce2019-06-20 03:09:57 -0700308 _ pref.ProtoMessage = (*messageIfaceWrapper)(nil)
Joe Tsaifd528ff2019-09-03 16:30:39 -0700309 _ unwrapper = (*messageIfaceWrapper)(nil)
Joe Tsai82760ce2019-06-20 03:09:57 -0700310)
311
312// MessageOf returns a reflective view over a message. The input must be a
313// pointer to a named Go struct. If the provided type has a ProtoReflect method,
314// it must be implemented by calling this method.
315func (mi *MessageInfo) MessageOf(m interface{}) pref.Message {
316 // TODO: Switch the input to be an opaque Pointer.
Damien Neil16163b42019-08-06 15:43:25 -0700317 if reflect.TypeOf(m) != mi.GoReflectType {
318 panic(fmt.Sprintf("type mismatch: got %T, want %v", m, mi.GoReflectType))
Joe Tsai82760ce2019-06-20 03:09:57 -0700319 }
320 p := pointerOfIface(m)
321 if p.IsNil() {
322 return mi.nilMessage.Init(mi)
323 }
324 return &messageReflectWrapper{p, mi}
325}
326
Joe Tsai2aea6142019-07-31 12:27:30 -0700327func (m *messageReflectWrapper) pointer() pointer { return m.p }
328func (m *messageReflectWrapper) messageInfo() *MessageInfo { return m.mi }
Joe Tsai82760ce2019-06-20 03:09:57 -0700329
330func (m *messageIfaceWrapper) ProtoReflect() pref.Message {
331 return (*messageReflectWrapper)(m)
332}
Joe Tsaifd528ff2019-09-03 16:30:39 -0700333func (m *messageIfaceWrapper) protoUnwrap() interface{} {
Damien Neil16163b42019-08-06 15:43:25 -0700334 return m.p.AsIfaceOf(m.mi.GoReflectType.Elem())
Joe Tsai82760ce2019-06-20 03:09:57 -0700335}
Joe Tsai82760ce2019-06-20 03:09:57 -0700336
Joe Tsai82760ce2019-06-20 03:09:57 -0700337// checkField verifies that the provided field descriptor is valid.
338// Exactly one of the returned values is populated.
339func (mi *MessageInfo) checkField(fd pref.FieldDescriptor) (*fieldInfo, pref.ExtensionType) {
Joe Tsai9d637ca2019-09-18 18:08:52 -0700340 var fi *fieldInfo
341 if n := fd.Number(); 0 < n && int(n) < len(mi.denseFields) {
342 fi = mi.denseFields[n]
343 } else {
344 fi = mi.fields[n]
345 }
346 if fi != nil {
Joe Tsai82760ce2019-06-20 03:09:57 -0700347 if fi.fieldDesc != fd {
Joe Tsai1f5b6fe2020-04-22 21:58:56 -0700348 if got, want := fd.FullName(), fi.fieldDesc.FullName(); got != want {
349 panic(fmt.Sprintf("mismatching field: got %v, want %v", got, want))
350 }
351 panic(fmt.Sprintf("mismatching field: %v", fd.FullName()))
Joe Tsai82760ce2019-06-20 03:09:57 -0700352 }
353 return fi, nil
354 }
Joe Tsai9d637ca2019-09-18 18:08:52 -0700355
Joe Tsai82760ce2019-06-20 03:09:57 -0700356 if fd.IsExtension() {
Joe Tsai1f5b6fe2020-04-22 21:58:56 -0700357 if got, want := fd.ContainingMessage().FullName(), mi.Desc.FullName(); got != want {
Joe Tsaifb5fde42020-02-20 11:00:10 -0800358 // TODO: Should this be exact containing message descriptor match?
Joe Tsai1f5b6fe2020-04-22 21:58:56 -0700359 panic(fmt.Sprintf("extension %v has mismatching containing message: got %v, want %v", fd.FullName(), got, want))
Joe Tsai82760ce2019-06-20 03:09:57 -0700360 }
Damien Neil16163b42019-08-06 15:43:25 -0700361 if !mi.Desc.ExtensionRanges().Has(fd.Number()) {
Joe Tsai1f5b6fe2020-04-22 21:58:56 -0700362 panic(fmt.Sprintf("extension %v extends %v outside the extension range", fd.FullName(), mi.Desc.FullName()))
Joe Tsai82760ce2019-06-20 03:09:57 -0700363 }
Damien Neil92f76182019-08-02 16:58:08 -0700364 xtd, ok := fd.(pref.ExtensionTypeDescriptor)
365 if !ok {
Joe Tsai1f5b6fe2020-04-22 21:58:56 -0700366 panic(fmt.Sprintf("extension %v does not implement protoreflect.ExtensionTypeDescriptor", fd.FullName()))
Damien Neil92f76182019-08-02 16:58:08 -0700367 }
368 return nil, xtd.Type()
Joe Tsai82760ce2019-06-20 03:09:57 -0700369 }
Joe Tsai1f5b6fe2020-04-22 21:58:56 -0700370 panic(fmt.Sprintf("field %v is invalid", fd.FullName()))
Joe Tsai82760ce2019-06-20 03:09:57 -0700371}