blob: 72f45230bc7a5008f1280d275d6957ccff24adec [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 Tsai08e00302018-11-26 22:32:06 -080045 conv := pvalue.NewLegacyConverter(ot.Field(0).Type, fd.Kind(), legacyWrapper)
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 },
Damien Neil97e7f572018-12-07 14:28:33 -080089 newMessage: func() pref.Message {
90 // This is only valid for messages and panics for other kinds.
Joe Tsai3bc7d6f2019-01-09 02:57:13 -080091 return conv.MessageType.New()
Joe Tsai2c870bb2018-10-17 11:46:52 -070092 },
Damien Neilc37adef2019-04-01 13:49:56 -070093 offset: fieldOffset,
94 isPointer: true,
Joe Tsai2c870bb2018-10-17 11:46:52 -070095 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -070096}
97
98func fieldInfoForMap(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsaibbfaeb72018-10-17 00:27:21 +000099 ft := fs.Type
100 if ft.Kind() != reflect.Map {
101 panic(fmt.Sprintf("invalid type: got %v, want map kind", ft))
102 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700103 keyConv := pvalue.NewLegacyConverter(ft.Key(), fd.MapKey().Kind(), legacyWrapper)
104 valConv := pvalue.NewLegacyConverter(ft.Elem(), fd.MapValue().Kind(), legacyWrapper)
Damien Neilc37adef2019-04-01 13:49:56 -0700105 wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000106 fieldOffset := offsetOf(fs)
107 // TODO: Implement unsafe fast path?
108 return fieldInfo{
109 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800110 if p.IsNil() {
111 return false
112 }
113 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000114 return rv.Len() > 0
115 },
116 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800117 if p.IsNil() {
118 v := reflect.Zero(reflect.PtrTo(fs.Type)).Interface()
119 return pref.ValueOf(pvalue.MapOf(v, keyConv, valConv))
120 }
121 v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800122 return pref.ValueOf(pvalue.MapOf(v, keyConv, valConv))
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000123 },
124 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800125 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaiba0ef9a2018-11-29 14:54:05 -0800126 rv.Set(reflect.ValueOf(v.Map().(pvalue.Unwrapper).ProtoUnwrap()).Elem())
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000127 },
128 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800129 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000130 rv.Set(reflect.Zero(rv.Type()))
131 },
Damien Neilc37adef2019-04-01 13:49:56 -0700132 funcs: encoderFuncsForMap(fd, ft),
133 offset: fieldOffset,
134 wiretag: wiretag,
135 tagsize: wire.SizeVarint(wiretag),
136 isPointer: true,
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000137 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700138}
139
Joe Tsai4b7aff62018-11-14 14:05:19 -0800140func fieldInfoForList(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsai91e14662018-09-13 13:24:35 -0700141 ft := fs.Type
142 if ft.Kind() != reflect.Slice {
143 panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
144 }
Joe Tsai08e00302018-11-26 22:32:06 -0800145 conv := pvalue.NewLegacyConverter(ft.Elem(), fd.Kind(), legacyWrapper)
Damien Neilc37adef2019-04-01 13:49:56 -0700146 var wiretag uint64
147 if !fd.IsPacked() {
148 wiretag = wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
149 } else {
150 wiretag = wire.EncodeTag(fd.Number(), wire.BytesType)
151 }
Joe Tsai91e14662018-09-13 13:24:35 -0700152 fieldOffset := offsetOf(fs)
153 // TODO: Implement unsafe fast path?
154 return fieldInfo{
155 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800156 if p.IsNil() {
157 return false
158 }
159 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai91e14662018-09-13 13:24:35 -0700160 return rv.Len() > 0
161 },
162 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800163 if p.IsNil() {
164 v := reflect.Zero(reflect.PtrTo(fs.Type)).Interface()
165 return pref.ValueOf(pvalue.ListOf(v, conv))
166 }
167 v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
Joe Tsai4b7aff62018-11-14 14:05:19 -0800168 return pref.ValueOf(pvalue.ListOf(v, conv))
Joe Tsai91e14662018-09-13 13:24:35 -0700169 },
170 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800171 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaiba0ef9a2018-11-29 14:54:05 -0800172 rv.Set(reflect.ValueOf(v.List().(pvalue.Unwrapper).ProtoUnwrap()).Elem())
Joe Tsai91e14662018-09-13 13:24:35 -0700173 },
174 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800175 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai91e14662018-09-13 13:24:35 -0700176 rv.Set(reflect.Zero(rv.Type()))
177 },
Damien Neilc37adef2019-04-01 13:49:56 -0700178 funcs: fieldCoder(fd, ft),
179 offset: fieldOffset,
180 wiretag: wiretag,
181 tagsize: wire.SizeVarint(wiretag),
182 isPointer: true,
Joe Tsai91e14662018-09-13 13:24:35 -0700183 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700184}
185
186var emptyBytes = reflect.ValueOf([]byte{})
187
188func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
189 ft := fs.Type
Damien Neilc37adef2019-04-01 13:49:56 -0700190 funcs := fieldCoder(fd, ft)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700191 nullable := fd.Syntax() == pref.Proto2
192 if nullable {
193 if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
194 panic(fmt.Sprintf("invalid type: got %v, want pointer", ft))
195 }
196 if ft.Kind() == reflect.Ptr {
197 ft = ft.Elem()
198 }
199 }
Joe Tsai08e00302018-11-26 22:32:06 -0800200 conv := pvalue.NewLegacyConverter(ft, fd.Kind(), legacyWrapper)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700201 fieldOffset := offsetOf(fs)
Damien Neilc37adef2019-04-01 13:49:56 -0700202 wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700203 // TODO: Implement unsafe fast path?
204 return fieldInfo{
205 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800206 if p.IsNil() {
207 return false
208 }
209 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700210 if nullable {
211 return !rv.IsNil()
212 }
213 switch rv.Kind() {
214 case reflect.Bool:
215 return rv.Bool()
216 case reflect.Int32, reflect.Int64:
Joe Tsai44e389c2018-11-19 15:27:09 -0800217 return rv.Int() != 0
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700218 case reflect.Uint32, reflect.Uint64:
Joe Tsai44e389c2018-11-19 15:27:09 -0800219 return rv.Uint() != 0
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700220 case reflect.Float32, reflect.Float64:
Joe Tsai060cdac2019-04-22 11:44:49 -0700221 return rv.Float() != 0 || math.Signbit(rv.Float())
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700222 case reflect.String, reflect.Slice:
223 return rv.Len() > 0
224 default:
225 panic(fmt.Sprintf("invalid type: %v", rv.Type())) // should never happen
226 }
227 },
228 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800229 if p.IsNil() {
230 return defaultValueOf(fd)
231 }
232 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700233 if nullable {
234 if rv.IsNil() {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800235 return defaultValueOf(fd)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700236 }
237 if rv.Kind() == reflect.Ptr {
238 rv = rv.Elem()
239 }
240 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800241 return conv.PBValueOf(rv)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700242 },
243 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800244 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700245 if nullable && rv.Kind() == reflect.Ptr {
246 if rv.IsNil() {
247 rv.Set(reflect.New(ft))
248 }
249 rv = rv.Elem()
250 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800251 rv.Set(conv.GoValueOf(v))
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700252 if nullable && rv.Kind() == reflect.Slice && rv.IsNil() {
253 rv.Set(emptyBytes)
254 }
255 },
256 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800257 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700258 rv.Set(reflect.Zero(rv.Type()))
259 },
Damien Neilc37adef2019-04-01 13:49:56 -0700260 funcs: funcs,
261 offset: fieldOffset,
262 isPointer: nullable,
263 wiretag: wiretag,
264 tagsize: wire.SizeVarint(wiretag),
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700265 }
266}
267
268func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsaice6edd32018-10-19 16:27:46 -0700269 ft := fs.Type
Joe Tsai08e00302018-11-26 22:32:06 -0800270 conv := pvalue.NewLegacyConverter(ft, fd.Kind(), legacyWrapper)
Joe Tsaice6edd32018-10-19 16:27:46 -0700271 fieldOffset := offsetOf(fs)
272 // TODO: Implement unsafe fast path?
Damien Neilc37adef2019-04-01 13:49:56 -0700273 wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
Joe Tsaice6edd32018-10-19 16:27:46 -0700274 return fieldInfo{
275 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800276 if p.IsNil() {
277 return false
278 }
279 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaice6edd32018-10-19 16:27:46 -0700280 return !rv.IsNil()
281 },
282 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800283 if p.IsNil() {
284 return pref.Value{}
285 }
286 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaif6d4a422018-11-19 14:26:06 -0800287 if rv.IsNil() {
288 return pref.Value{}
289 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800290 return conv.PBValueOf(rv)
Joe Tsaice6edd32018-10-19 16:27:46 -0700291 },
292 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800293 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai88bc5a72018-11-05 11:42:22 -0800294 rv.Set(conv.GoValueOf(v))
Joe Tsaif6d4a422018-11-19 14:26:06 -0800295 if rv.IsNil() {
296 panic("invalid nil pointer")
297 }
Joe Tsaice6edd32018-10-19 16:27:46 -0700298 },
299 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800300 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaice6edd32018-10-19 16:27:46 -0700301 rv.Set(reflect.Zero(rv.Type()))
302 },
Damien Neil97e7f572018-12-07 14:28:33 -0800303 newMessage: func() pref.Message {
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800304 return conv.MessageType.New()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700305 },
Damien Neilc37adef2019-04-01 13:49:56 -0700306 funcs: fieldCoder(fd, ft),
307 offset: fieldOffset,
308 isPointer: true,
309 wiretag: wiretag,
310 tagsize: wire.SizeVarint(wiretag),
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700311 }
312}
Joe Tsai6cf80c42018-12-01 04:57:09 -0800313
314// defaultValueOf returns the default value for the field.
315func defaultValueOf(fd pref.FieldDescriptor) pref.Value {
316 if fd == nil {
317 return pref.Value{}
318 }
319 pv := fd.Default() // invalid Value for messages and repeated fields
320 if fd.Kind() == pref.BytesKind && pv.IsValid() && len(pv.Bytes()) > 0 {
321 return pref.ValueOf(append([]byte(nil), pv.Bytes()...)) // copy default bytes for safety
322 }
323 return pv
324}
Joe Tsai4ec39c72019-04-03 13:40:53 -0700325
326type oneofInfo struct {
327 which func(pointer) pref.FieldNumber
328}
329
330func makeOneofInfo(od pref.OneofDescriptor, fs reflect.StructField, wrappersByType map[reflect.Type]pref.FieldNumber) *oneofInfo {
331 fieldOffset := offsetOf(fs)
332 return &oneofInfo{
333 which: func(p pointer) pref.FieldNumber {
334 if p.IsNil() {
335 return 0
336 }
337 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
338 if rv.IsNil() {
339 return 0
340 }
341 return wrappersByType[rv.Elem().Type().Elem()]
342 },
343 }
344}