blob: 994758059ae5aa5caf602f0c67556ff02f64c8cc [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 Neil302cb322019-06-19 15:22:13 -07008 "google.golang.org/protobuf/internal/encoding/messageset"
Damien Neile89e6242019-05-13 23:55:40 -07009 "google.golang.org/protobuf/internal/encoding/wire"
10 "google.golang.org/protobuf/reflect/protoreflect"
Joe Tsaif8b855d2019-07-12 13:37:59 -070011 "google.golang.org/protobuf/runtime/protoiface"
Damien Neil61e93c72019-03-27 09:23:20 -070012)
13
14// Size returns the size in bytes of the wire-format encoding of m.
15func Size(m Message) int {
Damien Neil03e74862019-04-07 18:18:31 -070016 return MarshalOptions{}.Size(m)
17}
18
19// Size returns the size in bytes of the wire-format encoding of m.
20func (o MarshalOptions) Size(m Message) int {
Damien Neil61e93c72019-03-27 09:23:20 -070021 return sizeMessage(m.ProtoReflect())
22}
23
Joe Tsai0f81b382019-07-10 23:14:31 -070024func sizeMessage(m protoreflect.Message) (size int) {
25 if methods := protoMethods(m); methods != nil && methods.Size != nil {
Joe Tsaif8b855d2019-07-12 13:37:59 -070026 return methods.Size(m, protoiface.MarshalOptions{})
Damien Neil0d3e8cc2019-04-01 13:31:55 -070027 }
Joe Tsai0f81b382019-07-10 23:14:31 -070028 return sizeMessageSlow(m)
Damien Neil0d3e8cc2019-04-01 13:31:55 -070029}
30
Joe Tsai0f81b382019-07-10 23:14:31 -070031func sizeMessageSlow(m protoreflect.Message) (size int) {
Damien Neil302cb322019-06-19 15:22:13 -070032 if messageset.IsMessageSet(m.Descriptor()) {
33 return sizeMessageSet(m)
34 }
Joe Tsai378c1322019-04-25 23:48:08 -070035 m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
36 size += sizeField(fd, v)
Damien Neil61e93c72019-03-27 09:23:20 -070037 return true
38 })
Joe Tsai378c1322019-04-25 23:48:08 -070039 size += len(m.GetUnknown())
Damien Neil61e93c72019-03-27 09:23:20 -070040 return size
41}
42
Joe Tsaiac31a352019-05-13 14:32:56 -070043func sizeField(fd protoreflect.FieldDescriptor, value protoreflect.Value) (size int) {
44 num := fd.Number()
Damien Neil61e93c72019-03-27 09:23:20 -070045 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -070046 case fd.IsList():
47 return sizeList(num, fd, value.List())
48 case fd.IsMap():
49 return sizeMap(num, fd, value.Map())
Damien Neil61e93c72019-03-27 09:23:20 -070050 default:
Joe Tsaiac31a352019-05-13 14:32:56 -070051 return wire.SizeTag(num) + sizeSingular(num, fd.Kind(), value)
Damien Neil61e93c72019-03-27 09:23:20 -070052 }
53}
54
Joe Tsaiac31a352019-05-13 14:32:56 -070055func sizeList(num wire.Number, fd protoreflect.FieldDescriptor, list protoreflect.List) (size int) {
Joe Tsai378c1322019-04-25 23:48:08 -070056 if fd.IsPacked() && list.Len() > 0 {
Joe Tsaiac31a352019-05-13 14:32:56 -070057 content := 0
58 for i, llen := 0, list.Len(); i < llen; i++ {
59 content += sizeSingular(num, fd.Kind(), list.Get(i))
60 }
61 return wire.SizeTag(num) + wire.SizeBytes(content)
62 }
63
64 for i, llen := 0, list.Len(); i < llen; i++ {
65 size += wire.SizeTag(num) + sizeSingular(num, fd.Kind(), list.Get(i))
66 }
Damien Neil61e93c72019-03-27 09:23:20 -070067 return size
68}
69
Joe Tsaiac31a352019-05-13 14:32:56 -070070func sizeMap(num wire.Number, fd protoreflect.FieldDescriptor, mapv protoreflect.Map) (size int) {
71 mapv.Range(func(key protoreflect.MapKey, value protoreflect.Value) bool {
72 size += wire.SizeTag(num)
73 size += wire.SizeBytes(sizeField(fd.MapKey(), key.Value()) + sizeField(fd.MapValue(), value))
74 return true
75 })
Damien Neil61e93c72019-03-27 09:23:20 -070076 return size
77}