blob: bdab90a33616b0cc0a31a87312f1ac66dec31a84 [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 (
8 "fmt"
9 "reflect"
10
Joe Tsai01ab2962018-09-21 17:44:00 -070011 "github.com/golang/protobuf/v2/internal/flags"
12 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Joe Tsaifa02f4e2018-09-12 16:20:37 -070013)
14
15type fieldInfo struct {
16 // TODO: specialize marshal and unmarshal functions?
17
18 has func(pointer) bool
19 get func(pointer) pref.Value
20 set func(pointer, pref.Value)
21 clear func(pointer)
22 mutable func(pointer) pref.Mutable
23}
24
25func fieldInfoForWeak(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
26 if !flags.Proto1Legacy {
27 panic("weak fields not supported")
28 }
29 // TODO: support weak fields.
30 panic(fmt.Sprintf("invalid field: %v", fd))
31}
32
33func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, ot reflect.Type) fieldInfo {
Joe Tsai2c870bb2018-10-17 11:46:52 -070034 ft := fs.Type
35 if ft.Kind() != reflect.Interface {
36 panic(fmt.Sprintf("invalid type: got %v, want interface kind", ft))
37 }
38 if ot.Kind() != reflect.Struct {
39 panic(fmt.Sprintf("invalid type: got %v, want struct kind", ot))
40 }
41 if !reflect.PtrTo(ot).Implements(ft) {
42 panic(fmt.Sprintf("invalid type: %v does not implement %v", ot, ft))
43 }
44 conv := matchGoTypePBKind(ot.Field(0).Type, fd.Kind())
45 fieldOffset := offsetOf(fs)
46 // TODO: Implement unsafe fast path?
47 return fieldInfo{
48 // NOTE: The logic below intentionally assumes that oneof fields are
49 // well-formatted. That is, the oneof interface never contains a
50 // typed nil pointer to one of the wrapper structs.
51
52 has: func(p pointer) bool {
53 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
54 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
55 return false
56 }
57 return true
58 },
59 get: func(p pointer) pref.Value {
60 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
61 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
62 if fd.Kind() == pref.MessageKind || fd.Kind() == pref.GroupKind {
63 // Return a typed nil pointer of the message type to be
64 // consistent with the behavior of generated getters.
65 rv = reflect.Zero(ot.Field(0).Type)
66 return conv.toPB(rv)
67 }
68 return fd.Default()
69 }
70 rv = rv.Elem().Elem().Field(0)
71 return conv.toPB(rv)
72 },
73 set: func(p pointer, v pref.Value) {
74 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
75 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
76 rv.Set(reflect.New(ot))
77 }
78 rv = rv.Elem().Elem().Field(0)
79 rv.Set(conv.toGo(v))
80 },
81 clear: func(p pointer) {
82 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
83 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
84 return
85 }
86 rv.Set(reflect.Zero(rv.Type()))
87 },
88 mutable: func(p pointer) pref.Mutable {
89 // Mutable is only valid for messages and panics for other kinds.
90 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
91 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
92 rv.Set(reflect.New(ot))
93 }
94 rv = rv.Elem().Elem().Field(0)
95 if rv.IsNil() {
96 pv := pref.ValueOf(conv.newMessage())
97 rv.Set(conv.toGo(pv))
98 }
99 return rv.Interface().(pref.Message)
100 },
101 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700102}
103
104func fieldInfoForMap(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000105 ft := fs.Type
106 if ft.Kind() != reflect.Map {
107 panic(fmt.Sprintf("invalid type: got %v, want map kind", ft))
108 }
109 keyConv := matchGoTypePBKind(ft.Key(), fd.MessageType().Fields().ByNumber(1).Kind())
110 valConv := matchGoTypePBKind(ft.Elem(), fd.MessageType().Fields().ByNumber(2).Kind())
111 fieldOffset := offsetOf(fs)
112 // TODO: Implement unsafe fast path?
113 return fieldInfo{
114 has: func(p pointer) bool {
115 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
116 return rv.Len() > 0
117 },
118 get: func(p pointer) pref.Value {
119 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
120 return pref.ValueOf(mapReflect{rv, keyConv, valConv})
121 },
122 set: func(p pointer, v pref.Value) {
123 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
124 rv.Set(v.Map().(mapReflect).v)
125 },
126 clear: func(p pointer) {
127 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
128 rv.Set(reflect.Zero(rv.Type()))
129 },
130 mutable: func(p pointer) pref.Mutable {
131 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
132 return mapReflect{rv, keyConv, valConv}
133 },
134 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700135}
136
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000137type mapReflect struct {
138 v reflect.Value // addressable map[K]V
139 keyConv converter
140 valConv converter
141}
142
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000143func (ms mapReflect) Len() int {
144 return ms.v.Len()
145}
146func (ms mapReflect) Has(k pref.MapKey) bool {
147 rk := ms.keyConv.toGo(k.Value())
148 rv := ms.v.MapIndex(rk)
149 return rv.IsValid()
150}
151func (ms mapReflect) Get(k pref.MapKey) pref.Value {
152 rk := ms.keyConv.toGo(k.Value())
153 rv := ms.v.MapIndex(rk)
154 if !rv.IsValid() {
155 return pref.Value{}
156 }
157 return ms.valConv.toPB(rv)
158}
159func (ms mapReflect) Set(k pref.MapKey, v pref.Value) {
160 if ms.v.IsNil() {
161 ms.v.Set(reflect.MakeMap(ms.v.Type()))
162 }
163 rk := ms.keyConv.toGo(k.Value())
164 rv := ms.valConv.toGo(v)
165 ms.v.SetMapIndex(rk, rv)
166}
167func (ms mapReflect) Clear(k pref.MapKey) {
168 rk := ms.keyConv.toGo(k.Value())
169 ms.v.SetMapIndex(rk, reflect.Value{})
170}
171func (ms mapReflect) Mutable(k pref.MapKey) pref.Mutable {
172 // Mutable is only valid for messages and panics for other kinds.
173 if ms.v.IsNil() {
174 ms.v.Set(reflect.MakeMap(ms.v.Type()))
175 }
176 rk := ms.keyConv.toGo(k.Value())
177 rv := ms.v.MapIndex(rk)
178 if !rv.IsValid() || rv.IsNil() {
179 pv := pref.ValueOf(ms.valConv.newMessage())
180 rv = ms.valConv.toGo(pv)
181 ms.v.SetMapIndex(rk, rv)
182 }
183 return rv.Interface().(pref.Message)
184}
185func (ms mapReflect) Range(f func(pref.MapKey, pref.Value) bool) {
186 for _, k := range ms.v.MapKeys() {
187 if v := ms.v.MapIndex(k); v.IsValid() {
188 pk := ms.keyConv.toPB(k).MapKey()
189 pv := ms.valConv.toPB(v)
190 if !f(pk, pv) {
191 return
192 }
193 }
194 }
195}
196func (ms mapReflect) Unwrap() interface{} { // TODO: unexport?
197 return ms.v.Interface()
198}
199func (ms mapReflect) ProtoMutable() {}
200
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700201func fieldInfoForVector(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsai91e14662018-09-13 13:24:35 -0700202 ft := fs.Type
203 if ft.Kind() != reflect.Slice {
204 panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
205 }
206 conv := matchGoTypePBKind(ft.Elem(), fd.Kind())
207 fieldOffset := offsetOf(fs)
208 // TODO: Implement unsafe fast path?
209 return fieldInfo{
210 has: func(p pointer) bool {
211 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
212 return rv.Len() > 0
213 },
214 get: func(p pointer) pref.Value {
215 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
216 return pref.ValueOf(vectorReflect{rv, conv})
217 },
218 set: func(p pointer, v pref.Value) {
219 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
220 rv.Set(v.Vector().(vectorReflect).v)
221 },
222 clear: func(p pointer) {
223 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
224 rv.Set(reflect.Zero(rv.Type()))
225 },
226 mutable: func(p pointer) pref.Mutable {
227 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
228 return vectorReflect{rv, conv}
229 },
230 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700231}
232
Joe Tsai91e14662018-09-13 13:24:35 -0700233type vectorReflect struct {
234 v reflect.Value // addressable []T
235 conv converter
236}
237
238func (vs vectorReflect) Len() int {
239 return vs.v.Len()
240}
241func (vs vectorReflect) Get(i int) pref.Value {
242 return vs.conv.toPB(vs.v.Index(i))
243}
244func (vs vectorReflect) Set(i int, v pref.Value) {
245 vs.v.Index(i).Set(vs.conv.toGo(v))
246}
247func (vs vectorReflect) Append(v pref.Value) {
248 vs.v.Set(reflect.Append(vs.v, vs.conv.toGo(v)))
249}
250func (vs vectorReflect) Mutable(i int) pref.Mutable {
251 // Mutable is only valid for messages and panics for other kinds.
252 rv := vs.v.Index(i)
253 if rv.IsNil() {
254 pv := pref.ValueOf(vs.conv.newMessage())
255 rv.Set(vs.conv.toGo(pv))
256 }
257 return rv.Interface().(pref.Message)
258}
259func (vs vectorReflect) MutableAppend() pref.Mutable {
260 // MutableAppend is only valid for messages and panics for other kinds.
261 pv := pref.ValueOf(vs.conv.newMessage())
262 vs.v.Set(reflect.Append(vs.v, vs.conv.toGo(pv)))
263 return vs.v.Index(vs.Len() - 1).Interface().(pref.Message)
264}
265func (vs vectorReflect) Truncate(i int) {
266 vs.v.Set(vs.v.Slice(0, i))
267}
268func (vs vectorReflect) Unwrap() interface{} { // TODO: unexport?
269 return vs.v.Interface()
270}
271func (vs vectorReflect) ProtoMutable() {}
272
273var _ pref.Vector = vectorReflect{}
274
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700275var emptyBytes = reflect.ValueOf([]byte{})
276
277func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
278 ft := fs.Type
279 nullable := fd.Syntax() == pref.Proto2
280 if nullable {
281 if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
282 panic(fmt.Sprintf("invalid type: got %v, want pointer", ft))
283 }
284 if ft.Kind() == reflect.Ptr {
285 ft = ft.Elem()
286 }
287 }
288 conv := matchGoTypePBKind(ft, fd.Kind())
289 fieldOffset := offsetOf(fs)
290 // TODO: Implement unsafe fast path?
291 return fieldInfo{
292 has: func(p pointer) bool {
293 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
294 if nullable {
295 return !rv.IsNil()
296 }
297 switch rv.Kind() {
298 case reflect.Bool:
299 return rv.Bool()
300 case reflect.Int32, reflect.Int64:
301 return rv.Int() > 0
302 case reflect.Uint32, reflect.Uint64:
303 return rv.Uint() > 0
304 case reflect.Float32, reflect.Float64:
305 return rv.Float() > 0
306 case reflect.String, reflect.Slice:
307 return rv.Len() > 0
308 default:
309 panic(fmt.Sprintf("invalid type: %v", rv.Type())) // should never happen
310 }
311 },
312 get: func(p pointer) pref.Value {
313 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
314 if nullable {
315 if rv.IsNil() {
316 pv := fd.Default()
317 if fd.Kind() == pref.BytesKind && len(pv.Bytes()) > 0 {
318 return pref.ValueOf(append([]byte(nil), pv.Bytes()...)) // copy default bytes for safety
319 }
320 return pv
321 }
322 if rv.Kind() == reflect.Ptr {
323 rv = rv.Elem()
324 }
325 }
326 return conv.toPB(rv)
327 },
328 set: func(p pointer, v pref.Value) {
329 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
330 if nullable && rv.Kind() == reflect.Ptr {
331 if rv.IsNil() {
332 rv.Set(reflect.New(ft))
333 }
334 rv = rv.Elem()
335 }
336 rv.Set(conv.toGo(v))
337 if nullable && rv.Kind() == reflect.Slice && rv.IsNil() {
338 rv.Set(emptyBytes)
339 }
340 },
341 clear: func(p pointer) {
342 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
343 rv.Set(reflect.Zero(rv.Type()))
344 },
345 mutable: func(p pointer) pref.Mutable {
346 panic("invalid mutable call")
347 },
348 }
349}
350
351func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
352 // TODO: support vector fields.
353 panic(fmt.Sprintf("invalid field: %v", fd))
354}
355
356// messageV1 is the protoV1.Message interface.
357type messageV1 interface {
358 Reset()
359 String() string
360 ProtoMessage()
361}
362
363var (
364 boolType = reflect.TypeOf(bool(false))
365 int32Type = reflect.TypeOf(int32(0))
366 int64Type = reflect.TypeOf(int64(0))
367 uint32Type = reflect.TypeOf(uint32(0))
368 uint64Type = reflect.TypeOf(uint64(0))
369 float32Type = reflect.TypeOf(float32(0))
370 float64Type = reflect.TypeOf(float64(0))
371 stringType = reflect.TypeOf(string(""))
372 bytesType = reflect.TypeOf([]byte(nil))
373
374 enumIfaceV2 = reflect.TypeOf((*pref.ProtoEnum)(nil)).Elem()
375 messageIfaceV1 = reflect.TypeOf((*messageV1)(nil)).Elem()
376 messageIfaceV2 = reflect.TypeOf((*pref.ProtoMessage)(nil)).Elem()
377
378 byteType = reflect.TypeOf(byte(0))
379)
380
381// matchGoTypePBKind matches a Go type with the protobuf kind.
382//
383// This matcher deliberately supports a wider range of Go types than what
384// protoc-gen-go historically generated to be able to automatically wrap some
385// v1 messages generated by other forks of protoc-gen-go.
386func matchGoTypePBKind(t reflect.Type, k pref.Kind) converter {
387 switch k {
388 case pref.BoolKind:
389 if t.Kind() == reflect.Bool {
390 return makeScalarConverter(t, boolType)
391 }
392 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
393 if t.Kind() == reflect.Int32 {
394 return makeScalarConverter(t, int32Type)
395 }
396 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
397 if t.Kind() == reflect.Int64 {
398 return makeScalarConverter(t, int64Type)
399 }
400 case pref.Uint32Kind, pref.Fixed32Kind:
401 if t.Kind() == reflect.Uint32 {
402 return makeScalarConverter(t, uint32Type)
403 }
404 case pref.Uint64Kind, pref.Fixed64Kind:
405 if t.Kind() == reflect.Uint64 {
406 return makeScalarConverter(t, uint64Type)
407 }
408 case pref.FloatKind:
409 if t.Kind() == reflect.Float32 {
410 return makeScalarConverter(t, float32Type)
411 }
412 case pref.DoubleKind:
413 if t.Kind() == reflect.Float64 {
414 return makeScalarConverter(t, float64Type)
415 }
416 case pref.StringKind:
417 if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
418 return makeScalarConverter(t, stringType)
419 }
420 case pref.BytesKind:
421 if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
422 return makeScalarConverter(t, bytesType)
423 }
424 case pref.EnumKind:
425 // Handle v2 enums, which must satisfy the proto.Enum interface.
426 if t.Kind() != reflect.Ptr && t.Implements(enumIfaceV2) {
427 // TODO: implement this.
428 }
429
430 // Handle v1 enums, which we identify as simply a named int32 type.
431 if t.Kind() == reflect.Int32 && t.PkgPath() != "" {
432 // TODO: need logic to wrap a legacy enum to implement this.
433 }
434 case pref.MessageKind, pref.GroupKind:
435 // Handle v2 messages, which must satisfy the proto.Message interface.
436 if t.Kind() == reflect.Ptr && t.Implements(messageIfaceV2) {
437 // TODO: implement this.
438 }
439
440 // Handle v1 messages, which we need to wrap as a v2 message.
441 if t.Kind() == reflect.Ptr && t.Implements(messageIfaceV1) {
442 // TODO: need logic to wrap a legacy message.
443 }
444 }
445 panic(fmt.Sprintf("invalid Go type %v for protobuf kind %v", t, k))
446}
447
448// converter provides functions for converting to/from Go reflect.Value types
449// and protobuf protoreflect.Value types.
450type converter struct {
Joe Tsai91e14662018-09-13 13:24:35 -0700451 toPB func(reflect.Value) pref.Value
452 toGo func(pref.Value) reflect.Value
453 newMessage func() pref.Message
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700454}
455
456func makeScalarConverter(goType, pbType reflect.Type) converter {
457 return converter{
458 toPB: func(v reflect.Value) pref.Value {
459 if v.Type() != goType {
460 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), goType))
461 }
462 if goType.Kind() == reflect.String && pbType.Kind() == reflect.Slice && v.Len() == 0 {
463 return pref.ValueOf([]byte(nil)) // ensure empty string is []byte(nil)
464 }
465 return pref.ValueOf(v.Convert(pbType).Interface())
466 },
467 toGo: func(v pref.Value) reflect.Value {
468 rv := reflect.ValueOf(v.Interface())
469 if rv.Type() != pbType {
470 panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), pbType))
471 }
472 if pbType.Kind() == reflect.String && goType.Kind() == reflect.Slice && rv.Len() == 0 {
473 return reflect.Zero(goType) // ensure empty string is []byte(nil)
474 }
475 return rv.Convert(goType)
476 },
477 }
478}