...
1
2
3
4
5 package proto
6
7 import (
8 "google.golang.org/protobuf/encoding/protowire"
9 "google.golang.org/protobuf/internal/encoding/messageset"
10 "google.golang.org/protobuf/reflect/protoreflect"
11 "google.golang.org/protobuf/runtime/protoiface"
12 )
13
14
15 func Size(m Message) int {
16 return MarshalOptions{}.Size(m)
17 }
18
19
20 func (o MarshalOptions) Size(m Message) int {
21
22 if m == nil {
23 return 0
24 }
25
26 return o.size(m.ProtoReflect())
27 }
28
29
30
31
32 func (o MarshalOptions) size(m protoreflect.Message) (size int) {
33 methods := protoMethods(m)
34 if methods != nil && methods.Size != nil {
35 out := methods.Size(protoiface.SizeInput{
36 Message: m,
37 })
38 return out.Size
39 }
40 if methods != nil && methods.Marshal != nil {
41
42
43 out, _ := methods.Marshal(protoiface.MarshalInput{
44 Message: m,
45 })
46 return len(out.Buf)
47 }
48 return o.sizeMessageSlow(m)
49 }
50
51 func (o MarshalOptions) sizeMessageSlow(m protoreflect.Message) (size int) {
52 if messageset.IsMessageSet(m.Descriptor()) {
53 return o.sizeMessageSet(m)
54 }
55 m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
56 size += o.sizeField(fd, v)
57 return true
58 })
59 size += len(m.GetUnknown())
60 return size
61 }
62
63 func (o MarshalOptions) sizeField(fd protoreflect.FieldDescriptor, value protoreflect.Value) (size int) {
64 num := fd.Number()
65 switch {
66 case fd.IsList():
67 return o.sizeList(num, fd, value.List())
68 case fd.IsMap():
69 return o.sizeMap(num, fd, value.Map())
70 default:
71 return protowire.SizeTag(num) + o.sizeSingular(num, fd.Kind(), value)
72 }
73 }
74
75 func (o MarshalOptions) sizeList(num protowire.Number, fd protoreflect.FieldDescriptor, list protoreflect.List) (size int) {
76 sizeTag := protowire.SizeTag(num)
77
78 if fd.IsPacked() && list.Len() > 0 {
79 content := 0
80 for i, llen := 0, list.Len(); i < llen; i++ {
81 content += o.sizeSingular(num, fd.Kind(), list.Get(i))
82 }
83 return sizeTag + protowire.SizeBytes(content)
84 }
85
86 for i, llen := 0, list.Len(); i < llen; i++ {
87 size += sizeTag + o.sizeSingular(num, fd.Kind(), list.Get(i))
88 }
89 return size
90 }
91
92 func (o MarshalOptions) sizeMap(num protowire.Number, fd protoreflect.FieldDescriptor, mapv protoreflect.Map) (size int) {
93 sizeTag := protowire.SizeTag(num)
94
95 mapv.Range(func(key protoreflect.MapKey, value protoreflect.Value) bool {
96 size += sizeTag
97 size += protowire.SizeBytes(o.sizeField(fd.MapKey(), key.Value()) + o.sizeField(fd.MapValue(), value))
98 return true
99 })
100 return size
101 }
102
View as plain text