blob: 1266143ce1d48dd658a2c036b496913069ccffa4 [file] [log] [blame]
Damien Neil61e93c72019-03-27 09:23:20 -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 proto
6
7import (
Damien Neile89e6242019-05-13 23:55:40 -07008 "google.golang.org/protobuf/internal/encoding/wire"
9 "google.golang.org/protobuf/reflect/protoreflect"
Joe Tsaif8b855d2019-07-12 13:37:59 -070010 "google.golang.org/protobuf/runtime/protoiface"
Damien Neil61e93c72019-03-27 09:23:20 -070011)
12
13// Size returns the size in bytes of the wire-format encoding of m.
14func Size(m Message) int {
Damien Neil03e74862019-04-07 18:18:31 -070015 return MarshalOptions{}.Size(m)
16}
17
18// Size returns the size in bytes of the wire-format encoding of m.
19func (o MarshalOptions) Size(m Message) int {
Damien Neil61e93c72019-03-27 09:23:20 -070020 return sizeMessage(m.ProtoReflect())
21}
22
Joe Tsai0f81b382019-07-10 23:14:31 -070023func sizeMessage(m protoreflect.Message) (size int) {
24 if methods := protoMethods(m); methods != nil && methods.Size != nil {
Joe Tsaif8b855d2019-07-12 13:37:59 -070025 return methods.Size(m, protoiface.MarshalOptions{})
Damien Neil0d3e8cc2019-04-01 13:31:55 -070026 }
Joe Tsai0f81b382019-07-10 23:14:31 -070027 return sizeMessageSlow(m)
Damien Neil0d3e8cc2019-04-01 13:31:55 -070028}
29
Joe Tsai0f81b382019-07-10 23:14:31 -070030func sizeMessageSlow(m protoreflect.Message) (size int) {
Joe Tsai378c1322019-04-25 23:48:08 -070031 m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
32 size += sizeField(fd, v)
Damien Neil61e93c72019-03-27 09:23:20 -070033 return true
34 })
Joe Tsai378c1322019-04-25 23:48:08 -070035 size += len(m.GetUnknown())
Damien Neil61e93c72019-03-27 09:23:20 -070036 return size
37}
38
Joe Tsaiac31a352019-05-13 14:32:56 -070039func sizeField(fd protoreflect.FieldDescriptor, value protoreflect.Value) (size int) {
40 num := fd.Number()
Damien Neil61e93c72019-03-27 09:23:20 -070041 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -070042 case fd.IsList():
43 return sizeList(num, fd, value.List())
44 case fd.IsMap():
45 return sizeMap(num, fd, value.Map())
Damien Neil61e93c72019-03-27 09:23:20 -070046 default:
Joe Tsaiac31a352019-05-13 14:32:56 -070047 return wire.SizeTag(num) + sizeSingular(num, fd.Kind(), value)
Damien Neil61e93c72019-03-27 09:23:20 -070048 }
49}
50
Joe Tsaiac31a352019-05-13 14:32:56 -070051func sizeList(num wire.Number, fd protoreflect.FieldDescriptor, list protoreflect.List) (size int) {
Joe Tsai378c1322019-04-25 23:48:08 -070052 if fd.IsPacked() && list.Len() > 0 {
Joe Tsaiac31a352019-05-13 14:32:56 -070053 content := 0
54 for i, llen := 0, list.Len(); i < llen; i++ {
55 content += sizeSingular(num, fd.Kind(), list.Get(i))
56 }
57 return wire.SizeTag(num) + wire.SizeBytes(content)
58 }
59
60 for i, llen := 0, list.Len(); i < llen; i++ {
61 size += wire.SizeTag(num) + sizeSingular(num, fd.Kind(), list.Get(i))
62 }
Damien Neil61e93c72019-03-27 09:23:20 -070063 return size
64}
65
Joe Tsaiac31a352019-05-13 14:32:56 -070066func sizeMap(num wire.Number, fd protoreflect.FieldDescriptor, mapv protoreflect.Map) (size int) {
67 mapv.Range(func(key protoreflect.MapKey, value protoreflect.Value) bool {
68 size += wire.SizeTag(num)
69 size += wire.SizeBytes(sizeField(fd.MapKey(), key.Value()) + sizeField(fd.MapValue(), value))
70 return true
71 })
Damien Neil61e93c72019-03-27 09:23:20 -070072 return size
73}