blob: aef3993fc6d37c0ab06e1ac6275357b73c534693 [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 {
39 // TODO: support map fields.
40 panic(fmt.Sprintf("invalid field: %v", fd))
41}
42
43func fieldInfoForVector(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsai91e14662018-09-13 13:24:35 -070044 ft := fs.Type
45 if ft.Kind() != reflect.Slice {
46 panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
47 }
48 conv := matchGoTypePBKind(ft.Elem(), fd.Kind())
49 fieldOffset := offsetOf(fs)
50 // TODO: Implement unsafe fast path?
51 return fieldInfo{
52 has: func(p pointer) bool {
53 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
54 return rv.Len() > 0
55 },
56 get: func(p pointer) pref.Value {
57 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
58 return pref.ValueOf(vectorReflect{rv, conv})
59 },
60 set: func(p pointer, v pref.Value) {
61 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
62 rv.Set(v.Vector().(vectorReflect).v)
63 },
64 clear: func(p pointer) {
65 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
66 rv.Set(reflect.Zero(rv.Type()))
67 },
68 mutable: func(p pointer) pref.Mutable {
69 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
70 return vectorReflect{rv, conv}
71 },
72 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -070073}
74
Joe Tsai91e14662018-09-13 13:24:35 -070075type vectorReflect struct {
76 v reflect.Value // addressable []T
77 conv converter
78}
79
80func (vs vectorReflect) Len() int {
81 return vs.v.Len()
82}
83func (vs vectorReflect) Get(i int) pref.Value {
84 return vs.conv.toPB(vs.v.Index(i))
85}
86func (vs vectorReflect) Set(i int, v pref.Value) {
87 vs.v.Index(i).Set(vs.conv.toGo(v))
88}
89func (vs vectorReflect) Append(v pref.Value) {
90 vs.v.Set(reflect.Append(vs.v, vs.conv.toGo(v)))
91}
92func (vs vectorReflect) Mutable(i int) pref.Mutable {
93 // Mutable is only valid for messages and panics for other kinds.
94 rv := vs.v.Index(i)
95 if rv.IsNil() {
96 pv := pref.ValueOf(vs.conv.newMessage())
97 rv.Set(vs.conv.toGo(pv))
98 }
99 return rv.Interface().(pref.Message)
100}
101func (vs vectorReflect) MutableAppend() pref.Mutable {
102 // MutableAppend is only valid for messages and panics for other kinds.
103 pv := pref.ValueOf(vs.conv.newMessage())
104 vs.v.Set(reflect.Append(vs.v, vs.conv.toGo(pv)))
105 return vs.v.Index(vs.Len() - 1).Interface().(pref.Message)
106}
107func (vs vectorReflect) Truncate(i int) {
108 vs.v.Set(vs.v.Slice(0, i))
109}
110func (vs vectorReflect) Unwrap() interface{} { // TODO: unexport?
111 return vs.v.Interface()
112}
113func (vs vectorReflect) ProtoMutable() {}
114
115var _ pref.Vector = vectorReflect{}
116
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700117var emptyBytes = reflect.ValueOf([]byte{})
118
119func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
120 ft := fs.Type
121 nullable := fd.Syntax() == pref.Proto2
122 if nullable {
123 if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
124 panic(fmt.Sprintf("invalid type: got %v, want pointer", ft))
125 }
126 if ft.Kind() == reflect.Ptr {
127 ft = ft.Elem()
128 }
129 }
130 conv := matchGoTypePBKind(ft, fd.Kind())
131 fieldOffset := offsetOf(fs)
132 // TODO: Implement unsafe fast path?
133 return fieldInfo{
134 has: func(p pointer) bool {
135 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
136 if nullable {
137 return !rv.IsNil()
138 }
139 switch rv.Kind() {
140 case reflect.Bool:
141 return rv.Bool()
142 case reflect.Int32, reflect.Int64:
143 return rv.Int() > 0
144 case reflect.Uint32, reflect.Uint64:
145 return rv.Uint() > 0
146 case reflect.Float32, reflect.Float64:
147 return rv.Float() > 0
148 case reflect.String, reflect.Slice:
149 return rv.Len() > 0
150 default:
151 panic(fmt.Sprintf("invalid type: %v", rv.Type())) // should never happen
152 }
153 },
154 get: func(p pointer) pref.Value {
155 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
156 if nullable {
157 if rv.IsNil() {
158 pv := fd.Default()
159 if fd.Kind() == pref.BytesKind && len(pv.Bytes()) > 0 {
160 return pref.ValueOf(append([]byte(nil), pv.Bytes()...)) // copy default bytes for safety
161 }
162 return pv
163 }
164 if rv.Kind() == reflect.Ptr {
165 rv = rv.Elem()
166 }
167 }
168 return conv.toPB(rv)
169 },
170 set: func(p pointer, v pref.Value) {
171 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
172 if nullable && rv.Kind() == reflect.Ptr {
173 if rv.IsNil() {
174 rv.Set(reflect.New(ft))
175 }
176 rv = rv.Elem()
177 }
178 rv.Set(conv.toGo(v))
179 if nullable && rv.Kind() == reflect.Slice && rv.IsNil() {
180 rv.Set(emptyBytes)
181 }
182 },
183 clear: func(p pointer) {
184 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
185 rv.Set(reflect.Zero(rv.Type()))
186 },
187 mutable: func(p pointer) pref.Mutable {
188 panic("invalid mutable call")
189 },
190 }
191}
192
193func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
194 // TODO: support vector fields.
195 panic(fmt.Sprintf("invalid field: %v", fd))
196}
197
198// messageV1 is the protoV1.Message interface.
199type messageV1 interface {
200 Reset()
201 String() string
202 ProtoMessage()
203}
204
205var (
206 boolType = reflect.TypeOf(bool(false))
207 int32Type = reflect.TypeOf(int32(0))
208 int64Type = reflect.TypeOf(int64(0))
209 uint32Type = reflect.TypeOf(uint32(0))
210 uint64Type = reflect.TypeOf(uint64(0))
211 float32Type = reflect.TypeOf(float32(0))
212 float64Type = reflect.TypeOf(float64(0))
213 stringType = reflect.TypeOf(string(""))
214 bytesType = reflect.TypeOf([]byte(nil))
215
216 enumIfaceV2 = reflect.TypeOf((*pref.ProtoEnum)(nil)).Elem()
217 messageIfaceV1 = reflect.TypeOf((*messageV1)(nil)).Elem()
218 messageIfaceV2 = reflect.TypeOf((*pref.ProtoMessage)(nil)).Elem()
219
220 byteType = reflect.TypeOf(byte(0))
221)
222
223// matchGoTypePBKind matches a Go type with the protobuf kind.
224//
225// This matcher deliberately supports a wider range of Go types than what
226// protoc-gen-go historically generated to be able to automatically wrap some
227// v1 messages generated by other forks of protoc-gen-go.
228func matchGoTypePBKind(t reflect.Type, k pref.Kind) converter {
229 switch k {
230 case pref.BoolKind:
231 if t.Kind() == reflect.Bool {
232 return makeScalarConverter(t, boolType)
233 }
234 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
235 if t.Kind() == reflect.Int32 {
236 return makeScalarConverter(t, int32Type)
237 }
238 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
239 if t.Kind() == reflect.Int64 {
240 return makeScalarConverter(t, int64Type)
241 }
242 case pref.Uint32Kind, pref.Fixed32Kind:
243 if t.Kind() == reflect.Uint32 {
244 return makeScalarConverter(t, uint32Type)
245 }
246 case pref.Uint64Kind, pref.Fixed64Kind:
247 if t.Kind() == reflect.Uint64 {
248 return makeScalarConverter(t, uint64Type)
249 }
250 case pref.FloatKind:
251 if t.Kind() == reflect.Float32 {
252 return makeScalarConverter(t, float32Type)
253 }
254 case pref.DoubleKind:
255 if t.Kind() == reflect.Float64 {
256 return makeScalarConverter(t, float64Type)
257 }
258 case pref.StringKind:
259 if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
260 return makeScalarConverter(t, stringType)
261 }
262 case pref.BytesKind:
263 if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
264 return makeScalarConverter(t, bytesType)
265 }
266 case pref.EnumKind:
267 // Handle v2 enums, which must satisfy the proto.Enum interface.
268 if t.Kind() != reflect.Ptr && t.Implements(enumIfaceV2) {
269 // TODO: implement this.
270 }
271
272 // Handle v1 enums, which we identify as simply a named int32 type.
273 if t.Kind() == reflect.Int32 && t.PkgPath() != "" {
274 // TODO: need logic to wrap a legacy enum to implement this.
275 }
276 case pref.MessageKind, pref.GroupKind:
277 // Handle v2 messages, which must satisfy the proto.Message interface.
278 if t.Kind() == reflect.Ptr && t.Implements(messageIfaceV2) {
279 // TODO: implement this.
280 }
281
282 // Handle v1 messages, which we need to wrap as a v2 message.
283 if t.Kind() == reflect.Ptr && t.Implements(messageIfaceV1) {
284 // TODO: need logic to wrap a legacy message.
285 }
286 }
287 panic(fmt.Sprintf("invalid Go type %v for protobuf kind %v", t, k))
288}
289
290// converter provides functions for converting to/from Go reflect.Value types
291// and protobuf protoreflect.Value types.
292type converter struct {
Joe Tsai91e14662018-09-13 13:24:35 -0700293 toPB func(reflect.Value) pref.Value
294 toGo func(pref.Value) reflect.Value
295 newMessage func() pref.Message
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700296}
297
298func makeScalarConverter(goType, pbType reflect.Type) converter {
299 return converter{
300 toPB: func(v reflect.Value) pref.Value {
301 if v.Type() != goType {
302 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), goType))
303 }
304 if goType.Kind() == reflect.String && pbType.Kind() == reflect.Slice && v.Len() == 0 {
305 return pref.ValueOf([]byte(nil)) // ensure empty string is []byte(nil)
306 }
307 return pref.ValueOf(v.Convert(pbType).Interface())
308 },
309 toGo: func(v pref.Value) reflect.Value {
310 rv := reflect.ValueOf(v.Interface())
311 if rv.Type() != pbType {
312 panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), pbType))
313 }
314 if pbType.Kind() == reflect.String && goType.Kind() == reflect.Slice && rv.Len() == 0 {
315 return reflect.Zero(goType) // ensure empty string is []byte(nil)
316 }
317 return rv.Convert(goType)
318 },
319 }
320}