...
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 Flags: o.flags(),
38 })
39 return out.Size
40 }
41 if methods != nil && methods.Marshal != nil {
42
43
44 out, _ := methods.Marshal(protoiface.MarshalInput{
45 Message: m,
46 Flags: o.flags(),
47 })
48 return len(out.Buf)
49 }
50 return o.sizeMessageSlow(m)
51 }
52
53 func (o MarshalOptions) sizeMessageSlow(m protoreflect.Message) (size int) {
54 if messageset.IsMessageSet(m.Descriptor()) {
55 return o.sizeMessageSet(m)
56 }
57 m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
58 size += o.sizeField(fd, v)
59 return true
60 })
61 size += len(m.GetUnknown())
62 return size
63 }
64
65 func (o MarshalOptions) sizeField(fd protoreflect.FieldDescriptor, value protoreflect.Value) (size int) {
66 num := fd.Number()
67 switch {
68 case fd.IsList():
69 return o.sizeList(num, fd, value.List())
70 case fd.IsMap():
71 return o.sizeMap(num, fd, value.Map())
72 default:
73 return protowire.SizeTag(num) + o.sizeSingular(num, fd.Kind(), value)
74 }
75 }
76
77 func (o MarshalOptions) sizeList(num protowire.Number, fd protoreflect.FieldDescriptor, list protoreflect.List) (size int) {
78 sizeTag := protowire.SizeTag(num)
79
80 if fd.IsPacked() && list.Len() > 0 {
81 content := 0
82 for i, llen := 0, list.Len(); i < llen; i++ {
83 content += o.sizeSingular(num, fd.Kind(), list.Get(i))
84 }
85 return sizeTag + protowire.SizeBytes(content)
86 }
87
88 for i, llen := 0, list.Len(); i < llen; i++ {
89 size += sizeTag + o.sizeSingular(num, fd.Kind(), list.Get(i))
90 }
91 return size
92 }
93
94 func (o MarshalOptions) sizeMap(num protowire.Number, fd protoreflect.FieldDescriptor, mapv protoreflect.Map) (size int) {
95 sizeTag := protowire.SizeTag(num)
96
97 mapv.Range(func(key protoreflect.MapKey, value protoreflect.Value) bool {
98 size += sizeTag
99 size += protowire.SizeBytes(o.sizeField(fd.MapKey(), key.Value()) + o.sizeField(fd.MapValue(), value))
100 return true
101 })
102 return size
103 }
104
View as plain text