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