blob: 2d1c34c0cb499f3b6816e103a4618231d74f12dc [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 {
44 // TODO: support vector fields.
45 panic(fmt.Sprintf("invalid field: %v", fd))
46}
47
48var emptyBytes = reflect.ValueOf([]byte{})
49
50func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
51 ft := fs.Type
52 nullable := fd.Syntax() == pref.Proto2
53 if nullable {
54 if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
55 panic(fmt.Sprintf("invalid type: got %v, want pointer", ft))
56 }
57 if ft.Kind() == reflect.Ptr {
58 ft = ft.Elem()
59 }
60 }
61 conv := matchGoTypePBKind(ft, fd.Kind())
62 fieldOffset := offsetOf(fs)
63 // TODO: Implement unsafe fast path?
64 return fieldInfo{
65 has: func(p pointer) bool {
66 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
67 if nullable {
68 return !rv.IsNil()
69 }
70 switch rv.Kind() {
71 case reflect.Bool:
72 return rv.Bool()
73 case reflect.Int32, reflect.Int64:
74 return rv.Int() > 0
75 case reflect.Uint32, reflect.Uint64:
76 return rv.Uint() > 0
77 case reflect.Float32, reflect.Float64:
78 return rv.Float() > 0
79 case reflect.String, reflect.Slice:
80 return rv.Len() > 0
81 default:
82 panic(fmt.Sprintf("invalid type: %v", rv.Type())) // should never happen
83 }
84 },
85 get: func(p pointer) pref.Value {
86 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
87 if nullable {
88 if rv.IsNil() {
89 pv := fd.Default()
90 if fd.Kind() == pref.BytesKind && len(pv.Bytes()) > 0 {
91 return pref.ValueOf(append([]byte(nil), pv.Bytes()...)) // copy default bytes for safety
92 }
93 return pv
94 }
95 if rv.Kind() == reflect.Ptr {
96 rv = rv.Elem()
97 }
98 }
99 return conv.toPB(rv)
100 },
101 set: func(p pointer, v pref.Value) {
102 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
103 if nullable && rv.Kind() == reflect.Ptr {
104 if rv.IsNil() {
105 rv.Set(reflect.New(ft))
106 }
107 rv = rv.Elem()
108 }
109 rv.Set(conv.toGo(v))
110 if nullable && rv.Kind() == reflect.Slice && rv.IsNil() {
111 rv.Set(emptyBytes)
112 }
113 },
114 clear: func(p pointer) {
115 rv := p.apply(fieldOffset).asType(fs.Type).Elem()
116 rv.Set(reflect.Zero(rv.Type()))
117 },
118 mutable: func(p pointer) pref.Mutable {
119 panic("invalid mutable call")
120 },
121 }
122}
123
124func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
125 // TODO: support vector fields.
126 panic(fmt.Sprintf("invalid field: %v", fd))
127}
128
129// messageV1 is the protoV1.Message interface.
130type messageV1 interface {
131 Reset()
132 String() string
133 ProtoMessage()
134}
135
136var (
137 boolType = reflect.TypeOf(bool(false))
138 int32Type = reflect.TypeOf(int32(0))
139 int64Type = reflect.TypeOf(int64(0))
140 uint32Type = reflect.TypeOf(uint32(0))
141 uint64Type = reflect.TypeOf(uint64(0))
142 float32Type = reflect.TypeOf(float32(0))
143 float64Type = reflect.TypeOf(float64(0))
144 stringType = reflect.TypeOf(string(""))
145 bytesType = reflect.TypeOf([]byte(nil))
146
147 enumIfaceV2 = reflect.TypeOf((*pref.ProtoEnum)(nil)).Elem()
148 messageIfaceV1 = reflect.TypeOf((*messageV1)(nil)).Elem()
149 messageIfaceV2 = reflect.TypeOf((*pref.ProtoMessage)(nil)).Elem()
150
151 byteType = reflect.TypeOf(byte(0))
152)
153
154// matchGoTypePBKind matches a Go type with the protobuf kind.
155//
156// This matcher deliberately supports a wider range of Go types than what
157// protoc-gen-go historically generated to be able to automatically wrap some
158// v1 messages generated by other forks of protoc-gen-go.
159func matchGoTypePBKind(t reflect.Type, k pref.Kind) converter {
160 switch k {
161 case pref.BoolKind:
162 if t.Kind() == reflect.Bool {
163 return makeScalarConverter(t, boolType)
164 }
165 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
166 if t.Kind() == reflect.Int32 {
167 return makeScalarConverter(t, int32Type)
168 }
169 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
170 if t.Kind() == reflect.Int64 {
171 return makeScalarConverter(t, int64Type)
172 }
173 case pref.Uint32Kind, pref.Fixed32Kind:
174 if t.Kind() == reflect.Uint32 {
175 return makeScalarConverter(t, uint32Type)
176 }
177 case pref.Uint64Kind, pref.Fixed64Kind:
178 if t.Kind() == reflect.Uint64 {
179 return makeScalarConverter(t, uint64Type)
180 }
181 case pref.FloatKind:
182 if t.Kind() == reflect.Float32 {
183 return makeScalarConverter(t, float32Type)
184 }
185 case pref.DoubleKind:
186 if t.Kind() == reflect.Float64 {
187 return makeScalarConverter(t, float64Type)
188 }
189 case pref.StringKind:
190 if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
191 return makeScalarConverter(t, stringType)
192 }
193 case pref.BytesKind:
194 if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
195 return makeScalarConverter(t, bytesType)
196 }
197 case pref.EnumKind:
198 // Handle v2 enums, which must satisfy the proto.Enum interface.
199 if t.Kind() != reflect.Ptr && t.Implements(enumIfaceV2) {
200 // TODO: implement this.
201 }
202
203 // Handle v1 enums, which we identify as simply a named int32 type.
204 if t.Kind() == reflect.Int32 && t.PkgPath() != "" {
205 // TODO: need logic to wrap a legacy enum to implement this.
206 }
207 case pref.MessageKind, pref.GroupKind:
208 // Handle v2 messages, which must satisfy the proto.Message interface.
209 if t.Kind() == reflect.Ptr && t.Implements(messageIfaceV2) {
210 // TODO: implement this.
211 }
212
213 // Handle v1 messages, which we need to wrap as a v2 message.
214 if t.Kind() == reflect.Ptr && t.Implements(messageIfaceV1) {
215 // TODO: need logic to wrap a legacy message.
216 }
217 }
218 panic(fmt.Sprintf("invalid Go type %v for protobuf kind %v", t, k))
219}
220
221// converter provides functions for converting to/from Go reflect.Value types
222// and protobuf protoreflect.Value types.
223type converter struct {
224 toPB func(reflect.Value) pref.Value
225 toGo func(pref.Value) reflect.Value
226}
227
228func makeScalarConverter(goType, pbType reflect.Type) converter {
229 return converter{
230 toPB: func(v reflect.Value) pref.Value {
231 if v.Type() != goType {
232 panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), goType))
233 }
234 if goType.Kind() == reflect.String && pbType.Kind() == reflect.Slice && v.Len() == 0 {
235 return pref.ValueOf([]byte(nil)) // ensure empty string is []byte(nil)
236 }
237 return pref.ValueOf(v.Convert(pbType).Interface())
238 },
239 toGo: func(v pref.Value) reflect.Value {
240 rv := reflect.ValueOf(v.Interface())
241 if rv.Type() != pbType {
242 panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), pbType))
243 }
244 if pbType.Kind() == reflect.String && goType.Kind() == reflect.Slice && rv.Len() == 0 {
245 return reflect.Zero(goType) // ensure empty string is []byte(nil)
246 }
247 return rv.Convert(goType)
248 },
249 }
250}