blob: b8afb99bd313338d00c838440d37abd9ec571ce0 [file] [log] [blame]
Damien Neilc37adef2019-04-01 13:49:56 -07001// Copyright 2019 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 "unicode/utf8"
11
12 "google.golang.org/protobuf/internal/encoding/wire"
Damien Neilc37adef2019-04-01 13:49:56 -070013 "google.golang.org/protobuf/proto"
14 pref "google.golang.org/protobuf/reflect/protoreflect"
15)
16
17type errInvalidUTF8 struct{}
18
19func (errInvalidUTF8) Error() string { return "string field contains invalid UTF-8" }
20func (errInvalidUTF8) InvalidUTF8() bool { return true }
21
22func makeOneofFieldCoder(fs reflect.StructField, od pref.OneofDescriptor, structFields map[pref.FieldNumber]reflect.StructField, otypes map[pref.FieldNumber]reflect.Type) pointerCoderFuncs {
23 type oneofFieldInfo struct {
24 wiretag uint64
25 tagsize int
26 funcs pointerCoderFuncs
27 }
28
29 oneofFieldInfos := make(map[reflect.Type]oneofFieldInfo)
30 for i, fields := 0, od.Fields(); i < fields.Len(); i++ {
31 fd := fields.Get(i)
32 ot := otypes[fd.Number()]
33 wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
34 oneofFieldInfos[ot] = oneofFieldInfo{
35 wiretag: wiretag,
36 tagsize: wire.SizeVarint(wiretag),
37 funcs: fieldCoder(fd, ot.Field(0).Type),
38 }
39 }
40 ft := fs.Type
41 return pointerCoderFuncs{
42 size: func(p pointer, _ int, opts marshalOptions) int {
43 v := p.AsValueOf(ft).Elem()
44 if v.IsNil() {
45 return 0
46 }
47 v = v.Elem() // interface -> *struct
48 telem := v.Elem().Type()
49 info, ok := oneofFieldInfos[telem]
50 if !ok {
51 panic(fmt.Errorf("invalid oneof type %v", telem))
52 }
53 return info.funcs.size(pointerOfValue(v).Apply(zeroOffset), info.tagsize, opts)
54 },
55 marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
56 v := p.AsValueOf(ft).Elem()
57 if v.IsNil() {
58 return b, nil
59 }
60 v = v.Elem() // interface -> *struct
61 telem := v.Elem().Type()
62 info, ok := oneofFieldInfos[telem]
63 if !ok {
64 panic(fmt.Errorf("invalid oneof type %v", telem))
65 }
66 return info.funcs.marshal(b, pointerOfValue(v).Apply(zeroOffset), info.wiretag, opts)
67 },
68 }
69}
70
71func makeMessageFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
Joe Tsai4fe96632019-05-22 05:12:36 -040072 if fi, ok := getMessageInfo(ft); ok {
Damien Neilc37adef2019-04-01 13:49:56 -070073 return pointerCoderFuncs{
74 size: func(p pointer, tagsize int, opts marshalOptions) int {
Joe Tsai4fe96632019-05-22 05:12:36 -040075 return sizeMessageInfo(p, fi, tagsize, opts)
Damien Neilc37adef2019-04-01 13:49:56 -070076 },
77 marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
Joe Tsai4fe96632019-05-22 05:12:36 -040078 return appendMessageInfo(b, p, wiretag, fi, opts)
Damien Neilc37adef2019-04-01 13:49:56 -070079 },
80 }
81 } else {
82 return pointerCoderFuncs{
83 size: func(p pointer, tagsize int, opts marshalOptions) int {
Damien Neil5b6d0472019-06-14 11:54:07 -070084 m := asMessage(p.AsValueOf(ft).Elem())
Damien Neilc37adef2019-04-01 13:49:56 -070085 return sizeMessage(m, tagsize, opts)
86 },
87 marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
Damien Neil5b6d0472019-06-14 11:54:07 -070088 m := asMessage(p.AsValueOf(ft).Elem())
Damien Neilc37adef2019-04-01 13:49:56 -070089 return appendMessage(b, m, wiretag, opts)
90 },
91 }
92 }
93}
94
Joe Tsai4fe96632019-05-22 05:12:36 -040095func sizeMessageInfo(p pointer, mi *MessageInfo, tagsize int, opts marshalOptions) int {
Damien Neilc37adef2019-04-01 13:49:56 -070096 return wire.SizeBytes(mi.sizePointer(p.Elem(), opts)) + tagsize
97}
98
Joe Tsai4fe96632019-05-22 05:12:36 -040099func appendMessageInfo(b []byte, p pointer, wiretag uint64, mi *MessageInfo, opts marshalOptions) ([]byte, error) {
Damien Neilc37adef2019-04-01 13:49:56 -0700100 b = wire.AppendVarint(b, wiretag)
101 b = wire.AppendVarint(b, uint64(mi.sizePointer(p.Elem(), opts)))
102 return mi.marshalAppendPointer(b, p.Elem(), opts)
103}
104
105func sizeMessage(m proto.Message, tagsize int, _ marshalOptions) int {
106 return wire.SizeBytes(proto.Size(m)) + tagsize
107}
108
109func appendMessage(b []byte, m proto.Message, wiretag uint64, opts marshalOptions) ([]byte, error) {
110 b = wire.AppendVarint(b, wiretag)
111 b = wire.AppendVarint(b, uint64(proto.Size(m)))
112 return opts.Options().MarshalAppend(b, m)
113}
114
115func sizeMessageIface(ival interface{}, tagsize int, opts marshalOptions) int {
116 m := Export{}.MessageOf(ival).Interface()
117 return sizeMessage(m, tagsize, opts)
118}
119
120func appendMessageIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
121 m := Export{}.MessageOf(ival).Interface()
122 return appendMessage(b, m, wiretag, opts)
123}
124
125var coderMessageIface = ifaceCoderFuncs{
126 size: sizeMessageIface,
127 marshal: appendMessageIface,
128}
129
130func makeGroupFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
Joe Tsai4fe96632019-05-22 05:12:36 -0400131 if fi, ok := getMessageInfo(ft); ok {
Damien Neilc37adef2019-04-01 13:49:56 -0700132 return pointerCoderFuncs{
133 size: func(p pointer, tagsize int, opts marshalOptions) int {
134 return sizeGroupType(p, fi, tagsize, opts)
135 },
136 marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
137 return appendGroupType(b, p, wiretag, fi, opts)
138 },
139 }
140 } else {
141 return pointerCoderFuncs{
142 size: func(p pointer, tagsize int, opts marshalOptions) int {
Damien Neil5b6d0472019-06-14 11:54:07 -0700143 m := asMessage(p.AsValueOf(ft).Elem())
Damien Neilc37adef2019-04-01 13:49:56 -0700144 return sizeGroup(m, tagsize, opts)
145 },
146 marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
Damien Neil5b6d0472019-06-14 11:54:07 -0700147 m := asMessage(p.AsValueOf(ft).Elem())
Damien Neilc37adef2019-04-01 13:49:56 -0700148 return appendGroup(b, m, wiretag, opts)
149 },
150 }
151 }
152}
153
Joe Tsai4fe96632019-05-22 05:12:36 -0400154func sizeGroupType(p pointer, mi *MessageInfo, tagsize int, opts marshalOptions) int {
Damien Neilc37adef2019-04-01 13:49:56 -0700155 return 2*tagsize + mi.sizePointer(p.Elem(), opts)
156}
157
Joe Tsai4fe96632019-05-22 05:12:36 -0400158func appendGroupType(b []byte, p pointer, wiretag uint64, mi *MessageInfo, opts marshalOptions) ([]byte, error) {
Damien Neilc37adef2019-04-01 13:49:56 -0700159 b = wire.AppendVarint(b, wiretag) // start group
160 b, err := mi.marshalAppendPointer(b, p.Elem(), opts)
161 b = wire.AppendVarint(b, wiretag+1) // end group
162 return b, err
163}
164
165func sizeGroup(m proto.Message, tagsize int, _ marshalOptions) int {
166 return 2*tagsize + proto.Size(m)
167}
168
169func appendGroup(b []byte, m proto.Message, wiretag uint64, opts marshalOptions) ([]byte, error) {
170 b = wire.AppendVarint(b, wiretag) // start group
171 b, err := opts.Options().MarshalAppend(b, m)
172 b = wire.AppendVarint(b, wiretag+1) // end group
173 return b, err
174}
175
176func sizeGroupIface(ival interface{}, tagsize int, opts marshalOptions) int {
177 m := Export{}.MessageOf(ival).Interface()
178 return sizeGroup(m, tagsize, opts)
179}
180
181func appendGroupIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
182 m := Export{}.MessageOf(ival).Interface()
183 return appendGroup(b, m, wiretag, opts)
184}
185
186var coderGroupIface = ifaceCoderFuncs{
187 size: sizeGroupIface,
188 marshal: appendGroupIface,
189}
190
191func makeMessageSliceFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
Joe Tsai4fe96632019-05-22 05:12:36 -0400192 if fi, ok := getMessageInfo(ft); ok {
Damien Neilc37adef2019-04-01 13:49:56 -0700193 return pointerCoderFuncs{
194 marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
195 return appendMessageSliceInfo(b, p, wiretag, fi, opts)
196 },
197 size: func(p pointer, tagsize int, opts marshalOptions) int {
198 return sizeMessageSliceInfo(p, fi, tagsize, opts)
199 },
200 }
201 }
202 return pointerCoderFuncs{
203 size: func(p pointer, tagsize int, opts marshalOptions) int {
204 return sizeMessageSlice(p, ft, tagsize, opts)
205 },
206 marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
207 return appendMessageSlice(b, p, wiretag, ft, opts)
208 },
209 }
210}
211
Joe Tsai4fe96632019-05-22 05:12:36 -0400212func sizeMessageSliceInfo(p pointer, mi *MessageInfo, tagsize int, opts marshalOptions) int {
Damien Neilc37adef2019-04-01 13:49:56 -0700213 s := p.PointerSlice()
214 n := 0
215 for _, v := range s {
216 n += wire.SizeBytes(mi.sizePointer(v, opts)) + tagsize
217 }
218 return n
219}
220
Joe Tsai4fe96632019-05-22 05:12:36 -0400221func appendMessageSliceInfo(b []byte, p pointer, wiretag uint64, mi *MessageInfo, opts marshalOptions) ([]byte, error) {
Damien Neilc37adef2019-04-01 13:49:56 -0700222 s := p.PointerSlice()
Damien Neilc37adef2019-04-01 13:49:56 -0700223 var err error
224 for _, v := range s {
225 b = wire.AppendVarint(b, wiretag)
226 siz := mi.sizePointer(v, opts)
227 b = wire.AppendVarint(b, uint64(siz))
228 b, err = mi.marshalAppendPointer(b, v, opts)
Damien Neil8c86fc52019-06-19 09:28:29 -0700229 if err != nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700230 return b, err
231 }
232 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700233 return b, nil
Damien Neilc37adef2019-04-01 13:49:56 -0700234}
235
236func sizeMessageSlice(p pointer, goType reflect.Type, tagsize int, _ marshalOptions) int {
237 s := p.PointerSlice()
238 n := 0
239 for _, v := range s {
240 m := Export{}.MessageOf(v.AsValueOf(goType.Elem()).Interface()).Interface()
241 n += wire.SizeBytes(proto.Size(m)) + tagsize
242 }
243 return n
244}
245
246func appendMessageSlice(b []byte, p pointer, wiretag uint64, goType reflect.Type, opts marshalOptions) ([]byte, error) {
247 s := p.PointerSlice()
Damien Neilc37adef2019-04-01 13:49:56 -0700248 var err error
249 for _, v := range s {
250 m := Export{}.MessageOf(v.AsValueOf(goType.Elem()).Interface()).Interface()
251 b = wire.AppendVarint(b, wiretag)
252 siz := proto.Size(m)
253 b = wire.AppendVarint(b, uint64(siz))
254 b, err = opts.Options().MarshalAppend(b, m)
Damien Neil8c86fc52019-06-19 09:28:29 -0700255 if err != nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700256 return b, err
257 }
258 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700259 return b, nil
Damien Neilc37adef2019-04-01 13:49:56 -0700260}
261
262// Slices of messages
263
264func sizeMessageSliceIface(ival interface{}, tagsize int, opts marshalOptions) int {
265 p := pointerOfIface(ival)
266 return sizeMessageSlice(p, reflect.TypeOf(ival).Elem().Elem(), tagsize, opts)
267}
268
269func appendMessageSliceIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
270 p := pointerOfIface(ival)
271 return appendMessageSlice(b, p, wiretag, reflect.TypeOf(ival).Elem().Elem(), opts)
272}
273
274var coderMessageSliceIface = ifaceCoderFuncs{
275 size: sizeMessageSliceIface,
276 marshal: appendMessageSliceIface,
277}
278
279func makeGroupSliceFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
Joe Tsai4fe96632019-05-22 05:12:36 -0400280 if fi, ok := getMessageInfo(ft); ok {
Damien Neilc37adef2019-04-01 13:49:56 -0700281 return pointerCoderFuncs{
282 size: func(p pointer, tagsize int, opts marshalOptions) int {
283 return sizeGroupSliceInfo(p, fi, tagsize, opts)
284 },
285 marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
286 return appendGroupSliceInfo(b, p, wiretag, fi, opts)
287 },
288 }
289 }
290 return pointerCoderFuncs{
291 size: func(p pointer, tagsize int, opts marshalOptions) int {
292 return sizeGroupSlice(p, ft, tagsize, opts)
293 },
294 marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
295 return appendGroupSlice(b, p, wiretag, ft, opts)
296 },
297 }
298}
299
300func sizeGroupSlice(p pointer, messageType reflect.Type, tagsize int, _ marshalOptions) int {
301 s := p.PointerSlice()
302 n := 0
303 for _, v := range s {
304 m := Export{}.MessageOf(v.AsValueOf(messageType.Elem()).Interface()).Interface()
305 n += 2*tagsize + proto.Size(m)
306 }
307 return n
308}
309
310func appendGroupSlice(b []byte, p pointer, wiretag uint64, messageType reflect.Type, opts marshalOptions) ([]byte, error) {
311 s := p.PointerSlice()
Damien Neilc37adef2019-04-01 13:49:56 -0700312 var err error
313 for _, v := range s {
314 m := Export{}.MessageOf(v.AsValueOf(messageType.Elem()).Interface()).Interface()
315 b = wire.AppendVarint(b, wiretag) // start group
316 b, err = opts.Options().MarshalAppend(b, m)
Damien Neil8c86fc52019-06-19 09:28:29 -0700317 if err != nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700318 return b, err
319 }
320 b = wire.AppendVarint(b, wiretag+1) // end group
321 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700322 return b, nil
Damien Neilc37adef2019-04-01 13:49:56 -0700323}
324
Joe Tsai4fe96632019-05-22 05:12:36 -0400325func sizeGroupSliceInfo(p pointer, mi *MessageInfo, tagsize int, opts marshalOptions) int {
Damien Neilc37adef2019-04-01 13:49:56 -0700326 s := p.PointerSlice()
327 n := 0
328 for _, v := range s {
329 n += 2*tagsize + mi.sizePointer(v, opts)
330 }
331 return n
332}
333
Joe Tsai4fe96632019-05-22 05:12:36 -0400334func appendGroupSliceInfo(b []byte, p pointer, wiretag uint64, mi *MessageInfo, opts marshalOptions) ([]byte, error) {
Damien Neilc37adef2019-04-01 13:49:56 -0700335 s := p.PointerSlice()
Damien Neilc37adef2019-04-01 13:49:56 -0700336 var err error
337 for _, v := range s {
338 b = wire.AppendVarint(b, wiretag) // start group
339 b, err = mi.marshalAppendPointer(b, v, opts)
Damien Neil8c86fc52019-06-19 09:28:29 -0700340 if err != nil {
Damien Neilc37adef2019-04-01 13:49:56 -0700341 return b, err
342 }
343 b = wire.AppendVarint(b, wiretag+1) // end group
344 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700345 return b, nil
Damien Neilc37adef2019-04-01 13:49:56 -0700346}
347
348func sizeGroupSliceIface(ival interface{}, tagsize int, opts marshalOptions) int {
349 p := pointerOfIface(ival)
350 return sizeGroupSlice(p, reflect.TypeOf(ival).Elem().Elem(), tagsize, opts)
351}
352
353func appendGroupSliceIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
354 p := pointerOfIface(ival)
355 return appendGroupSlice(b, p, wiretag, reflect.TypeOf(ival).Elem().Elem(), opts)
356}
357
358var coderGroupSliceIface = ifaceCoderFuncs{
359 size: sizeGroupSliceIface,
360 marshal: appendGroupSliceIface,
361}
362
363// Enums
364
365func sizeEnumIface(ival interface{}, tagsize int, _ marshalOptions) (n int) {
366 v := reflect.ValueOf(ival).Int()
367 return wire.SizeVarint(uint64(v)) + tagsize
368}
369
370func appendEnumIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
371 v := reflect.ValueOf(ival).Int()
372 b = wire.AppendVarint(b, wiretag)
373 b = wire.AppendVarint(b, uint64(v))
374 return b, nil
375}
376
377var coderEnumIface = ifaceCoderFuncs{
378 size: sizeEnumIface,
379 marshal: appendEnumIface,
380}
381
382func sizeEnumSliceIface(ival interface{}, tagsize int, opts marshalOptions) (size int) {
383 return sizeEnumSliceReflect(reflect.ValueOf(ival).Elem(), tagsize, opts)
384}
385
386func sizeEnumSliceReflect(s reflect.Value, tagsize int, _ marshalOptions) (size int) {
387 for i, llen := 0, s.Len(); i < llen; i++ {
388 size += wire.SizeVarint(uint64(s.Index(i).Int())) + tagsize
389 }
390 return size
391}
392
393func appendEnumSliceIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
394 return appendEnumSliceReflect(b, reflect.ValueOf(ival).Elem(), wiretag, opts)
395}
396
397func appendEnumSliceReflect(b []byte, s reflect.Value, wiretag uint64, opts marshalOptions) ([]byte, error) {
398 for i, llen := 0, s.Len(); i < llen; i++ {
399 b = wire.AppendVarint(b, wiretag)
400 b = wire.AppendVarint(b, uint64(s.Index(i).Int()))
401 }
402 return b, nil
403}
404
405var coderEnumSliceIface = ifaceCoderFuncs{
406 size: sizeEnumSliceIface,
407 marshal: appendEnumSliceIface,
408}
409
410// Strings with UTF8 validation.
411
412func appendStringValidateUTF8(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
413 v := *p.String()
414 b = wire.AppendVarint(b, wiretag)
Damien Neilcedb5952019-06-21 12:04:07 -0700415 b = wire.AppendString(b, v)
Damien Neilc37adef2019-04-01 13:49:56 -0700416 if !utf8.ValidString(v) {
417 return b, errInvalidUTF8{}
418 }
419 return b, nil
420}
421
422var coderStringValidateUTF8 = pointerCoderFuncs{
423 size: sizeString,
424 marshal: appendStringValidateUTF8,
425}
426
427func appendStringNoZeroValidateUTF8(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
428 v := *p.String()
429 if len(v) == 0 {
430 return b, nil
431 }
432 b = wire.AppendVarint(b, wiretag)
Damien Neilcedb5952019-06-21 12:04:07 -0700433 b = wire.AppendString(b, v)
Damien Neilc37adef2019-04-01 13:49:56 -0700434 if !utf8.ValidString(v) {
435 return b, errInvalidUTF8{}
436 }
437 return b, nil
438}
439
440var coderStringNoZeroValidateUTF8 = pointerCoderFuncs{
441 size: sizeStringNoZero,
442 marshal: appendStringNoZeroValidateUTF8,
443}
444
445func sizeStringSliceValidateUTF8(p pointer, tagsize int, _ marshalOptions) (size int) {
446 s := *p.StringSlice()
447 for _, v := range s {
Damien Neilcedb5952019-06-21 12:04:07 -0700448 size += tagsize + wire.SizeBytes(len(v))
Damien Neilc37adef2019-04-01 13:49:56 -0700449 }
450 return size
451}
452
453func appendStringSliceValidateUTF8(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
454 s := *p.StringSlice()
455 var err error
456 for _, v := range s {
457 b = wire.AppendVarint(b, wiretag)
Damien Neilcedb5952019-06-21 12:04:07 -0700458 b = wire.AppendString(b, v)
Damien Neilc37adef2019-04-01 13:49:56 -0700459 if !utf8.ValidString(v) {
460 err = errInvalidUTF8{}
461 }
462 }
463 return b, err
464}
465
466var coderStringSliceValidateUTF8 = pointerCoderFuncs{
467 size: sizeStringSliceValidateUTF8,
468 marshal: appendStringSliceValidateUTF8,
469}
470
471func sizeStringIfaceValidateUTF8(ival interface{}, tagsize int, _ marshalOptions) int {
472 v := ival.(string)
Damien Neilcedb5952019-06-21 12:04:07 -0700473 return tagsize + wire.SizeBytes(len(v))
Damien Neilc37adef2019-04-01 13:49:56 -0700474}
475
476func appendStringIfaceValidateUTF8(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
477 v := ival.(string)
478 b = wire.AppendVarint(b, wiretag)
Damien Neilcedb5952019-06-21 12:04:07 -0700479 b = wire.AppendString(b, v)
Damien Neilc37adef2019-04-01 13:49:56 -0700480 if !utf8.ValidString(v) {
481 return b, errInvalidUTF8{}
482 }
483 return b, nil
484}
485
486var coderStringIfaceValidateUTF8 = ifaceCoderFuncs{
487 size: sizeStringIfaceValidateUTF8,
488 marshal: appendStringIfaceValidateUTF8,
489}
Damien Neil5b6d0472019-06-14 11:54:07 -0700490
491func asMessage(v reflect.Value) pref.ProtoMessage {
492 if m, ok := v.Interface().(pref.ProtoMessage); ok {
493 return m
494 }
495 return legacyWrapMessage(v)
496}