blob: a69d2c8ad9ae7de641f55132ad37761654dbb334 [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"
Joe Tsai060cdac2019-04-22 11:44:49 -07009 "math"
Joe Tsaifa02f4e2018-09-12 16:20:37 -070010 "reflect"
11
Damien Neilc37adef2019-04-01 13:49:56 -070012 "google.golang.org/protobuf/internal/encoding/wire"
Damien Neile89e6242019-05-13 23:55:40 -070013 pvalue "google.golang.org/protobuf/internal/value"
14 pref "google.golang.org/protobuf/reflect/protoreflect"
Joe Tsaifa02f4e2018-09-12 16:20:37 -070015)
16
17type fieldInfo struct {
Damien Neilc37adef2019-04-01 13:49:56 -070018 // These fields are used for protobuf reflection support.
Damien Neil97e7f572018-12-07 14:28:33 -080019 has func(pointer) bool
20 get func(pointer) pref.Value
21 set func(pointer, pref.Value)
22 clear func(pointer)
23 newMessage func() pref.Message
Damien Neilc37adef2019-04-01 13:49:56 -070024
25 // These fields are used for fast-path functions.
26 funcs pointerCoderFuncs // fast-path per-field functions
27 num pref.FieldNumber // field number
28 offset offset // struct field offset
29 wiretag uint64 // field tag (number + wire type)
30 tagsize int // size of the varint-encoded tag
31 isPointer bool // true if IsNil may be called on the struct field
Joe Tsaifa02f4e2018-09-12 16:20:37 -070032}
33
Joe Tsaifa02f4e2018-09-12 16:20:37 -070034func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, ot reflect.Type) fieldInfo {
Joe Tsai2c870bb2018-10-17 11:46:52 -070035 ft := fs.Type
36 if ft.Kind() != reflect.Interface {
37 panic(fmt.Sprintf("invalid type: got %v, want interface kind", ft))
38 }
39 if ot.Kind() != reflect.Struct {
40 panic(fmt.Sprintf("invalid type: got %v, want struct kind", ot))
41 }
42 if !reflect.PtrTo(ot).Implements(ft) {
43 panic(fmt.Sprintf("invalid type: %v does not implement %v", ot, ft))
44 }
Joe Tsaib2f66be2019-05-22 00:42:45 -040045 conv := newConverter(ot.Field(0).Type, fd.Kind())
Joe Tsai2c870bb2018-10-17 11:46:52 -070046 fieldOffset := offsetOf(fs)
47 // TODO: Implement unsafe fast path?
48 return fieldInfo{
49 // NOTE: The logic below intentionally assumes that oneof fields are
50 // well-formatted. That is, the oneof interface never contains a
51 // typed nil pointer to one of the wrapper structs.
52
53 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -080054 if p.IsNil() {
55 return false
56 }
57 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai2c870bb2018-10-17 11:46:52 -070058 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
59 return false
60 }
61 return true
62 },
63 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -080064 if p.IsNil() {
65 return defaultValueOf(fd)
66 }
67 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai2c870bb2018-10-17 11:46:52 -070068 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
Joe Tsai6cf80c42018-12-01 04:57:09 -080069 return defaultValueOf(fd)
Joe Tsai2c870bb2018-10-17 11:46:52 -070070 }
71 rv = rv.Elem().Elem().Field(0)
Joe Tsai88bc5a72018-11-05 11:42:22 -080072 return conv.PBValueOf(rv)
Joe Tsai2c870bb2018-10-17 11:46:52 -070073 },
74 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -080075 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai2c870bb2018-10-17 11:46:52 -070076 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
77 rv.Set(reflect.New(ot))
78 }
79 rv = rv.Elem().Elem().Field(0)
Joe Tsai88bc5a72018-11-05 11:42:22 -080080 rv.Set(conv.GoValueOf(v))
Joe Tsai2c870bb2018-10-17 11:46:52 -070081 },
82 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -080083 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai2c870bb2018-10-17 11:46:52 -070084 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
85 return
86 }
87 rv.Set(reflect.Zero(rv.Type()))
88 },
Joe Tsaib2f66be2019-05-22 00:42:45 -040089 newMessage: conv.NewMessage,
90 offset: fieldOffset,
91 isPointer: true,
Joe Tsai2c870bb2018-10-17 11:46:52 -070092 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -070093}
94
95func fieldInfoForMap(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsaibbfaeb72018-10-17 00:27:21 +000096 ft := fs.Type
97 if ft.Kind() != reflect.Map {
98 panic(fmt.Sprintf("invalid type: got %v, want map kind", ft))
99 }
Joe Tsaib2f66be2019-05-22 00:42:45 -0400100 keyConv := newConverter(ft.Key(), fd.MapKey().Kind())
101 valConv := newConverter(ft.Elem(), fd.MapValue().Kind())
Damien Neilc37adef2019-04-01 13:49:56 -0700102 wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000103 fieldOffset := offsetOf(fs)
104 // TODO: Implement unsafe fast path?
105 return fieldInfo{
106 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800107 if p.IsNil() {
108 return false
109 }
110 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000111 return rv.Len() > 0
112 },
113 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800114 if p.IsNil() {
115 v := reflect.Zero(reflect.PtrTo(fs.Type)).Interface()
116 return pref.ValueOf(pvalue.MapOf(v, keyConv, valConv))
117 }
118 v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800119 return pref.ValueOf(pvalue.MapOf(v, keyConv, valConv))
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000120 },
121 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800122 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaiba0ef9a2018-11-29 14:54:05 -0800123 rv.Set(reflect.ValueOf(v.Map().(pvalue.Unwrapper).ProtoUnwrap()).Elem())
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000124 },
125 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800126 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000127 rv.Set(reflect.Zero(rv.Type()))
128 },
Damien Neilc37adef2019-04-01 13:49:56 -0700129 funcs: encoderFuncsForMap(fd, ft),
130 offset: fieldOffset,
131 wiretag: wiretag,
132 tagsize: wire.SizeVarint(wiretag),
133 isPointer: true,
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000134 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700135}
136
Joe Tsai4b7aff62018-11-14 14:05:19 -0800137func fieldInfoForList(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsai91e14662018-09-13 13:24:35 -0700138 ft := fs.Type
139 if ft.Kind() != reflect.Slice {
140 panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
141 }
Joe Tsaib2f66be2019-05-22 00:42:45 -0400142 conv := newConverter(ft.Elem(), fd.Kind())
Damien Neilc37adef2019-04-01 13:49:56 -0700143 var wiretag uint64
144 if !fd.IsPacked() {
145 wiretag = wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
146 } else {
147 wiretag = wire.EncodeTag(fd.Number(), wire.BytesType)
148 }
Joe Tsai91e14662018-09-13 13:24:35 -0700149 fieldOffset := offsetOf(fs)
150 // TODO: Implement unsafe fast path?
151 return fieldInfo{
152 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800153 if p.IsNil() {
154 return false
155 }
156 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai91e14662018-09-13 13:24:35 -0700157 return rv.Len() > 0
158 },
159 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800160 if p.IsNil() {
161 v := reflect.Zero(reflect.PtrTo(fs.Type)).Interface()
162 return pref.ValueOf(pvalue.ListOf(v, conv))
163 }
164 v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
Joe Tsai4b7aff62018-11-14 14:05:19 -0800165 return pref.ValueOf(pvalue.ListOf(v, conv))
Joe Tsai91e14662018-09-13 13:24:35 -0700166 },
167 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800168 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaiba0ef9a2018-11-29 14:54:05 -0800169 rv.Set(reflect.ValueOf(v.List().(pvalue.Unwrapper).ProtoUnwrap()).Elem())
Joe Tsai91e14662018-09-13 13:24:35 -0700170 },
171 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800172 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai91e14662018-09-13 13:24:35 -0700173 rv.Set(reflect.Zero(rv.Type()))
174 },
Damien Neilc37adef2019-04-01 13:49:56 -0700175 funcs: fieldCoder(fd, ft),
176 offset: fieldOffset,
177 wiretag: wiretag,
178 tagsize: wire.SizeVarint(wiretag),
179 isPointer: true,
Joe Tsai91e14662018-09-13 13:24:35 -0700180 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700181}
182
183var emptyBytes = reflect.ValueOf([]byte{})
184
185func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
186 ft := fs.Type
Damien Neilc37adef2019-04-01 13:49:56 -0700187 funcs := fieldCoder(fd, ft)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700188 nullable := fd.Syntax() == pref.Proto2
189 if nullable {
190 if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
191 panic(fmt.Sprintf("invalid type: got %v, want pointer", ft))
192 }
193 if ft.Kind() == reflect.Ptr {
194 ft = ft.Elem()
195 }
196 }
Joe Tsaib2f66be2019-05-22 00:42:45 -0400197 conv := newConverter(ft, fd.Kind())
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700198 fieldOffset := offsetOf(fs)
Damien Neilc37adef2019-04-01 13:49:56 -0700199 wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700200 // TODO: Implement unsafe fast path?
201 return fieldInfo{
202 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800203 if p.IsNil() {
204 return false
205 }
206 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700207 if nullable {
208 return !rv.IsNil()
209 }
210 switch rv.Kind() {
211 case reflect.Bool:
212 return rv.Bool()
213 case reflect.Int32, reflect.Int64:
Joe Tsai44e389c2018-11-19 15:27:09 -0800214 return rv.Int() != 0
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700215 case reflect.Uint32, reflect.Uint64:
Joe Tsai44e389c2018-11-19 15:27:09 -0800216 return rv.Uint() != 0
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700217 case reflect.Float32, reflect.Float64:
Joe Tsai060cdac2019-04-22 11:44:49 -0700218 return rv.Float() != 0 || math.Signbit(rv.Float())
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700219 case reflect.String, reflect.Slice:
220 return rv.Len() > 0
221 default:
222 panic(fmt.Sprintf("invalid type: %v", rv.Type())) // should never happen
223 }
224 },
225 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800226 if p.IsNil() {
227 return defaultValueOf(fd)
228 }
229 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700230 if nullable {
231 if rv.IsNil() {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800232 return defaultValueOf(fd)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700233 }
234 if rv.Kind() == reflect.Ptr {
235 rv = rv.Elem()
236 }
237 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800238 return conv.PBValueOf(rv)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700239 },
240 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800241 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700242 if nullable && rv.Kind() == reflect.Ptr {
243 if rv.IsNil() {
244 rv.Set(reflect.New(ft))
245 }
246 rv = rv.Elem()
247 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800248 rv.Set(conv.GoValueOf(v))
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700249 if nullable && rv.Kind() == reflect.Slice && rv.IsNil() {
250 rv.Set(emptyBytes)
251 }
252 },
253 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800254 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700255 rv.Set(reflect.Zero(rv.Type()))
256 },
Damien Neilc37adef2019-04-01 13:49:56 -0700257 funcs: funcs,
258 offset: fieldOffset,
259 isPointer: nullable,
260 wiretag: wiretag,
261 tagsize: wire.SizeVarint(wiretag),
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700262 }
263}
264
265func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsaice6edd32018-10-19 16:27:46 -0700266 ft := fs.Type
Joe Tsaib2f66be2019-05-22 00:42:45 -0400267 conv := newConverter(ft, fd.Kind())
Joe Tsaice6edd32018-10-19 16:27:46 -0700268 fieldOffset := offsetOf(fs)
269 // TODO: Implement unsafe fast path?
Damien Neilc37adef2019-04-01 13:49:56 -0700270 wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
Joe Tsaice6edd32018-10-19 16:27:46 -0700271 return fieldInfo{
272 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800273 if p.IsNil() {
274 return false
275 }
276 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaice6edd32018-10-19 16:27:46 -0700277 return !rv.IsNil()
278 },
279 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800280 if p.IsNil() {
281 return pref.Value{}
282 }
283 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaif6d4a422018-11-19 14:26:06 -0800284 if rv.IsNil() {
285 return pref.Value{}
286 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800287 return conv.PBValueOf(rv)
Joe Tsaice6edd32018-10-19 16:27:46 -0700288 },
289 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800290 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai88bc5a72018-11-05 11:42:22 -0800291 rv.Set(conv.GoValueOf(v))
Joe Tsaif6d4a422018-11-19 14:26:06 -0800292 if rv.IsNil() {
293 panic("invalid nil pointer")
294 }
Joe Tsaice6edd32018-10-19 16:27:46 -0700295 },
296 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800297 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaice6edd32018-10-19 16:27:46 -0700298 rv.Set(reflect.Zero(rv.Type()))
299 },
Joe Tsaib2f66be2019-05-22 00:42:45 -0400300 newMessage: conv.NewMessage,
301 funcs: fieldCoder(fd, ft),
302 offset: fieldOffset,
303 isPointer: true,
304 wiretag: wiretag,
305 tagsize: wire.SizeVarint(wiretag),
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700306 }
307}
Joe Tsai6cf80c42018-12-01 04:57:09 -0800308
309// defaultValueOf returns the default value for the field.
310func defaultValueOf(fd pref.FieldDescriptor) pref.Value {
311 if fd == nil {
312 return pref.Value{}
313 }
314 pv := fd.Default() // invalid Value for messages and repeated fields
315 if fd.Kind() == pref.BytesKind && pv.IsValid() && len(pv.Bytes()) > 0 {
316 return pref.ValueOf(append([]byte(nil), pv.Bytes()...)) // copy default bytes for safety
317 }
318 return pv
319}
Joe Tsai4ec39c72019-04-03 13:40:53 -0700320
321type oneofInfo struct {
322 which func(pointer) pref.FieldNumber
323}
324
325func makeOneofInfo(od pref.OneofDescriptor, fs reflect.StructField, wrappersByType map[reflect.Type]pref.FieldNumber) *oneofInfo {
326 fieldOffset := offsetOf(fs)
327 return &oneofInfo{
328 which: func(p pointer) pref.FieldNumber {
329 if p.IsNil() {
330 return 0
331 }
332 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
333 if rv.IsNil() {
334 return 0
335 }
336 return wrappersByType[rv.Elem().Type().Elem()]
337 },
338 }
339}
Joe Tsaib2f66be2019-05-22 00:42:45 -0400340
341func newConverter(t reflect.Type, k pref.Kind) pvalue.Converter {
342 if legacyWrapper != nil {
343 return legacyWrapper.NewConverter(t, k)
344 }
345 return pvalue.NewConverter(t, k)
346}