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