blob: e55b6dec1f7ccc246865e8bb3f474b3d5a1a33b9 [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"
Joe Tsaiafd36332019-08-05 13:20:14 -070011 "sync"
Joe Tsaifa02f4e2018-09-12 16:20:37 -070012
Joe Tsai3d8e3692019-04-08 13:52:14 -070013 "google.golang.org/protobuf/internal/flags"
Damien Neile89e6242019-05-13 23:55:40 -070014 pref "google.golang.org/protobuf/reflect/protoreflect"
Joe Tsai3d8e3692019-04-08 13:52:14 -070015 preg "google.golang.org/protobuf/reflect/protoregistry"
Joe Tsai21ade492019-05-22 13:42:54 -040016 piface "google.golang.org/protobuf/runtime/protoiface"
Joe Tsaifa02f4e2018-09-12 16:20:37 -070017)
18
19type fieldInfo struct {
Joe Tsai378c1322019-04-25 23:48:08 -070020 fieldDesc pref.FieldDescriptor
21
Damien Neilc37adef2019-04-01 13:49:56 -070022 // These fields are used for protobuf reflection support.
Damien Neil97e7f572018-12-07 14:28:33 -080023 has func(pointer) bool
Joe Tsai378c1322019-04-25 23:48:08 -070024 clear func(pointer)
Damien Neil97e7f572018-12-07 14:28:33 -080025 get func(pointer) pref.Value
26 set func(pointer, pref.Value)
Joe Tsai378c1322019-04-25 23:48:08 -070027 mutable func(pointer) pref.Value
Damien Neil97e7f572018-12-07 14:28:33 -080028 newMessage func() pref.Message
Damien Neilf5274512019-08-05 10:48:38 -070029 newField func() pref.Value
Joe Tsaifa02f4e2018-09-12 16:20:37 -070030}
31
Joe Tsaic0e4bb22019-07-06 13:05:11 -070032func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, x exporter, ot reflect.Type) fieldInfo {
Joe Tsai2c870bb2018-10-17 11:46:52 -070033 ft := fs.Type
34 if ft.Kind() != reflect.Interface {
35 panic(fmt.Sprintf("invalid type: got %v, want interface kind", ft))
36 }
37 if ot.Kind() != reflect.Struct {
38 panic(fmt.Sprintf("invalid type: got %v, want struct kind", ot))
39 }
40 if !reflect.PtrTo(ot).Implements(ft) {
41 panic(fmt.Sprintf("invalid type: %v does not implement %v", ot, ft))
42 }
Damien Neil954bd922019-07-17 16:52:10 -070043 conv := NewConverter(ot.Field(0).Type, fd)
44 isMessage := fd.Message() != nil
Joe Tsai378c1322019-04-25 23:48:08 -070045
Joe Tsai2c870bb2018-10-17 11:46:52 -070046 // TODO: Implement unsafe fast path?
Joe Tsaic0e4bb22019-07-06 13:05:11 -070047 fieldOffset := offsetOf(fs, x)
Joe Tsai2c870bb2018-10-17 11:46:52 -070048 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
Joe Tsai378c1322019-04-25 23:48:08 -070053 fieldDesc: fd,
Joe Tsai2c870bb2018-10-17 11:46:52 -070054 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -080055 if p.IsNil() {
56 return false
57 }
58 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai9b22b932019-08-08 19:23:32 -070059 if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
Joe Tsai2c870bb2018-10-17 11:46:52 -070060 return false
61 }
62 return true
63 },
Joe Tsai378c1322019-04-25 23:48:08 -070064 clear: func(p pointer) {
65 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
66 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
Joe Tsai9b22b932019-08-08 19:23:32 -070067 // NOTE: We intentionally don't check for rv.Elem().IsNil()
68 // so that (*OneofWrapperType)(nil) gets cleared to nil.
Joe Tsai378c1322019-04-25 23:48:08 -070069 return
70 }
71 rv.Set(reflect.Zero(rv.Type()))
72 },
Joe Tsai2c870bb2018-10-17 11:46:52 -070073 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -080074 if p.IsNil() {
Damien Neild4f08002019-08-07 12:21:41 -070075 return conv.Zero()
Joe Tsai6cf80c42018-12-01 04:57:09 -080076 }
77 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai9b22b932019-08-08 19:23:32 -070078 if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
Damien Neild4f08002019-08-07 12:21:41 -070079 return conv.Zero()
Joe Tsai2c870bb2018-10-17 11:46:52 -070080 }
81 rv = rv.Elem().Elem().Field(0)
Joe Tsai88bc5a72018-11-05 11:42:22 -080082 return conv.PBValueOf(rv)
Joe Tsai2c870bb2018-10-17 11:46:52 -070083 },
84 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -080085 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai9b22b932019-08-08 19:23:32 -070086 if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
Joe Tsai2c870bb2018-10-17 11:46:52 -070087 rv.Set(reflect.New(ot))
88 }
89 rv = rv.Elem().Elem().Field(0)
Joe Tsai88bc5a72018-11-05 11:42:22 -080090 rv.Set(conv.GoValueOf(v))
Joe Tsai2c870bb2018-10-17 11:46:52 -070091 },
Joe Tsai378c1322019-04-25 23:48:08 -070092 mutable: func(p pointer) pref.Value {
Damien Neil954bd922019-07-17 16:52:10 -070093 if !isMessage {
Joe Tsai378c1322019-04-25 23:48:08 -070094 panic("invalid Mutable on field with non-composite type")
95 }
Joe Tsai6cf80c42018-12-01 04:57:09 -080096 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai9b22b932019-08-08 19:23:32 -070097 if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
Joe Tsai378c1322019-04-25 23:48:08 -070098 rv.Set(reflect.New(ot))
Joe Tsai2c870bb2018-10-17 11:46:52 -070099 }
Joe Tsai378c1322019-04-25 23:48:08 -0700100 rv = rv.Elem().Elem().Field(0)
101 if rv.IsNil() {
Damien Neil954bd922019-07-17 16:52:10 -0700102 rv.Set(conv.GoValueOf(pref.ValueOf(conv.New().Message())))
Joe Tsai378c1322019-04-25 23:48:08 -0700103 }
104 return conv.PBValueOf(rv)
Joe Tsai2c870bb2018-10-17 11:46:52 -0700105 },
Damien Neil954bd922019-07-17 16:52:10 -0700106 newMessage: func() pref.Message {
107 return conv.New().Message()
108 },
Damien Neilf5274512019-08-05 10:48:38 -0700109 newField: func() pref.Value {
110 return conv.New()
111 },
Joe Tsai2c870bb2018-10-17 11:46:52 -0700112 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700113}
114
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700115func fieldInfoForMap(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000116 ft := fs.Type
117 if ft.Kind() != reflect.Map {
118 panic(fmt.Sprintf("invalid type: got %v, want map kind", ft))
119 }
Damien Neil954bd922019-07-17 16:52:10 -0700120 conv := NewConverter(ft, fd)
Joe Tsai378c1322019-04-25 23:48:08 -0700121
Joe Tsai91e14662018-09-13 13:24:35 -0700122 // TODO: Implement unsafe fast path?
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700123 fieldOffset := offsetOf(fs, x)
Joe Tsai91e14662018-09-13 13:24:35 -0700124 return fieldInfo{
Joe Tsai378c1322019-04-25 23:48:08 -0700125 fieldDesc: fd,
Joe Tsai91e14662018-09-13 13:24:35 -0700126 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800127 if p.IsNil() {
128 return false
129 }
130 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai91e14662018-09-13 13:24:35 -0700131 return rv.Len() > 0
132 },
Joe Tsai378c1322019-04-25 23:48:08 -0700133 clear: func(p pointer) {
134 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
135 rv.Set(reflect.Zero(rv.Type()))
136 },
Joe Tsai91e14662018-09-13 13:24:35 -0700137 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800138 if p.IsNil() {
Damien Neild4f08002019-08-07 12:21:41 -0700139 return conv.Zero()
Joe Tsai6cf80c42018-12-01 04:57:09 -0800140 }
Joe Tsai378c1322019-04-25 23:48:08 -0700141 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Damien Neil954bd922019-07-17 16:52:10 -0700142 return conv.PBValueOf(rv)
Joe Tsai91e14662018-09-13 13:24:35 -0700143 },
144 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800145 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Damien Neil954bd922019-07-17 16:52:10 -0700146 rv.Set(conv.GoValueOf(v))
Joe Tsai91e14662018-09-13 13:24:35 -0700147 },
Joe Tsai378c1322019-04-25 23:48:08 -0700148 mutable: func(p pointer) pref.Value {
Damien Neil954bd922019-07-17 16:52:10 -0700149 v := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
150 if v.IsNil() {
151 v.Set(reflect.MakeMap(fs.Type))
152 }
153 return conv.PBValueOf(v)
154 },
Damien Neilf5274512019-08-05 10:48:38 -0700155 newField: func() pref.Value {
156 return conv.New()
157 },
Damien Neil954bd922019-07-17 16:52:10 -0700158 }
159}
160
161func fieldInfoForList(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
162 ft := fs.Type
163 if ft.Kind() != reflect.Slice {
164 panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
165 }
166 conv := NewConverter(reflect.PtrTo(ft), fd)
Damien Neil954bd922019-07-17 16:52:10 -0700167
168 // TODO: Implement unsafe fast path?
169 fieldOffset := offsetOf(fs, x)
170 return fieldInfo{
171 fieldDesc: fd,
172 has: func(p pointer) bool {
173 if p.IsNil() {
174 return false
175 }
176 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
177 return rv.Len() > 0
178 },
179 clear: func(p pointer) {
180 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
181 rv.Set(reflect.Zero(rv.Type()))
182 },
183 get: func(p pointer) pref.Value {
184 if p.IsNil() {
Damien Neild4f08002019-08-07 12:21:41 -0700185 return conv.Zero()
Damien Neil954bd922019-07-17 16:52:10 -0700186 }
187 rv := p.Apply(fieldOffset).AsValueOf(fs.Type)
Damien Neil954bd922019-07-17 16:52:10 -0700188 return conv.PBValueOf(rv)
189 },
190 set: func(p pointer, v pref.Value) {
191 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifd528ff2019-09-03 16:30:39 -0700192 rv.Set(reflect.ValueOf(v.List().(unwrapper).protoUnwrap()).Elem())
Damien Neil954bd922019-07-17 16:52:10 -0700193 },
194 mutable: func(p pointer) pref.Value {
195 v := p.Apply(fieldOffset).AsValueOf(fs.Type)
196 return conv.PBValueOf(v)
Joe Tsai91e14662018-09-13 13:24:35 -0700197 },
Damien Neilf5274512019-08-05 10:48:38 -0700198 newField: func() pref.Value {
199 return conv.New()
200 },
Joe Tsai91e14662018-09-13 13:24:35 -0700201 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700202}
203
Joe Tsai3e6a39b2019-07-10 10:21:12 -0700204var (
205 nilBytes = reflect.ValueOf([]byte(nil))
206 emptyBytes = reflect.ValueOf([]byte{})
207)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700208
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700209func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700210 ft := fs.Type
211 nullable := fd.Syntax() == pref.Proto2
Joe Tsai3e6a39b2019-07-10 10:21:12 -0700212 isBytes := ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700213 if nullable {
214 if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
215 panic(fmt.Sprintf("invalid type: got %v, want pointer", ft))
216 }
217 if ft.Kind() == reflect.Ptr {
218 ft = ft.Elem()
219 }
220 }
Damien Neil954bd922019-07-17 16:52:10 -0700221 conv := NewConverter(ft, fd)
Joe Tsai378c1322019-04-25 23:48:08 -0700222
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700223 // TODO: Implement unsafe fast path?
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700224 fieldOffset := offsetOf(fs, x)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700225 return fieldInfo{
Joe Tsai378c1322019-04-25 23:48:08 -0700226 fieldDesc: fd,
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700227 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800228 if p.IsNil() {
229 return false
230 }
231 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700232 if nullable {
233 return !rv.IsNil()
234 }
235 switch rv.Kind() {
236 case reflect.Bool:
237 return rv.Bool()
238 case reflect.Int32, reflect.Int64:
Joe Tsai44e389c2018-11-19 15:27:09 -0800239 return rv.Int() != 0
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700240 case reflect.Uint32, reflect.Uint64:
Joe Tsai44e389c2018-11-19 15:27:09 -0800241 return rv.Uint() != 0
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700242 case reflect.Float32, reflect.Float64:
Joe Tsai060cdac2019-04-22 11:44:49 -0700243 return rv.Float() != 0 || math.Signbit(rv.Float())
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700244 case reflect.String, reflect.Slice:
245 return rv.Len() > 0
246 default:
247 panic(fmt.Sprintf("invalid type: %v", rv.Type())) // should never happen
248 }
249 },
Joe Tsai378c1322019-04-25 23:48:08 -0700250 clear: func(p pointer) {
251 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
252 rv.Set(reflect.Zero(rv.Type()))
253 },
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700254 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800255 if p.IsNil() {
Damien Neild4f08002019-08-07 12:21:41 -0700256 return conv.Zero()
Joe Tsai6cf80c42018-12-01 04:57:09 -0800257 }
258 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700259 if nullable {
260 if rv.IsNil() {
Damien Neild4f08002019-08-07 12:21:41 -0700261 return conv.Zero()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700262 }
263 if rv.Kind() == reflect.Ptr {
264 rv = rv.Elem()
265 }
266 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800267 return conv.PBValueOf(rv)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700268 },
269 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800270 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700271 if nullable && rv.Kind() == reflect.Ptr {
272 if rv.IsNil() {
273 rv.Set(reflect.New(ft))
274 }
275 rv = rv.Elem()
276 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800277 rv.Set(conv.GoValueOf(v))
Joe Tsai3e6a39b2019-07-10 10:21:12 -0700278 if isBytes && rv.Len() == 0 {
279 if nullable {
280 rv.Set(emptyBytes) // preserve presence in proto2
281 } else {
282 rv.Set(nilBytes) // do not preserve presence in proto3
283 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700284 }
285 },
Damien Neilf5274512019-08-05 10:48:38 -0700286 newField: func() pref.Value {
287 return conv.New()
288 },
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700289 }
290}
291
Joe Tsai3d8e3692019-04-08 13:52:14 -0700292func fieldInfoForWeakMessage(fd pref.FieldDescriptor, weakOffset offset) fieldInfo {
Joe Tsai1799d112019-08-08 13:31:59 -0700293 if !flags.ProtoLegacy {
Joe Tsai3d8e3692019-04-08 13:52:14 -0700294 panic("no support for proto1 weak fields")
295 }
296
Joe Tsaiafd36332019-08-05 13:20:14 -0700297 var once sync.Once
298 var messageType pref.MessageType
Joe Tsaiafd36332019-08-05 13:20:14 -0700299 lazyInit := func() {
300 once.Do(func() {
301 messageName := fd.Message().FullName()
302 messageType, _ = preg.GlobalTypes.FindMessageByName(messageName)
303 if messageType == nil {
Joe Tsai3d8e3692019-04-08 13:52:14 -0700304 panic(fmt.Sprintf("weak message %v is not linked in", messageName))
Joe Tsaiafd36332019-08-05 13:20:14 -0700305 }
Joe Tsaiafd36332019-08-05 13:20:14 -0700306 })
Joe Tsai3d8e3692019-04-08 13:52:14 -0700307 }
308
309 num := int32(fd.Number())
Joe Tsai3d8e3692019-04-08 13:52:14 -0700310 return fieldInfo{
311 fieldDesc: fd,
312 has: func(p pointer) bool {
313 if p.IsNil() {
314 return false
315 }
316 fs := p.Apply(weakOffset).WeakFields()
317 _, ok := (*fs)[num]
318 return ok
319 },
320 clear: func(p pointer) {
321 fs := p.Apply(weakOffset).WeakFields()
322 delete(*fs, num)
323 },
324 get: func(p pointer) pref.Value {
Joe Tsaiafd36332019-08-05 13:20:14 -0700325 lazyInit()
Joe Tsai3d8e3692019-04-08 13:52:14 -0700326 if p.IsNil() {
Damien Neild4f08002019-08-07 12:21:41 -0700327 return pref.ValueOf(messageType.Zero())
Joe Tsai3d8e3692019-04-08 13:52:14 -0700328 }
329 fs := p.Apply(weakOffset).WeakFields()
330 m, ok := (*fs)[num]
331 if !ok {
Damien Neild4f08002019-08-07 12:21:41 -0700332 return pref.ValueOf(messageType.Zero())
Joe Tsai3d8e3692019-04-08 13:52:14 -0700333 }
334 return pref.ValueOf(m.(pref.ProtoMessage).ProtoReflect())
335 },
336 set: func(p pointer, v pref.Value) {
Joe Tsaiafd36332019-08-05 13:20:14 -0700337 lazyInit()
Joe Tsai3d8e3692019-04-08 13:52:14 -0700338 m := v.Message()
339 if m.Descriptor() != messageType.Descriptor() {
340 panic("mismatching message descriptor")
341 }
342 fs := p.Apply(weakOffset).WeakFields()
343 if *fs == nil {
344 *fs = make(WeakFields)
345 }
346 (*fs)[num] = m.Interface().(piface.MessageV1)
347 },
348 mutable: func(p pointer) pref.Value {
Joe Tsaiafd36332019-08-05 13:20:14 -0700349 lazyInit()
Joe Tsai3d8e3692019-04-08 13:52:14 -0700350 fs := p.Apply(weakOffset).WeakFields()
351 if *fs == nil {
352 *fs = make(WeakFields)
353 }
354 m, ok := (*fs)[num]
355 if !ok {
356 m = messageType.New().Interface().(piface.MessageV1)
357 (*fs)[num] = m
358 }
359 return pref.ValueOf(m.(pref.ProtoMessage).ProtoReflect())
360 },
361 newMessage: func() pref.Message {
Joe Tsaiafd36332019-08-05 13:20:14 -0700362 lazyInit()
Joe Tsai3d8e3692019-04-08 13:52:14 -0700363 return messageType.New()
364 },
Damien Neilf5274512019-08-05 10:48:38 -0700365 newField: func() pref.Value {
366 lazyInit()
367 return pref.ValueOf(messageType.New())
368 },
Joe Tsai3d8e3692019-04-08 13:52:14 -0700369 }
370}
371
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700372func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
Joe Tsaice6edd32018-10-19 16:27:46 -0700373 ft := fs.Type
Damien Neil954bd922019-07-17 16:52:10 -0700374 conv := NewConverter(ft, fd)
Joe Tsai378c1322019-04-25 23:48:08 -0700375
376 // TODO: Implement unsafe fast path?
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700377 fieldOffset := offsetOf(fs, x)
Joe Tsaice6edd32018-10-19 16:27:46 -0700378 return fieldInfo{
Joe Tsai378c1322019-04-25 23:48:08 -0700379 fieldDesc: fd,
Joe Tsaice6edd32018-10-19 16:27:46 -0700380 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800381 if p.IsNil() {
382 return false
383 }
384 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaice6edd32018-10-19 16:27:46 -0700385 return !rv.IsNil()
386 },
Joe Tsai378c1322019-04-25 23:48:08 -0700387 clear: func(p pointer) {
388 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
389 rv.Set(reflect.Zero(rv.Type()))
390 },
Joe Tsaice6edd32018-10-19 16:27:46 -0700391 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800392 if p.IsNil() {
Damien Neild4f08002019-08-07 12:21:41 -0700393 return conv.Zero()
Joe Tsai6cf80c42018-12-01 04:57:09 -0800394 }
395 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai88bc5a72018-11-05 11:42:22 -0800396 return conv.PBValueOf(rv)
Joe Tsaice6edd32018-10-19 16:27:46 -0700397 },
398 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800399 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai88bc5a72018-11-05 11:42:22 -0800400 rv.Set(conv.GoValueOf(v))
Joe Tsaif6d4a422018-11-19 14:26:06 -0800401 if rv.IsNil() {
402 panic("invalid nil pointer")
403 }
Joe Tsaice6edd32018-10-19 16:27:46 -0700404 },
Joe Tsai378c1322019-04-25 23:48:08 -0700405 mutable: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800406 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai378c1322019-04-25 23:48:08 -0700407 if rv.IsNil() {
Damien Neil954bd922019-07-17 16:52:10 -0700408 rv.Set(conv.GoValueOf(conv.New()))
Joe Tsai378c1322019-04-25 23:48:08 -0700409 }
410 return conv.PBValueOf(rv)
Joe Tsaice6edd32018-10-19 16:27:46 -0700411 },
Damien Neil954bd922019-07-17 16:52:10 -0700412 newMessage: func() pref.Message {
413 return conv.New().Message()
414 },
Damien Neilf5274512019-08-05 10:48:38 -0700415 newField: func() pref.Value {
416 return conv.New()
417 },
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700418 }
419}
Joe Tsai6cf80c42018-12-01 04:57:09 -0800420
Joe Tsai4ec39c72019-04-03 13:40:53 -0700421type oneofInfo struct {
Joe Tsai378c1322019-04-25 23:48:08 -0700422 oneofDesc pref.OneofDescriptor
423 which func(pointer) pref.FieldNumber
Joe Tsai4ec39c72019-04-03 13:40:53 -0700424}
425
Joe Tsaic0e4bb22019-07-06 13:05:11 -0700426func makeOneofInfo(od pref.OneofDescriptor, fs reflect.StructField, x exporter, wrappersByType map[reflect.Type]pref.FieldNumber) *oneofInfo {
427 fieldOffset := offsetOf(fs, x)
Joe Tsai4ec39c72019-04-03 13:40:53 -0700428 return &oneofInfo{
Joe Tsai378c1322019-04-25 23:48:08 -0700429 oneofDesc: od,
Joe Tsai4ec39c72019-04-03 13:40:53 -0700430 which: func(p pointer) pref.FieldNumber {
431 if p.IsNil() {
432 return 0
433 }
434 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
435 if rv.IsNil() {
436 return 0
437 }
438 return wrappersByType[rv.Elem().Type().Elem()]
439 },
440 }
441}