blob: ab00a206b8bd01664a0d3eab86434d797f35aa92 [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"
Damien Neil61e93c72019-03-27 09:23:20 -070010)
11
12// Size returns the size in bytes of the wire-format encoding of m.
13func Size(m Message) int {
Damien Neil03e74862019-04-07 18:18:31 -070014 return MarshalOptions{}.Size(m)
15}
16
17// Size returns the size in bytes of the wire-format encoding of m.
18func (o MarshalOptions) Size(m Message) int {
Damien Neil61e93c72019-03-27 09:23:20 -070019 return sizeMessage(m.ProtoReflect())
20}
21
Joe Tsai0f81b382019-07-10 23:14:31 -070022func sizeMessage(m protoreflect.Message) (size int) {
23 if methods := protoMethods(m); methods != nil && methods.Size != nil {
24 return methods.Size(m)
Damien Neil0d3e8cc2019-04-01 13:31:55 -070025 }
Joe Tsai0f81b382019-07-10 23:14:31 -070026 return sizeMessageSlow(m)
Damien Neil0d3e8cc2019-04-01 13:31:55 -070027}
28
Joe Tsai0f81b382019-07-10 23:14:31 -070029func sizeMessageSlow(m protoreflect.Message) (size int) {
Joe Tsai378c1322019-04-25 23:48:08 -070030 m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
31 size += sizeField(fd, v)
Damien Neil61e93c72019-03-27 09:23:20 -070032 return true
33 })
Joe Tsai378c1322019-04-25 23:48:08 -070034 size += len(m.GetUnknown())
Damien Neil61e93c72019-03-27 09:23:20 -070035 return size
36}
37
Joe Tsaiac31a352019-05-13 14:32:56 -070038func sizeField(fd protoreflect.FieldDescriptor, value protoreflect.Value) (size int) {
39 num := fd.Number()
Damien Neil61e93c72019-03-27 09:23:20 -070040 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -070041 case fd.IsList():
42 return sizeList(num, fd, value.List())
43 case fd.IsMap():
44 return sizeMap(num, fd, value.Map())
Damien Neil61e93c72019-03-27 09:23:20 -070045 default:
Joe Tsaiac31a352019-05-13 14:32:56 -070046 return wire.SizeTag(num) + sizeSingular(num, fd.Kind(), value)
Damien Neil61e93c72019-03-27 09:23:20 -070047 }
48}
49
Joe Tsaiac31a352019-05-13 14:32:56 -070050func sizeList(num wire.Number, fd protoreflect.FieldDescriptor, list protoreflect.List) (size int) {
Joe Tsai378c1322019-04-25 23:48:08 -070051 if fd.IsPacked() && list.Len() > 0 {
Joe Tsaiac31a352019-05-13 14:32:56 -070052 content := 0
53 for i, llen := 0, list.Len(); i < llen; i++ {
54 content += sizeSingular(num, fd.Kind(), list.Get(i))
55 }
56 return wire.SizeTag(num) + wire.SizeBytes(content)
57 }
58
59 for i, llen := 0, list.Len(); i < llen; i++ {
60 size += wire.SizeTag(num) + sizeSingular(num, fd.Kind(), list.Get(i))
61 }
Damien Neil61e93c72019-03-27 09:23:20 -070062 return size
63}
64
Joe Tsaiac31a352019-05-13 14:32:56 -070065func sizeMap(num wire.Number, fd protoreflect.FieldDescriptor, mapv protoreflect.Map) (size int) {
66 mapv.Range(func(key protoreflect.MapKey, value protoreflect.Value) bool {
67 size += wire.SizeTag(num)
68 size += wire.SizeBytes(sizeField(fd.MapKey(), key.Value()) + sizeField(fd.MapValue(), value))
69 return true
70 })
Damien Neil61e93c72019-03-27 09:23:20 -070071 return size
72}