blob: 10405d052002a382cc47b48e634d1033fc4f993d [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
Joe Tsaif0c01e42018-11-06 13:05:20 -080012 pvalue "github.com/golang/protobuf/v2/internal/value"
Joe Tsai01ab2962018-09-21 17:44:00 -070013 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Joe Tsaifa02f4e2018-09-12 16:20:37 -070014)
15
16type fieldInfo struct {
17 // TODO: specialize marshal and unmarshal functions?
18
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
Joe Tsaifa02f4e2018-09-12 16:20:37 -070024}
25
Joe Tsaifa02f4e2018-09-12 16:20:37 -070026func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, ot reflect.Type) fieldInfo {
Joe Tsai2c870bb2018-10-17 11:46:52 -070027 ft := fs.Type
28 if ft.Kind() != reflect.Interface {
29 panic(fmt.Sprintf("invalid type: got %v, want interface kind", ft))
30 }
31 if ot.Kind() != reflect.Struct {
32 panic(fmt.Sprintf("invalid type: got %v, want struct kind", ot))
33 }
34 if !reflect.PtrTo(ot).Implements(ft) {
35 panic(fmt.Sprintf("invalid type: %v does not implement %v", ot, ft))
36 }
Joe Tsai08e00302018-11-26 22:32:06 -080037 conv := pvalue.NewLegacyConverter(ot.Field(0).Type, fd.Kind(), legacyWrapper)
Joe Tsai2c870bb2018-10-17 11:46:52 -070038 fieldOffset := offsetOf(fs)
39 // TODO: Implement unsafe fast path?
40 return fieldInfo{
41 // NOTE: The logic below intentionally assumes that oneof fields are
42 // well-formatted. That is, the oneof interface never contains a
43 // typed nil pointer to one of the wrapper structs.
44
45 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -080046 if p.IsNil() {
47 return false
48 }
49 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai2c870bb2018-10-17 11:46:52 -070050 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
51 return false
52 }
53 return true
54 },
55 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -080056 if p.IsNil() {
57 return defaultValueOf(fd)
58 }
59 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai2c870bb2018-10-17 11:46:52 -070060 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
Joe Tsai6cf80c42018-12-01 04:57:09 -080061 return defaultValueOf(fd)
Joe Tsai2c870bb2018-10-17 11:46:52 -070062 }
63 rv = rv.Elem().Elem().Field(0)
Joe Tsai88bc5a72018-11-05 11:42:22 -080064 return conv.PBValueOf(rv)
Joe Tsai2c870bb2018-10-17 11:46:52 -070065 },
66 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -080067 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai2c870bb2018-10-17 11:46:52 -070068 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
69 rv.Set(reflect.New(ot))
70 }
71 rv = rv.Elem().Elem().Field(0)
Joe Tsai88bc5a72018-11-05 11:42:22 -080072 rv.Set(conv.GoValueOf(v))
Joe Tsai2c870bb2018-10-17 11:46:52 -070073 },
74 clear: func(p pointer) {
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 return
78 }
79 rv.Set(reflect.Zero(rv.Type()))
80 },
Damien Neil97e7f572018-12-07 14:28:33 -080081 newMessage: func() pref.Message {
82 // This is only valid for messages and panics for other kinds.
Joe Tsai3bc7d6f2019-01-09 02:57:13 -080083 return conv.MessageType.New()
Joe Tsai2c870bb2018-10-17 11:46:52 -070084 },
85 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -070086}
87
88func fieldInfoForMap(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsaibbfaeb72018-10-17 00:27:21 +000089 ft := fs.Type
90 if ft.Kind() != reflect.Map {
91 panic(fmt.Sprintf("invalid type: got %v, want map kind", ft))
92 }
Joe Tsaiac31a352019-05-13 14:32:56 -070093 keyConv := pvalue.NewLegacyConverter(ft.Key(), fd.MapKey().Kind(), legacyWrapper)
94 valConv := pvalue.NewLegacyConverter(ft.Elem(), fd.MapValue().Kind(), legacyWrapper)
Joe Tsaibbfaeb72018-10-17 00:27:21 +000095 fieldOffset := offsetOf(fs)
96 // TODO: Implement unsafe fast path?
97 return fieldInfo{
98 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -080099 if p.IsNil() {
100 return false
101 }
102 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000103 return rv.Len() > 0
104 },
105 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800106 if p.IsNil() {
107 v := reflect.Zero(reflect.PtrTo(fs.Type)).Interface()
108 return pref.ValueOf(pvalue.MapOf(v, keyConv, valConv))
109 }
110 v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
Joe Tsaif0c01e42018-11-06 13:05:20 -0800111 return pref.ValueOf(pvalue.MapOf(v, keyConv, valConv))
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000112 },
113 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800114 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaiba0ef9a2018-11-29 14:54:05 -0800115 rv.Set(reflect.ValueOf(v.Map().(pvalue.Unwrapper).ProtoUnwrap()).Elem())
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000116 },
117 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800118 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000119 rv.Set(reflect.Zero(rv.Type()))
120 },
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000121 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700122}
123
Joe Tsai4b7aff62018-11-14 14:05:19 -0800124func fieldInfoForList(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsai91e14662018-09-13 13:24:35 -0700125 ft := fs.Type
126 if ft.Kind() != reflect.Slice {
127 panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
128 }
Joe Tsai08e00302018-11-26 22:32:06 -0800129 conv := pvalue.NewLegacyConverter(ft.Elem(), fd.Kind(), legacyWrapper)
Joe Tsai91e14662018-09-13 13:24:35 -0700130 fieldOffset := offsetOf(fs)
131 // TODO: Implement unsafe fast path?
132 return fieldInfo{
133 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800134 if p.IsNil() {
135 return false
136 }
137 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai91e14662018-09-13 13:24:35 -0700138 return rv.Len() > 0
139 },
140 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800141 if p.IsNil() {
142 v := reflect.Zero(reflect.PtrTo(fs.Type)).Interface()
143 return pref.ValueOf(pvalue.ListOf(v, conv))
144 }
145 v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
Joe Tsai4b7aff62018-11-14 14:05:19 -0800146 return pref.ValueOf(pvalue.ListOf(v, conv))
Joe Tsai91e14662018-09-13 13:24:35 -0700147 },
148 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800149 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaiba0ef9a2018-11-29 14:54:05 -0800150 rv.Set(reflect.ValueOf(v.List().(pvalue.Unwrapper).ProtoUnwrap()).Elem())
Joe Tsai91e14662018-09-13 13:24:35 -0700151 },
152 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800153 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai91e14662018-09-13 13:24:35 -0700154 rv.Set(reflect.Zero(rv.Type()))
155 },
Joe Tsai91e14662018-09-13 13:24:35 -0700156 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700157}
158
159var emptyBytes = reflect.ValueOf([]byte{})
160
161func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
162 ft := fs.Type
163 nullable := fd.Syntax() == pref.Proto2
164 if nullable {
165 if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
166 panic(fmt.Sprintf("invalid type: got %v, want pointer", ft))
167 }
168 if ft.Kind() == reflect.Ptr {
169 ft = ft.Elem()
170 }
171 }
Joe Tsai08e00302018-11-26 22:32:06 -0800172 conv := pvalue.NewLegacyConverter(ft, fd.Kind(), legacyWrapper)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700173 fieldOffset := offsetOf(fs)
174 // TODO: Implement unsafe fast path?
175 return fieldInfo{
176 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800177 if p.IsNil() {
178 return false
179 }
180 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700181 if nullable {
182 return !rv.IsNil()
183 }
184 switch rv.Kind() {
185 case reflect.Bool:
186 return rv.Bool()
187 case reflect.Int32, reflect.Int64:
Joe Tsai44e389c2018-11-19 15:27:09 -0800188 return rv.Int() != 0
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700189 case reflect.Uint32, reflect.Uint64:
Joe Tsai44e389c2018-11-19 15:27:09 -0800190 return rv.Uint() != 0
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700191 case reflect.Float32, reflect.Float64:
Joe Tsai060cdac2019-04-22 11:44:49 -0700192 return rv.Float() != 0 || math.Signbit(rv.Float())
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700193 case reflect.String, reflect.Slice:
194 return rv.Len() > 0
195 default:
196 panic(fmt.Sprintf("invalid type: %v", rv.Type())) // should never happen
197 }
198 },
199 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800200 if p.IsNil() {
201 return defaultValueOf(fd)
202 }
203 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700204 if nullable {
205 if rv.IsNil() {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800206 return defaultValueOf(fd)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700207 }
208 if rv.Kind() == reflect.Ptr {
209 rv = rv.Elem()
210 }
211 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800212 return conv.PBValueOf(rv)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700213 },
214 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800215 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700216 if nullable && rv.Kind() == reflect.Ptr {
217 if rv.IsNil() {
218 rv.Set(reflect.New(ft))
219 }
220 rv = rv.Elem()
221 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800222 rv.Set(conv.GoValueOf(v))
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700223 if nullable && rv.Kind() == reflect.Slice && rv.IsNil() {
224 rv.Set(emptyBytes)
225 }
226 },
227 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800228 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700229 rv.Set(reflect.Zero(rv.Type()))
230 },
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700231 }
232}
233
234func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsaice6edd32018-10-19 16:27:46 -0700235 ft := fs.Type
Joe Tsai08e00302018-11-26 22:32:06 -0800236 conv := pvalue.NewLegacyConverter(ft, fd.Kind(), legacyWrapper)
Joe Tsaice6edd32018-10-19 16:27:46 -0700237 fieldOffset := offsetOf(fs)
238 // TODO: Implement unsafe fast path?
239 return fieldInfo{
240 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800241 if p.IsNil() {
242 return false
243 }
244 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaice6edd32018-10-19 16:27:46 -0700245 return !rv.IsNil()
246 },
247 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800248 if p.IsNil() {
249 return pref.Value{}
250 }
251 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaif6d4a422018-11-19 14:26:06 -0800252 if rv.IsNil() {
253 return pref.Value{}
254 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800255 return conv.PBValueOf(rv)
Joe Tsaice6edd32018-10-19 16:27:46 -0700256 },
257 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800258 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai88bc5a72018-11-05 11:42:22 -0800259 rv.Set(conv.GoValueOf(v))
Joe Tsaif6d4a422018-11-19 14:26:06 -0800260 if rv.IsNil() {
261 panic("invalid nil pointer")
262 }
Joe Tsaice6edd32018-10-19 16:27:46 -0700263 },
264 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800265 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaice6edd32018-10-19 16:27:46 -0700266 rv.Set(reflect.Zero(rv.Type()))
267 },
Damien Neil97e7f572018-12-07 14:28:33 -0800268 newMessage: func() pref.Message {
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800269 return conv.MessageType.New()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700270 },
271 }
272}
Joe Tsai6cf80c42018-12-01 04:57:09 -0800273
274// defaultValueOf returns the default value for the field.
275func defaultValueOf(fd pref.FieldDescriptor) pref.Value {
276 if fd == nil {
277 return pref.Value{}
278 }
279 pv := fd.Default() // invalid Value for messages and repeated fields
280 if fd.Kind() == pref.BytesKind && pv.IsValid() && len(pv.Bytes()) > 0 {
281 return pref.ValueOf(append([]byte(nil), pv.Bytes()...)) // copy default bytes for safety
282 }
283 return pv
284}
Joe Tsai4ec39c72019-04-03 13:40:53 -0700285
286type oneofInfo struct {
287 which func(pointer) pref.FieldNumber
288}
289
290func makeOneofInfo(od pref.OneofDescriptor, fs reflect.StructField, wrappersByType map[reflect.Type]pref.FieldNumber) *oneofInfo {
291 fieldOffset := offsetOf(fs)
292 return &oneofInfo{
293 which: func(p pointer) pref.FieldNumber {
294 if p.IsNil() {
295 return 0
296 }
297 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
298 if rv.IsNil() {
299 return 0
300 }
301 return wrappersByType[rv.Elem().Type().Elem()]
302 },
303 }
304}