blob: 0ef8b12c9064d3ea63dd05ee34a27a209245fe4e [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"
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
26func fieldInfoForWeak(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
27 if !flags.Proto1Legacy {
28 panic("weak fields not supported")
29 }
30 // TODO: support weak fields.
31 panic(fmt.Sprintf("invalid field: %v", fd))
32}
33
34func 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 },
93 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -070094}
95
96func fieldInfoForMap(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsaibbfaeb72018-10-17 00:27:21 +000097 ft := fs.Type
98 if ft.Kind() != reflect.Map {
99 panic(fmt.Sprintf("invalid type: got %v, want map kind", ft))
100 }
Joe Tsai08e00302018-11-26 22:32:06 -0800101 keyConv := pvalue.NewLegacyConverter(ft.Key(), fd.MessageType().Fields().ByNumber(1).Kind(), legacyWrapper)
102 valConv := pvalue.NewLegacyConverter(ft.Elem(), fd.MessageType().Fields().ByNumber(2).Kind(), legacyWrapper)
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 },
Joe Tsaibbfaeb72018-10-17 00:27:21 +0000129 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700130}
131
Joe Tsai4b7aff62018-11-14 14:05:19 -0800132func fieldInfoForList(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsai91e14662018-09-13 13:24:35 -0700133 ft := fs.Type
134 if ft.Kind() != reflect.Slice {
135 panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
136 }
Joe Tsai08e00302018-11-26 22:32:06 -0800137 conv := pvalue.NewLegacyConverter(ft.Elem(), fd.Kind(), legacyWrapper)
Joe Tsai91e14662018-09-13 13:24:35 -0700138 fieldOffset := offsetOf(fs)
139 // TODO: Implement unsafe fast path?
140 return fieldInfo{
141 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800142 if p.IsNil() {
143 return false
144 }
145 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai91e14662018-09-13 13:24:35 -0700146 return rv.Len() > 0
147 },
148 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800149 if p.IsNil() {
150 v := reflect.Zero(reflect.PtrTo(fs.Type)).Interface()
151 return pref.ValueOf(pvalue.ListOf(v, conv))
152 }
153 v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
Joe Tsai4b7aff62018-11-14 14:05:19 -0800154 return pref.ValueOf(pvalue.ListOf(v, conv))
Joe Tsai91e14662018-09-13 13:24:35 -0700155 },
156 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800157 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaiba0ef9a2018-11-29 14:54:05 -0800158 rv.Set(reflect.ValueOf(v.List().(pvalue.Unwrapper).ProtoUnwrap()).Elem())
Joe Tsai91e14662018-09-13 13:24:35 -0700159 },
160 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800161 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai91e14662018-09-13 13:24:35 -0700162 rv.Set(reflect.Zero(rv.Type()))
163 },
Joe Tsai91e14662018-09-13 13:24:35 -0700164 }
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700165}
166
167var emptyBytes = reflect.ValueOf([]byte{})
168
169func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
170 ft := fs.Type
171 nullable := fd.Syntax() == pref.Proto2
172 if nullable {
173 if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
174 panic(fmt.Sprintf("invalid type: got %v, want pointer", ft))
175 }
176 if ft.Kind() == reflect.Ptr {
177 ft = ft.Elem()
178 }
179 }
Joe Tsai08e00302018-11-26 22:32:06 -0800180 conv := pvalue.NewLegacyConverter(ft, fd.Kind(), legacyWrapper)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700181 fieldOffset := offsetOf(fs)
182 // TODO: Implement unsafe fast path?
183 return fieldInfo{
184 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800185 if p.IsNil() {
186 return false
187 }
188 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700189 if nullable {
190 return !rv.IsNil()
191 }
192 switch rv.Kind() {
193 case reflect.Bool:
194 return rv.Bool()
195 case reflect.Int32, reflect.Int64:
Joe Tsai44e389c2018-11-19 15:27:09 -0800196 return rv.Int() != 0
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700197 case reflect.Uint32, reflect.Uint64:
Joe Tsai44e389c2018-11-19 15:27:09 -0800198 return rv.Uint() != 0
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700199 case reflect.Float32, reflect.Float64:
Joe Tsai44e389c2018-11-19 15:27:09 -0800200 return rv.Float() != 0
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700201 case reflect.String, reflect.Slice:
202 return rv.Len() > 0
203 default:
204 panic(fmt.Sprintf("invalid type: %v", rv.Type())) // should never happen
205 }
206 },
207 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800208 if p.IsNil() {
209 return defaultValueOf(fd)
210 }
211 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700212 if nullable {
213 if rv.IsNil() {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800214 return defaultValueOf(fd)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700215 }
216 if rv.Kind() == reflect.Ptr {
217 rv = rv.Elem()
218 }
219 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800220 return conv.PBValueOf(rv)
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700221 },
222 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800223 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700224 if nullable && rv.Kind() == reflect.Ptr {
225 if rv.IsNil() {
226 rv.Set(reflect.New(ft))
227 }
228 rv = rv.Elem()
229 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800230 rv.Set(conv.GoValueOf(v))
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700231 if nullable && rv.Kind() == reflect.Slice && rv.IsNil() {
232 rv.Set(emptyBytes)
233 }
234 },
235 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800236 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700237 rv.Set(reflect.Zero(rv.Type()))
238 },
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700239 }
240}
241
242func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
Joe Tsaice6edd32018-10-19 16:27:46 -0700243 ft := fs.Type
Joe Tsai08e00302018-11-26 22:32:06 -0800244 conv := pvalue.NewLegacyConverter(ft, fd.Kind(), legacyWrapper)
Joe Tsaice6edd32018-10-19 16:27:46 -0700245 fieldOffset := offsetOf(fs)
246 // TODO: Implement unsafe fast path?
247 return fieldInfo{
248 has: func(p pointer) bool {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800249 if p.IsNil() {
250 return false
251 }
252 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaice6edd32018-10-19 16:27:46 -0700253 return !rv.IsNil()
254 },
255 get: func(p pointer) pref.Value {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800256 if p.IsNil() {
257 return pref.Value{}
258 }
259 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaif6d4a422018-11-19 14:26:06 -0800260 if rv.IsNil() {
261 return pref.Value{}
262 }
Joe Tsai88bc5a72018-11-05 11:42:22 -0800263 return conv.PBValueOf(rv)
Joe Tsaice6edd32018-10-19 16:27:46 -0700264 },
265 set: func(p pointer, v pref.Value) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800266 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsai88bc5a72018-11-05 11:42:22 -0800267 rv.Set(conv.GoValueOf(v))
Joe Tsaif6d4a422018-11-19 14:26:06 -0800268 if rv.IsNil() {
269 panic("invalid nil pointer")
270 }
Joe Tsaice6edd32018-10-19 16:27:46 -0700271 },
272 clear: func(p pointer) {
Joe Tsai6cf80c42018-12-01 04:57:09 -0800273 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
Joe Tsaice6edd32018-10-19 16:27:46 -0700274 rv.Set(reflect.Zero(rv.Type()))
275 },
Damien Neil97e7f572018-12-07 14:28:33 -0800276 newMessage: func() pref.Message {
Joe Tsai3bc7d6f2019-01-09 02:57:13 -0800277 return conv.MessageType.New()
Joe Tsaifa02f4e2018-09-12 16:20:37 -0700278 },
279 }
280}
Joe Tsai6cf80c42018-12-01 04:57:09 -0800281
282// defaultValueOf returns the default value for the field.
283func defaultValueOf(fd pref.FieldDescriptor) pref.Value {
284 if fd == nil {
285 return pref.Value{}
286 }
287 pv := fd.Default() // invalid Value for messages and repeated fields
288 if fd.Kind() == pref.BytesKind && pv.IsValid() && len(pv.Bytes()) > 0 {
289 return pref.ValueOf(append([]byte(nil), pv.Bytes()...)) // copy default bytes for safety
290 }
291 return pv
292}